From 7e36c8a8c200278f484b45884dc2e8daa33ee61c Mon Sep 17 00:00:00 2001 From: Roman Simionov Date: Wed, 12 Feb 2020 13:13:39 +0300 Subject: [PATCH] Merge 20_1 into preact_button (#11978) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * DataGrid: Fix scrolling if max-height of the widget container is set to a non-integer number of pixels (T849902) (#11632) * TabPanel - Fix active tab switching on focusIn (T852689) (#11583) * Fix active tab switching on focusIn (T852689) * Tests for fix T852689 * Small refactoring * Small fix * Tests improvements * Small refactoring * Test refactorings * Tests improvements * fix tests for non jquery enviroment * Small fix * Small test refactoring * Fix test for mobile devices * Fix focusing for mobile devices * Fix focusing logic * Small refactoring * Small fixes * Pull request feedback * Tets fix * Small refactoring * Small fix * Refactoring * Small tests refactoring * Small tests refactoring * Small test refactoring * Tests refactorings * Rid of unexpected borders for the DataGrid selected rows in generic light and dark themes (T853231) (#11665) * Fix mock of window for server side tests (#11681) * PivotGrid: Fix texts.emptyValue was not working (T852897) (#11671) * Fix environment preparation for gesture cover tests (#11672) * Fix environment preparation for gesture cover tests * refactor * Comment unstable assert in test (#11688) * Fix DropDownEditor Popup position depending the "rtlEnabled" option value (T856114) (#11687) * Fix Popup position of the DropDownEditor depending on "rtlEnabled" option value (T856114) * refactoring * Support date serialization formats for DateBox with list picker type (T854579) (#11695) * DataGrid - Setting the isHighlighted option in the onFocusedCellChanging event handler does not work when the end user uses the Tab key to navigate between data cells (T853599) (#11667) * Renovation: odata/mixins es6 refactoring (#11444) * Renovation: Data Source refactoring (#11479) * DataGrid: Fix onRowClick call on "Save" click when edit mode is "form" (T848729) (#11615) * DataGrid: Fix onRowClick call on "Save" click when edit mode is "form" (T848729) * Fix test * Gantt: fix incorrect key value on assignment deleting (T850951) (#11704) * UpdateCI - Functional tests - Added testCafe quarantineMode parameter and applied it for the Scheduler (#11640) * UpdateCI - Functional tests - Added testCafe quarantineMode parameter and applied it for scheduler. * A bit of refactoring * A bit of refactoring * DataGrid - Focused row should not being reseted after begin edit row if form edit mode (T851400) (#11620) * DataGrid - Contrast Theme - Deleted records are not visible in Batch Editing Mode ( T856115) (#11702) * Fix recurrence part position and size after daylights saving change (T804886, first step) (#11657) * dxScheduler - fix recurrent appointment rendering with workWeek view (T853629) (#11660) * Scheduler, remove skipTimezone checking after T834428 fixing (#11680) * ExcelJS - changing 'wrapText' setting according grid.wordWrapEnabled option (#11701) * ExcelJS - changing default value for 'autoFilterEnabled' property to false (#11700) * Refactor some functions in Scheduler subscribes (#11712) * Draft (#11715) * Fix Scheduler tests in Tokyo and Australia timezones (#11722) * Scheduler - Reduce test speed in unstable functional tests (#11706) * Fix hiding tooltip by click issue (T850217) (#11720) * Add missing tests on events for Popup and Overlay (#11719) * Fix Lookup styles for compact themes (T856794) (#11725) * Drone CI: colorized logs (#11721) * Less refactoring for scss generation (icons, typography, button, buttonGroup, scrollView) (#11629) * File Manager - Directory Chooser dialog text change (#11732) * Draft * Next iteration * Implement dialogManager and add localizations constants * Remove redundant code * Fix up test * Add confirmation dialog draft and move dialog inits to ctor * Fix uncaught exception when a legend is hidden (T854736) (#11737) * File Manager - Notification popup configuration (#11741) * Draft * Reset text alignment * Option rename * DateBox should not raise any errors when useMaskBehavior is enabled and locale digits are different to arabic digits (T851630) (#11678) * Remove some code for deprecated formatWidthCalculator and closeOnValueChange DateBox options (#11736) * File Manager - Change icon of filesView 'ParentFolder' item (#11634) * Icon changed * Breadcrumbs icon revert and filesView parentFolder icon change * List (Sortable) - Fix item dragging to the top position when allowReordering is false (T856292) (#11729) * List (Sortable) - Fix item dragging to the top position when allowReordering is false (T856292) * Fix lint * Do not use real clean-css module in some integration tests. (#11749) * TreeView - fix docs for the rootValue (T854356) (#11718) * Fix docs for the rootValue of the treeView (T854356) * Small tests refactoring * File Manager - 'File actions' button shape (#11746) * File Manager - Thumbnails View - adjust icons size * Next version * Draft * Revert "Next version" This reverts commit cd99f05fc03c8d0d0b385d0722a66610757335b2. * Next one draft * Buttons and icons now are of default theme size * Looks like not bad case * Change focused icon color * Remove comment * Revert "File Manager - Thumbnails View - adjust icons size" This reverts commit 92a82e828bfda3540da86e9c41e30b9cb494a27c. * Change list icon in dark material theme (T857017) (#11752) * SelectBox: add some event tests (#11756) * Renovation: odata/store es6 refactoring (#11391) * dxPieChart: Fix triggering onLegendClick for legend icon (T854491) (#11760) * Add missing tests for a DateBox widget (#11733) * Use bash arrays for Chrome args (docker-ci) (#11764) * Scss generator (#11750) * Drone CI - Add time zone argument to the test matrix (#11761) * Drone CI - Add time zone argument to the test matrix * Add TZ for Travis, Shippable * QUnit: Rework API for ignoring uncleared timers (#11765) * QUnit: Refactor to use one way for ignoring uncleared timers * QUnit: Get rid of timerIgnoringCheckers.applyUnregister method * QUnit: timerIgnoringCheckers -> timersDetector.ignoreRules * QUnit: ignoreRules.needSkip -> ignoreRules.shouldIgnore * QUnit: Get rid of ignoreAngularBrowserDeferTimer duplication * QUnit: Refactor isThirdPartyLibraryTimer * QUnit: Get rid of normalizedTimerInfo * QUnit: Refactor spyWindowMethods * QUnit: Consolidate all ignore rules for angular in one place * QUnit: Log test failure when uncleared timers detected instead of global one * Less: change icon mixin from 'selector' to 'parametrized' (#11763) * Update README.txt Sync with https://github.com/DevExpress/DevExtreme/pull/10897 * Remove advanceCaret DateBox option (#11768) * Scrollable - check scroll position after update() (T848870) (#11766) * DataGrid - column headers do not align with cells if showScrollbar is 'always' (#11758) * Add missing NumberBox test (#11769) * DataGrid: Fix selected checkboxes were not checked after page refresh if stateStoring is enabled and renderAsync is true (T857205) (#11773) * Scss generator: additional widgets (#11782) * Add bundled tests for "onInitialized" and "onDisposing" events (#11762) * Add bundled tests for "onInitialized" and "onDisposing" events * add LayoutManager to tests Co-authored-by: AlekseyMartynov * Drone CI: reduce dotnet cache footprint (#11783) * ExcelJS - set vertical alignment for cell is 'top' as default (#11778) * Add noClean option for devextreme-themebuilder (#11790) (#11799) * Gantt: Add time intervals (#11776) * DataGrid: The onFocusedRowChanged event firing refactoring (#11724) * Fix passing of the event that caused the value to change when clicking the List item of the DateBox time picker (T858107) (#11800) * DropDownButton: add some events tests (#11775) * DropDownButton: add some events tests * Fix widget behavior - Possible problems with SSR (depends on specific config) has been resolved - ContentReady event has been normalized - OptionChanged issues has been resolver * add one more test * remove comma * fix typo Co-authored-by: Dmitry Levkovskiy * Diagram redesign (#11812) * Diagram - UI changes (toolbox) + rename some files * Fix linter errors * QUnit: Enable errors for 'qunit/no-ok-equality' rule (#11816) * Fix "Initialized and Disposing events" tests for IE (#11814) * HtmlEditor: Ignore Quill timers in tests (#11818) * Add missing TagBox tests (#11810) * QUnit: Make extensions compatible with IE (#11843) * Scss: add new widgets to generator (#11831) * DataGrid: Fix cell was not highlighted after editing another cell and click (refix T836391) (#11659) Co-authored-by: AlekseyMartynov * DOTNET_USE_POLLING_FILE_WATCHER=true (docker-ci) (#11855) * FileManager - Update result type for file provider's methods (#11853) * Scss: add new widgets to generator (#11868) * ThemeBuilder tests refactoring (#11801) * DataGrid: Fix group cell that has the dx-datagrid-hidden-column class when the hidingPriority property is specified for a grid column (T857506) (#11833) * DataGrid: Fix group cell that has the dx-datagrid-hidden-column class when the hidingPriority property is specified for a grid column (T857506) * Fix lint * Support ScrollView reachBottom event for dropDownLists keyboard navigation if the browser is zoomed (T858013) (#11851) * dxScheduler - fix appointment popup on closing (T854500) (#11754) * Fix angular typescript hack (#11884) * Fix FF test after #11724 (#11876) * Widgets: Eliminate global object pollution (#11887) * CollectionWidget: Remove globals in tests * Tooltip: Do not set 'aria-describedby' to window * TreeList: Fix values were not assigned by e.promise in onInitNewRow (T857405) (#11794) * Fix Calendar accessibility issues (#11846) * Fix Calendar accessibility issues * Calendar views refactoring * base view refactoring * remove code duplication * Update cache before callBase * Support zero value as a new selected item key for the DropDownButton (T858013) (#11880) * DataGrid: Remove globals in tests (#11888) * FileManager - Add public constructor for FileManagerItem class (#11885) * TreeList: Add node property for a detail adaptive row (#11871) * ExcelJS - add doс comments for arguments of the 'exportDataGrid' function (#11807) * TreeList: Fix navigateTo to the same page with row expanding after #11724 (#11895) * Don't hang if QUnit runner is broken (docker-ci) (#11897) * Update docker-ci.sh Quotes * Revert "ExcelJS - add doс comments for arguments of the 'exportDataGrid' function (#11807)" (#11898) * Merge js/events.d.ts into js/events/index.d.ts (#11901) * DataGrid - KeyboardNavigation - Replace pointerUp with pointerDown (#11900) * DataGrid - KeyboardNavigation - Replace pointerUp with pointerDown * Fix fileManager tests * Fix treeList tests * Fix tests in FF * Fix IE test * FileManager - Update public API (#11905) * File Manager - UploadPanel items appearance (#11907) * RadioGroup: add some event tests (#11866) * TreeList: Fix getSelectedRowsData method when calling navigateToRow in the onNodesInitialized event (T858312) (#11904) * ExcelJS - add doс comments for arguments of the 'exportDataGrid' function (#11912) * Diagram - fix server-side rendering test (#11913) * DataGrid: Fix onFocusedRowChanged firing on scroll if autoNavigateToFocusedRow is false after #11724 (#11910) * Fix zero-time appointment width in month & timelineMonth views (T858496) (#11860) * Fix zero-time appointment width in month & timelineMonth views (T858496) * rename index * Refactor * Drone CI - Fix setting timezone (#11906) * Drone CI - Fix setting timezone * Drone CI - Correct timezones * List: Fix incorrect dragged item render if RTL is enabled (T859557) (#11918) * Fix "event" argument of the Switch "valueChanged" event when value changed by gesture (T860005) (#11922) * File Manager - ProgressPanel close button alignment (#11926) * File Manager - ProgressPanel close button alignment * Now it's more aligned * Update docker-ci.sh * run_$TARGET convention (docker-ci) * Update ja.json (#11879) * Update ja.json Added localizations for Max and Min * Update ja.json localized dxDataGrid-summaryAvg as well * FileManager - Update FileSystemProviderBase.getItems() method signature (#11933) * Update localization.js Give names to a bunch of tasks * ExcelJS - rename cellsRange to cellRange (#11936) * DataGrid: fix column header's sort icon remains after grouping by this column if showWhenGrouped (T859208) (#11914) * dxLookup - Fix field paddings in the Material theme * DataGrid - Click by command select cell should not highlight focus if editing is enabled (refix T836391) (#11937) * CI: QUnit runner watchdog (#11938) * ExcelJS - change doc comments (#11935) * Don't build all themes in TEST_CI mode (#11939) * Update aspnet.tests.js spy.restore() * File Manager - ProgressPanel file icons size (#11950) * FileManager - Progress panel close button alignment (#11951) * File Manager - ProgressPanel close button alignment * Now it's more aligned * File Manager - ProgressPanel close button alignment * Diagram - redesign (add history toolbar and view toolbar) (#11944) * Diagram - add history toolbar + viewSettings toolbar - first commit * Diagram - commands refactoring * Diagram - add an ability to check context menu items * Diagram - context menus refactoring * Diagram - context menu icons fix * Diagram - fix select box commands * Diagram - toolbars refactoring + tests * Fix tests * Fix tests * Fix tests * Fix the knokout binding with the observable array in the Form (#11923) (#11954) * FileManager - Update CustomFileSystemProviderOptions declarations (#11952) * FileManager - Update event / callback function signatures (#11953) * Draggable: fix clone had incorrect direction if rtlEnabled (T859557 refix) (#11928) * Fix label and bar point overlapping on the edge of pane (T856746) (#11955) * Fix double min-width rule in the CSS bundle (#11960) * ASP.NET: warning about the alternate template syntax (#11934) * Limit DropDownLists popup height if the container is larger than a window (T859133) (#11949) * FileManager - Add upload.chunkSize option (#11966) * Fix after merge Co-authored-by: Konstantin Volnyagin Co-authored-by: Sergey Novikov <57402891+novsstation@users.noreply.github.com> Co-authored-by: kotov.alexander Co-authored-by: Andrey Ignatovskiy <43685423+LazyLahtak@users.noreply.github.com> Co-authored-by: Jaan Toming Co-authored-by: Dmitry Levkovskiy Co-authored-by: Alexey Kamyshin Co-authored-by: Igor Maltsev Co-authored-by: Alyar Co-authored-by: Alexander Zelevinskiy <16476188+zelik88@users.noreply.github.com> Co-authored-by: Anton Sermyazhko Co-authored-by: Yana Yarovaya Co-authored-by: Smirnova Yuliya Co-authored-by: EugeniyKiyashko Co-authored-by: Stanislav Klesarev Co-authored-by: polosatov.alexander Co-authored-by: AlekseyMartynov Co-authored-by: Alexey Babich Co-authored-by: Anton Kuznetsov Co-authored-by: Alexander Bezborodov Co-authored-by: Alexander Ziborov <1420883+San4es@users.noreply.github.com> Co-authored-by: Stepan Co-authored-by: Roman Rodin Co-authored-by: Vladimir Kovalev <47112293+vladkovl@users.noreply.github.com> Co-authored-by: ilya.kharchenko <14272298+IlyaKhD@users.noreply.github.com> Co-authored-by: AlisherAmonulloev Co-authored-by: groshenkovamarina Co-authored-by: Dmitry Semenov Co-authored-by: pavelgruba --- .drone.yml | 11 +- .gitignore | 1 + .travis.yml | 9 +- build/docker-image/README.txt | 2 +- build/gulp/localization.js | 18 +- build/gulp/modules_metadata.json | 48 +- build/gulp/scss/compiler.js | 13 + build/gulp/scss/config.js | 4 + build/gulp/scss/generator.js | 433 ++++ build/gulp/scss/index-data.js | 75 + build/gulp/scss/replacements.js | 246 ++ build/gulp/scss/tasks.js | 20 + build/gulp/style-compiler.js | 29 +- build/gulp/ts.js | 58 +- docker-ci.sh | 144 +- drone-cache-clean.sh | 5 + drone-cache.sh | 2 + gulpfile.js | 10 +- .../widgets/common/diagram/toolbox-drag.svg | 12 + .../color-schemes/dark/list/delete.png | Bin 265 -> 452 bytes js/aspnet.js | 20 +- js/bundles/modules/core.js | 2 +- js/bundles/modules/data.js | 2 +- js/bundles/modules/file_management.js | 12 + js/bundles/modules/file_providers.js | 8 - js/bundles/modules/parts/file_management.js | 11 + js/bundles/modules/parts/file_providers.js | 11 - js/bundles/modules/parts/widgets-base.js | 2 +- js/core/utils/position.js | 4 +- js/core/utils/window.js | 12 +- js/data/data_source/data_source.js | 484 ++-- js/data/data_source/operation_manager.js | 34 + js/data/data_source/utils.js | 124 + js/data/odata/context.js | 19 +- js/data/odata/mixins.js | 71 - js/data/odata/request_dispatcher.js | 55 + js/data/odata/store.js | 158 +- js/data/odata/utils.js | 23 + js/data_helper.js | 2 +- js/docEnums.js | 4 +- js/events.d.ts | 245 -- js/events/index.d.ts | 243 +- js/excel_exporter.d.ts | 207 ++ js/excel_exporter.js | 41 + js/exporter/excel/excel.doc_comments.d.ts | 56 - js/exporter/excel/excel.doc_comments.js | 13 - js/exporter/exceljs/excelExporter.js | 3 - ...{exportDataGrid.js => export_data_grid.js} | 37 +- js/file_management/custom_provider.d.ts | 135 ++ .../custom_provider.js} | 45 +- js/file_management/errors.js | 13 + js/file_management/file_system_item.d.ts | 84 + js/file_management/file_system_item.js | 104 + js/file_management/object_provider.d.ts | 40 + .../object_provider.js} | 73 +- js/file_management/provider_base.d.ts | 166 ++ .../provider_base.js} | 103 +- js/file_management/remote_provider.d.ts | 33 + .../remote_provider.js} | 35 +- js/file_management/upload_info.d.ts | 50 + .../utils.js} | 15 +- js/localization/messages/de.json | 12 +- js/localization/messages/en.json | 144 +- js/localization/messages/ja.json | 18 +- js/localization/messages/ru.json | 124 +- js/ui/calendar/ui.calendar.base_view.js | 205 +- js/ui/calendar/ui.calendar.js | 6 +- js/ui/calendar/ui.calendar.views.js | 158 +- js/ui/collection/ui.collection_widget.edit.js | 3 +- js/ui/data_grid.d.ts | 5 +- js/ui/date_box/ui.date_box.base.js | 12 +- js/ui/date_box/ui.date_box.mask.js | 38 +- js/ui/date_box/ui.date_box.strategy.js | 6 - js/ui/date_box/ui.date_box.strategy.list.js | 9 +- js/ui/diagram.d.ts | 20 +- .../{diagram_bar.js => diagram.bar.js} | 15 +- ...ommands.js => diagram.commands_manager.js} | 447 ++-- js/ui/diagram/diagram.edges_option.js | 9 + ...iagram_importer.js => diagram.importer.js} | 0 .../{diagram_item.js => diagram.items.js} | 0 ...agram.items.js => diagram.items_option.js} | 0 ...agram.nodes.js => diagram.nodes_option.js} | 2 +- ...onsupdate.js => diagram.options_update.js} | 4 +- js/ui/diagram/diagram.toolbox_manager.js | 52 + ...textmenu.js => ui.diagram.context_menu.js} | 143 +- ...olbox.js => ui.diagram.context_toolbox.js} | 0 ...anager.js => ui.diagram.dialog_manager.js} | 2 +- js/ui/diagram/ui.diagram.dialogs.js | 12 +- js/ui/diagram/ui.diagram.edges.js | 9 - js/ui/diagram/ui.diagram.floating_panel.js | 36 + js/ui/diagram/ui.diagram.history_toolbar.js | 10 + js/ui/diagram/ui.diagram.js | 313 ++- js/ui/diagram/ui.diagram.leftpanel.js | 101 - js/ui/diagram/ui.diagram.main_toolbar.js | 26 + js/ui/diagram/ui.diagram.menu_helper.js | 53 + .../{diagram.panel.js => ui.diagram.panel.js} | 0 js/ui/diagram/ui.diagram.rightpanel.js | 10 +- js/ui/diagram/ui.diagram.toolbar.js | 239 +- js/ui/diagram/ui.diagram.toolbox.js | 268 ++- js/ui/diagram/ui.diagram.view_toolbar.js | 10 + js/ui/draggable.js | 4 +- js/ui/drop_down_button.js | 33 +- js/ui/drop_down_editor/ui.drop_down_editor.js | 112 +- js/ui/drop_down_editor/ui.drop_down_list.js | 3 +- js/ui/file_manager.d.ts | 27 +- js/ui/file_manager/file_items_controller.js | 80 +- js/ui/file_manager/file_provider/ajax.d.ts | 33 - js/ui/file_manager/file_provider/ajax.js | 76 - js/ui/file_manager/file_provider/array.d.ts | 40 - js/ui/file_manager/file_provider/custom.d.ts | 103 - .../file_provider/file_provider.d.ts | 67 - js/ui/file_manager/file_provider/remote.d.ts | 33 - .../ui.file_manager.breadcrumbs.js | 2 +- .../ui.file_manager.command_manager.js | 4 +- js/ui/file_manager/ui.file_manager.common.js | 26 +- .../ui.file_manager.dialog.folder_chooser.js | 12 +- js/ui/file_manager/ui.file_manager.dialog.js | 8 + .../ui.file_manager.dialog_manager.js | 64 + js/ui/file_manager/ui.file_manager.editing.js | 56 +- .../ui.file_manager.file_actions_button.js | 7 +- .../ui.file_manager.files_tree_view.js | 14 +- .../ui.file_manager.item_list.details.js | 2 +- .../ui.file_manager.item_list.thumbnails.js | 2 +- js/ui/file_manager/ui.file_manager.js | 38 +- .../file_manager/ui.file_manager.messages.js | 2 +- .../ui.file_manager.notification.js | 7 +- ...ile_manager.notification.progress_panel.js | 4 + js/ui/file_manager/ui.file_manager.toolbar.js | 6 +- js/ui/file_uploader.d.ts | 20 +- js/ui/form/ui.form.layout_manager.js | 4 +- js/ui/gantt.d.ts | 13 +- js/ui/grid_core/ui.grid_core.adaptivity.js | 4 +- .../grid_core/ui.grid_core.column_headers.js | 10 +- .../ui.grid_core.columns_controller.js | 3 +- .../grid_core/ui.grid_core.data_controller.js | 15 +- js/ui/grid_core/ui.grid_core.editing.js | 4 +- .../ui.grid_core.filter_custom_operations.js | 4 +- js/ui/grid_core/ui.grid_core.focus.js | 49 +- js/ui/grid_core/ui.grid_core.grid_view.js | 2 +- js/ui/grid_core/ui.grid_core.header_filter.js | 2 +- .../ui.grid_core.keyboard_navigation.js | 85 +- js/ui/grid_core/ui.grid_core.selection.js | 11 +- js/ui/grid_core/ui.grid_core.sorting_mixin.js | 4 +- js/ui/grid_core/ui.grid_core.validating.js | 18 +- js/ui/pivot_grid/data_source.js | 2 +- .../ui.pivot_grid.field_chooser_base.js | 8 + js/ui/scheduler/appointmentPopup.js | 2 +- ...ui.scheduler.appointments.strategy.base.js | 4 +- ...intments.strategy.horizontal_month_line.js | 7 +- .../ui.scheduler.appointment_form.js | 72 +- js/ui/scheduler/ui.scheduler.appointments.js | 9 +- js/ui/scheduler/ui.scheduler.js | 29 + .../ui.scheduler.resource_manager.js | 9 +- js/ui/scheduler/ui.scheduler.subscribes.js | 14 +- js/ui/scheduler/utils.js | 15 +- .../ui.scheduler.timeline_work_week.js | 26 +- .../workspaces/ui.scheduler.work_space.js | 14 +- .../ui.scheduler.work_space_work_week.js | 15 +- js/ui/scheduler/workspaces/utils.work_week.js | 23 + .../ui.scroll_view.native.pull_down.js | 6 +- js/ui/scroll_view/ui.scroll_view.simulated.js | 2 +- js/ui/shared/ui.editor_factory_mixin.js | 3 +- js/ui/sortable.js | 3 +- js/ui/switch.js | 1 + js/ui/tab_panel.js | 12 +- js/ui/tag_box.js | 2 +- js/ui/tooltip/tooltip.js | 5 +- .../ui.tree_list.data_source_adapter.js | 2 +- js/ui/tree_list/ui.tree_list.editing.js | 2 +- js/ui/tree_view.d.ts | 4 +- js/viz/chart_components/tracker.js | 13 +- js/viz/components/legend.js | 2 +- js/viz/core/utils.js | 5 + js/viz/series/points/bar_point.js | 77 +- js/viz/series/points/candlestick_point.js | 17 +- js/viz/series/points/polar_point.js | 21 +- js/viz/series/points/range_bar_point.js | 15 - js/viz/series/points/symbol_point.js | 3 +- js/viz/sparklines/base_sparkline.js | 231 +- package.json | 4 +- shippable.yml | 9 +- styles/mixins.less | 6 - styles/widgets/base/colorView.less | 25 +- styles/widgets/base/dataGrid.less | 10 +- styles/widgets/base/diagram.less | 2 +- styles/widgets/base/icons.less | 513 ++--- styles/widgets/base/pivotGrid.less | 8 +- styles/widgets/base/scheduler.less | 10 +- styles/widgets/base/treeList.less | 10 +- styles/widgets/base/validation.less | 20 +- styles/widgets/common/checkBox.less | 4 +- styles/widgets/common/diagram.less | 119 +- styles/widgets/common/dropDownEditor.less | 4 +- styles/widgets/common/fileManager.less | 17 +- styles/widgets/common/menu.less | 8 +- styles/widgets/common/radioGroup.less | 8 +- styles/widgets/common/splitter.less | 1 - .../widgets/generic/autocomplete.generic.less | 4 +- styles/widgets/generic/checkBox.generic.less | 8 +- .../carmine/generic.carmine.less | 39 +- .../contrast/generic.contrast.less | 21 +- .../color-schemes/dark/generic.dark.less | 67 +- .../darkmoon/generic.darkmoon.less | 54 +- .../darkviolet/generic.darkviolet.less | 49 +- .../greenmist/generic.greenmist.less | 39 +- .../color-schemes/light/generic.light.less | 60 +- .../softblue/generic.softblue.less | 60 +- styles/widgets/generic/colorView.generic.less | 2 + styles/widgets/generic/common.generic.less | 1 + .../widgets/generic/contextMenu.generic.less | 6 +- styles/widgets/generic/dataGrid.generic.less | 4 +- styles/widgets/generic/dateBox.generic.less | 4 +- styles/widgets/generic/diagram.generic.less | 164 +- .../generic/dropDownEditor.generic.less | 25 +- styles/widgets/generic/fieldset.generic.less | 2 +- .../widgets/generic/fileManager.generic.less | 30 +- styles/widgets/generic/gallery.generic.less | 4 +- styles/widgets/generic/gantt.generic.less | 5 + styles/widgets/generic/gridBase.generic.less | 52 +- styles/widgets/generic/list.generic.less | 4 +- styles/widgets/generic/lookup.generic.less | 8 +- styles/widgets/generic/menu.generic.less | 4 +- styles/widgets/generic/numberBox.generic.less | 4 +- styles/widgets/generic/pager.generic.less | 4 +- styles/widgets/generic/pivotGrid.generic.less | 6 +- .../widgets/generic/radioGroup.generic.less | 4 +- .../widgets/generic/size-schemes/compact.less | 4 +- .../widgets/generic/size-schemes/default.less | 4 +- styles/widgets/generic/tagBox.generic.less | 8 +- styles/widgets/generic/textBox.generic.less | 17 +- .../widgets/generic/textEditor.generic.less | 4 +- styles/widgets/generic/treeList.generic.less | 6 +- styles/widgets/generic/treeView.generic.less | 4 +- .../widgets/generic/typography.generic.less | 8 +- .../widgets/generic/validation.generic.less | 2 + styles/widgets/ios7/checkBox.ios7.less | 2 +- styles/widgets/ios7/contextMenu.ios7.less | 2 +- styles/widgets/ios7/dataGrid.ios7.less | 4 +- styles/widgets/ios7/diagram.ios7.less | 52 - styles/widgets/ios7/dropDownEditor.ios7.less | 2 +- styles/widgets/ios7/gallery.ios7.less | 4 +- styles/widgets/ios7/gantt.ios7.less | 2 - styles/widgets/ios7/gridBase.ios7.less | 44 +- styles/widgets/ios7/list.ios7.less | 2 +- styles/widgets/ios7/lookup.ios7.less | 2 +- styles/widgets/ios7/numberBox.ios7.less | 4 +- styles/widgets/ios7/pager.ios7.less | 4 +- styles/widgets/ios7/pivotGrid.ios7.less | 9 +- styles/widgets/ios7/treeList.ios7.less | 6 +- styles/widgets/ios7/treeView.ios7.less | 4 +- .../material/autocomplete.material.less | 4 +- .../widgets/material/checkBox.material.less | 6 +- .../material/color-schemes/material.dark.less | 26 +- .../color-schemes/material.light.less | 27 +- .../widgets/material/colorView.material.less | 2 + styles/widgets/material/common.material.less | 1 + .../material/contextMenu.material.less | 2 +- .../widgets/material/dataGrid.material.less | 4 +- styles/widgets/material/dateBox.material.less | 4 +- styles/widgets/material/diagram.material.less | 180 +- .../material/dropDownEditor.material.less | 12 +- .../widgets/material/fieldset.material.less | 2 +- .../material/fileManager.material.less | 30 +- styles/widgets/material/gallery.material.less | 4 +- styles/widgets/material/gantt.material.less | 5 + .../widgets/material/gridBase.material.less | 52 +- styles/widgets/material/list.material.less | 10 +- styles/widgets/material/lookup.material.less | 43 +- .../widgets/material/numberBox.material.less | 4 +- styles/widgets/material/pager.material.less | 4 +- .../widgets/material/pivotGrid.material.less | 8 +- .../widgets/material/radioGroup.material.less | 4 +- .../material/size-schemes/compact.less | 5 +- .../material/size-schemes/default.less | 5 +- .../material/size-schemes/shared/base.less | 2 + styles/widgets/material/switch.material.less | 20 +- styles/widgets/material/tagBox.material.less | 10 +- .../widgets/material/textArea.material.less | 4 +- styles/widgets/material/textBox.material.less | 18 +- .../widgets/material/textEditor.material.less | 12 +- .../widgets/material/timeView.material.less | 36 +- styles/widgets/material/tooltip.material.less | 4 +- .../widgets/material/treeList.material.less | 6 +- .../widgets/material/treeView.material.less | 7 +- .../widgets/material/typography.material.less | 6 +- .../widgets/material/validation.material.less | 2 + testing/.eslintrc | 2 +- testing/functional/helpers/testHelper.ts | 10 +- testing/functional/model/dataGrid.ts | 69 +- testing/functional/runner.js | 5 +- .../functional/tests/dataGrid/focusedRow.ts | 174 +- .../tests/dataGrid/keyboardNavigation.ts | 61 +- .../tests/scheduler/appointmentForm.ts | 5 +- .../tests/scheduler/deleteAppointments.ts | 1 + .../scheduler/grouping/groupingByDate.ts | 6 +- .../helpers/fileManager/file_provider.test.js | 14 +- testing/helpers/fileManagerHelpers.js | 20 +- .../helpers/grid/keyboardNavigationHelper.js | 7 +- testing/helpers/ignoreAngularTimers.js | 22 + testing/helpers/ignoreQuillTimers.js | 14 + testing/helpers/qunitExtensions.js | 318 ++- testing/helpers/ssrEmulator.js | 10 +- testing/helpers/wrappers/dataGridWrappers.js | 13 + testing/runner/Controllers/MainController.cs | 3 + testing/runner/Program.cs | 5 +- testing/runner/Views/Main/RunSuite.cshtml | 5 +- testing/runner/runner.csproj | 5 +- .../componentRegistration.tests.js | 42 +- .../modelIntegration.tests.js | 8 +- .../tests/DevExpress.angular/widgets.tests.js | 51 +- .../tests/DevExpress.aspnet/aspnet.tests.js | 33 +- .../tests/DevExpress.core/utils.ajax.tests.js | 2 +- .../DevExpress.core/utils.position.tests.js | 31 + .../dataSourceCreating.tests.js | 2 +- .../tests/DevExpress.data/odataStore.tests.js | 16 +- .../tests/DevExpress.data/storeArray.tests.js | 20 +- testing/tests/DevExpress.data/utils.tests.js | 4 +- .../exceljsParts/ExcelJSTestHelper.js | 8 +- .../exceljsParts/exceljs.format.tests.js | 6 +- .../exceljsParts/exceljs.tests.js | 2046 ++++++++--------- .../tests/DevExpress.knockout/form.tests.js | 56 +- .../localization.globalize.widgets.tests.js | 22 + .../localization.intl.tests.js | 1 + .../localization.intl.widgets.tests.js | 46 + .../DevExpress.serverSide/diagram.tests.js | 30 + .../tests/DevExpress.ui.events/drag.tests.js | 6 +- .../eventsInteraction.tests.js | 258 +-- .../adaptiveColumns.tests.js | 62 +- .../columnsResizingReorderingModule.tests.js | 18 +- ...ataGrid.export.customizeExcelCell.tests.js | 2 +- .../dataGrid.tests.js | 391 +++- .../dataSource.tests.js | 2 +- .../editing.tests.js | 42 + .../exportController.tests.js | 6 +- .../fixedColumns.tests.js | 16 +- .../focus.tests.js | 653 +++--- .../gridView.tests.js | 4 +- .../headerFilter.tests.js | 4 +- .../headerPanel.tests.js | 6 +- ...oardNavigation.keyboardController.tests.js | 43 +- .../keyboardNavigation.keyboardKeys.tests.js | 115 +- ...eyboardNavigation.realControllers.tests.js | 175 +- .../pagerView.tests.js | 2 +- .../rowsView.tests.js | 16 +- .../selection.tests.js | 2 +- .../actionButtons.test.js | 2 +- .../calendar.markup.tests.js | 31 +- .../calendar.tests.js | 104 +- .../calendarView.markup.tests.js | 61 +- .../calendarViews.tests.js | 97 +- .../datebox.mask.tests.js | 9 +- .../datebox.tests.js | 189 +- .../dropDownEditor.markup.tests.js | 30 + .../dropDownList.tests.js | 33 +- .../htmlEditor.converterController.tests.js | 1 + .../htmlEditor.missingModules.tests.part1.js | 1 + .../htmlEditor.missingModules.tests.part2.js | 1 + .../htmlEditor.tests.js | 1 + .../toolbarIntegration.tests.js | 6 +- .../numberBoxParts/common.tests.js | 20 +- .../radioGroup.tests.js | 84 +- .../selectBox.tests.js | 60 + .../slider.tests.js | 4 +- .../switch.tests.js | 13 +- .../tagBox.tests.js | 96 +- .../textEditorParts/common.tests.js | 2 +- .../validatorIntegration.tests.js | 1 + .../fieldChooser.tests.js | 74 + .../appointmentPopup.tests.js | 33 +- .../appointments.tests.js | 2 - .../common.markup.tests.js | 18 +- .../common.tests.js | 10 +- .../editing.tests.js | 6 +- .../integration.adaptivity.tests.js | 2 +- .../integration.allDayAppointments.tests.js | 8 +- .../integration.appointments.tests.js | 130 +- .../integration.dstAppointments.tests.js | 457 ++-- .../integration.workSpace.tests.js | 2 +- .../subscribes.tests.js | 11 - .../timeline.tests.js | 12 + .../workSpace.tests.js | 24 +- .../adaptiveColumns.tests.js | 81 + .../selection.tests.js | 34 +- .../treeList.tests.js | 69 +- .../DevExpress.ui.widgets/diagram.tests.js | 636 +---- .../diagramParts/clientSideEvents.tests.js | 93 + .../diagramParts/commandManager.tests.js | 82 + .../diagramParts/contextMenu.tests.js | 62 + .../diagramParts/dom.tests.js | 75 + .../diagramParts/historyToolbar.tests.js | 41 + .../diagramParts/importDiagram.tests.js | 2 +- .../diagramParts/mainToolbar.tests.js | 151 ++ .../diagramParts/options.tests.js | 240 ++ .../diagramParts/propertiesPanel.tests.js | 31 + .../diagramParts/toolbox.tests.js | 42 + .../diagramParts/viewToolbar.tests.js | 58 + .../DevExpress.ui.widgets/draggable.tests.js | 27 +- .../dropDownButton.tests.js | 502 +++- .../fileManager.tests.js | 1 - .../fileManagerParts/adaptivity.tests.js | 4 +- .../fileManagerParts/ajaxProvider.tests.js | 52 - .../fileManagerParts/arrayProvider.tests.js | 644 ++++-- .../fileManagerParts/common.tests.js | 50 +- .../fileManagerParts/contextMenu.tests.js | 4 +- .../fileManagerParts/customProvider.tests.js | 192 +- .../fileManagerParts/detailsView.tests.js | 39 +- .../fileManagerParts/editing.tests.js | 89 +- .../fileManagerParts/editingProgress.tests.js | 10 +- .../fileItemsController.tests.js | 21 +- .../fileManagerParts/markup.tests.js | 8 +- .../fileManagerParts/navigation.tests.js | 32 +- .../fileManagerParts/remoteProvider.tests.js | 45 +- .../fileManagerParts/toolbar.tests.js | 14 +- .../filterBuilderParts/commonTests.js | 6 +- .../DevExpress.ui.widgets/gantt.tests.js | 28 +- .../init_dispose_widget_bundled_tests.js | 58 + .../listParts/editingUITests.js | 73 +- .../DevExpress.ui.widgets/overlay.tests.js | 17 + .../DevExpress.ui.widgets/popup.tests.js | 60 +- .../DevExpress.ui.widgets/scrollView.tests.js | 4 +- .../scrollableParts/scrollable.api.tests.js | 80 +- .../DevExpress.ui.widgets/sortable.tests.js | 20 +- .../DevExpress.ui.widgets/tabPanel.tests.js | 43 +- .../treeViewParts/initialization.js | 62 +- .../DevExpress.ui/collectionWidget.tests.js | 4 +- .../DevExpress.ui/defaultOptions.tests.js | 1 - .../chart.part1.tests.js | 6 +- .../chart.part6.tests.js | 62 +- .../chart.part7.tests.js | 6 +- .../DevExpress.viz.charts/chart.tests.js | 14 +- .../chartInteraction.tests.js | 2 +- .../DevExpress.viz.charts/chartSync.tests.js | 32 +- .../DevExpress.viz.charts/pieChart.tests.js | 4 +- .../themeManager.tests.js | 2 +- .../DevExpress.viz.charts/tracker.tests.js | 14 +- .../barPoint.tests.js | 109 +- .../barSeries.tests.js | 4 +- .../baseSeries.tests.js | 4 +- .../bubbleSeries.tests.js | 4 +- .../financialPoint.tests.js | 39 +- .../financialSeries.tests.js | 4 +- .../export.integration.tests.js | 6 +- .../tests/DevExpress.viz.core/legend.tests.js | 14 + .../loadingIndicator.integration.tests.js | 4 +- .../title.integration.tests.js | 2 +- .../tooltip.integration.tests.js | 2 +- .../tests/DevExpress.viz.core/xyAxes.tests.js | 2 +- .../DevExpress.viz.gauges/baseGauge.tests.js | 4 +- .../DevExpress.viz.gauges/common.tests.js | 4 +- .../common.part1.tests.js | 8 +- .../common.part3.tests.js | 4 +- .../Animation.tests.js | 2 +- .../SvgElement.tests.js | 10 +- .../sankey.base.tests.js | 2 +- .../baseSparklineTooltipEvents.tests.js | 459 +--- .../DevExpress.viz.sparklines/bullet.tests.js | 2 +- .../bulletTooltip.tests.js | 12 +- .../sparkline.tests.js | 10 +- .../sparklineTooltip.tests.js | 28 +- .../mapLayer.tests.js | 8 +- .../mapLayer_new.tests.js | 8 +- .../projection.tests.js | 4 +- .../DevExpress.viz.vectorMap/tracker.tests.js | 2 +- testing/tests/DevExpress/misc.tests.js | 28 +- themebuilder/modules/less-template-loader.js | 10 +- themebuilder/tests/builder-spec.js | 9 +- .../tests/less-template-loader-spec.js | 38 + ts/dx.all.d.ts | 287 ++- 468 files changed, 13567 insertions(+), 8777 deletions(-) create mode 100644 build/gulp/scss/compiler.js create mode 100644 build/gulp/scss/config.js create mode 100644 build/gulp/scss/generator.js create mode 100644 build/gulp/scss/index-data.js create mode 100644 build/gulp/scss/replacements.js create mode 100644 build/gulp/scss/tasks.js create mode 100644 drone-cache-clean.sh create mode 100644 images/widgets/common/diagram/toolbox-drag.svg create mode 100644 js/bundles/modules/file_management.js delete mode 100644 js/bundles/modules/file_providers.js create mode 100644 js/bundles/modules/parts/file_management.js delete mode 100644 js/bundles/modules/parts/file_providers.js create mode 100644 js/data/data_source/operation_manager.js create mode 100644 js/data/data_source/utils.js delete mode 100644 js/data/odata/mixins.js create mode 100644 js/data/odata/request_dispatcher.js delete mode 100644 js/events.d.ts create mode 100644 js/excel_exporter.d.ts create mode 100644 js/excel_exporter.js delete mode 100644 js/exporter/exceljs/excelExporter.js rename js/exporter/exceljs/{exportDataGrid.js => export_data_grid.js} (88%) create mode 100644 js/file_management/custom_provider.d.ts rename js/{ui/file_manager/file_provider/custom.js => file_management/custom_provider.js} (57%) create mode 100644 js/file_management/errors.js create mode 100644 js/file_management/file_system_item.d.ts create mode 100644 js/file_management/file_system_item.js create mode 100644 js/file_management/object_provider.d.ts rename js/{ui/file_manager/file_provider/array.js => file_management/object_provider.js} (86%) create mode 100644 js/file_management/provider_base.d.ts rename js/{ui/file_manager/file_provider/file_provider.js => file_management/provider_base.js} (53%) create mode 100644 js/file_management/remote_provider.d.ts rename js/{ui/file_manager/file_provider/remote.js => file_management/remote_provider.js} (89%) create mode 100644 js/file_management/upload_info.d.ts rename js/{ui/file_manager/ui.file_manager.utils.js => file_management/utils.js} (80%) rename js/ui/diagram/{diagram_bar.js => diagram.bar.js} (71%) rename js/ui/diagram/{ui.diagram.commands.js => diagram.commands_manager.js} (66%) create mode 100644 js/ui/diagram/diagram.edges_option.js rename js/ui/diagram/{diagram_importer.js => diagram.importer.js} (100%) rename js/ui/diagram/{diagram_item.js => diagram.items.js} (100%) rename js/ui/diagram/{ui.diagram.items.js => diagram.items_option.js} (100%) rename js/ui/diagram/{ui.diagram.nodes.js => diagram.nodes_option.js} (77%) rename js/ui/diagram/{ui.diagram.optionsupdate.js => diagram.options_update.js} (97%) create mode 100644 js/ui/diagram/diagram.toolbox_manager.js rename js/ui/diagram/{ui.diagram.contextmenu.js => ui.diagram.context_menu.js} (55%) rename js/ui/diagram/{ui.diagram.contexttoolbox.js => ui.diagram.context_toolbox.js} (100%) rename js/ui/diagram/{ui.diagram.dialogmanager.js => ui.diagram.dialog_manager.js} (97%) delete mode 100644 js/ui/diagram/ui.diagram.edges.js create mode 100644 js/ui/diagram/ui.diagram.floating_panel.js create mode 100644 js/ui/diagram/ui.diagram.history_toolbar.js delete mode 100644 js/ui/diagram/ui.diagram.leftpanel.js create mode 100644 js/ui/diagram/ui.diagram.main_toolbar.js create mode 100644 js/ui/diagram/ui.diagram.menu_helper.js rename js/ui/diagram/{diagram.panel.js => ui.diagram.panel.js} (100%) create mode 100644 js/ui/diagram/ui.diagram.view_toolbar.js delete mode 100644 js/ui/file_manager/file_provider/ajax.d.ts delete mode 100644 js/ui/file_manager/file_provider/ajax.js delete mode 100644 js/ui/file_manager/file_provider/array.d.ts delete mode 100644 js/ui/file_manager/file_provider/custom.d.ts delete mode 100644 js/ui/file_manager/file_provider/file_provider.d.ts delete mode 100644 js/ui/file_manager/file_provider/remote.d.ts create mode 100644 js/ui/file_manager/ui.file_manager.dialog_manager.js create mode 100644 js/ui/scheduler/workspaces/utils.work_week.js create mode 100644 testing/helpers/ignoreAngularTimers.js create mode 100644 testing/helpers/ignoreQuillTimers.js create mode 100644 testing/tests/DevExpress.core/utils.position.tests.js create mode 100644 testing/tests/DevExpress.localization/localization.intl.widgets.tests.js create mode 100644 testing/tests/DevExpress.serverSide/diagram.tests.js create mode 100644 testing/tests/DevExpress.ui.widgets.treeList/adaptiveColumns.tests.js create mode 100644 testing/tests/DevExpress.ui.widgets/diagramParts/clientSideEvents.tests.js create mode 100644 testing/tests/DevExpress.ui.widgets/diagramParts/commandManager.tests.js create mode 100644 testing/tests/DevExpress.ui.widgets/diagramParts/contextMenu.tests.js create mode 100644 testing/tests/DevExpress.ui.widgets/diagramParts/dom.tests.js create mode 100644 testing/tests/DevExpress.ui.widgets/diagramParts/historyToolbar.tests.js create mode 100644 testing/tests/DevExpress.ui.widgets/diagramParts/mainToolbar.tests.js create mode 100644 testing/tests/DevExpress.ui.widgets/diagramParts/options.tests.js create mode 100644 testing/tests/DevExpress.ui.widgets/diagramParts/propertiesPanel.tests.js create mode 100644 testing/tests/DevExpress.ui.widgets/diagramParts/toolbox.tests.js create mode 100644 testing/tests/DevExpress.ui.widgets/diagramParts/viewToolbar.tests.js delete mode 100644 testing/tests/DevExpress.ui.widgets/fileManagerParts/ajaxProvider.tests.js create mode 100644 testing/tests/DevExpress.ui.widgets/init_dispose_widget_bundled_tests.js diff --git a/.drone.yml b/.drone.yml index c1ef455100dd..ae4b5aeda661 100644 --- a/.drone.yml +++ b/.drone.yml @@ -17,7 +17,7 @@ pipeline: build: image: devexpress/devextreme-build:20_1 environment: - - TRAVIS=true + - TRAVIS=true commands: - ./drone-cache.sh restore - script -qefc ./docker-ci.sh /dev/null @@ -31,8 +31,14 @@ matrix: - { TARGET: test, CONSTEL: misc } - { TARGET: test, CONSTEL: ui } - { TARGET: test, CONSTEL: ui.editors } + - { TARGET: test, CONSTEL: ui.editors, TZ: 'PST8PDT' } + - { TARGET: test, CONSTEL: ui.editors, TZ: 'Japan' } + - { TARGET: test, CONSTEL: ui.editors, TZ: 'Australia/ACT' } - { TARGET: test, CONSTEL: ui.grid } - { TARGET: test, CONSTEL: ui.scheduler } + - { TARGET: test, CONSTEL: ui.scheduler, TZ: 'PST8PDT' } + - { TARGET: test, CONSTEL: ui.scheduler, TZ: 'Japan' } + - { TARGET: test, CONSTEL: ui.scheduler, TZ: 'Australia/ACT' } - { TARGET: test, CONSTEL: viz } - { TARGET: test, PERF: true, JQUERY: true, NO_HEADLESS: true } - { TARGET: test, MOBILE_UA: ios9, CONSTEL: ui } @@ -48,8 +54,9 @@ matrix: - { TARGET: test, BROWSER: firefox, JQUERY: true, CONSTEL: ui.scheduler } - { TARGET: test, BROWSER: firefox, JQUERY: true, CONSTEL: viz } - { TARGET: test_functional, COMPONENT: dataGrid } - - { TARGET: test_functional, COMPONENT: scheduler } + - { TARGET: test_functional, COMPONENT: scheduler, QUARANTINE_MODE: true } - { TARGET: test_functional, COMPONENT: editors } - { TARGET: test_functional, COMPONENT: navigation } - { TARGET: test_themebuilder } - { TARGET: test_jest } + - { TARGET: test_scss } diff --git a/.gitignore b/.gitignore index 3f04c554b097..aecd07a8afe3 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ /js/**/*.p.js /themebuilder/data/less /themebuilder/data/metadata +/scss bin node_modules obj diff --git a/.travis.yml b/.travis.yml index 4b526c11461c..9febaf883b5d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,8 +12,14 @@ env: - TARGET=test CONSTEL=misc - TARGET=test CONSTEL=ui - TARGET=test CONSTEL=ui.editors + - TARGET=test CONSTEL=ui.editors TZ='PST8PDT' + - TARGET=test CONSTEL=ui.editors TZ='Japan' + - TARGET=test CONSTEL=ui.editors TZ='Australia/ACT' - TARGET=test CONSTEL=ui.grid - TARGET=test CONSTEL=ui.scheduler + - TARGET=test CONSTEL=ui.scheduler TZ='PST8PDT' + - TARGET=test CONSTEL=ui.scheduler TZ='Japan' + - TARGET=test CONSTEL=ui.scheduler TZ='Australia/ACT' - TARGET=test CONSTEL=viz - TARGET=test PERF=true JQUERY=true NO_HEADLESS=true - TARGET=test MOBILE_UA=ios9 CONSTEL=ui @@ -29,11 +35,12 @@ env: - TARGET=test BROWSER=firefox JQUERY=true CONSTEL=ui.scheduler - TARGET=test BROWSER=firefox JQUERY=true CONSTEL=viz - TARGET=test_functional COMPONENT=dataGrid - - TARGET=test_functional COMPONENT=scheduler + - TARGET=test_functional COMPONENT=scheduler QUARANTINE_MODE=true - TARGET=test_functional COMPONENT=editors - TARGET=test_functional COMPONENT=navigation - TARGET=test_themebuilder - TARGET=test_jest + - TARGET=test_scss cache: directories: diff --git a/build/docker-image/README.txt b/build/docker-image/README.txt index 6f547646d963..6fadf9f52676 100644 --- a/build/docker-image/README.txt +++ b/build/docker-image/README.txt @@ -2,7 +2,7 @@ Build: docker build -t devexpress/devextreme-build:YYYY-MM-DD . Debug: - docker run --rm -ti -p 5900:5900 -e TARGET=test -v REPO_PATH:/devextreme devexpress/devextreme-build:YYYY-MM-DD ./docker-ci.sh + docker run --rm -ti -p 5900:5900 -e NO_HEADLESS=true -e TARGET=test -v REPO_PATH:/devextreme devexpress/devextreme-build:YYYY-MM-DD ./docker-ci.sh Move tag: docker tag devexpress/devextreme-build:YYYY-MM-DD devexpress/devextreme-build:XX_X diff --git a/build/gulp/localization.js b/build/gulp/localization.js index 2a6d67749831..0889a3b5db94 100644 --- a/build/gulp/localization.js +++ b/build/gulp/localization.js @@ -87,8 +87,8 @@ const getMessages = function(directory, locale) { return serializeObject(json, true); }; -gulp.task('localization-messages', gulp.parallel(getLocales(DICTIONARY_SOURCE_FOLDER).map(locale => { - return function() { +gulp.task('localization-messages', gulp.parallel(getLocales(DICTIONARY_SOURCE_FOLDER).map(locale => Object.assign( + function() { return gulp .src('build/gulp/localization-template.jst') .pipe(template({ @@ -99,8 +99,9 @@ gulp.task('localization-messages', gulp.parallel(getLocales(DICTIONARY_SOURCE_FO .pipe(headerPipes.useStrict()) .pipe(headerPipes.bangLicense()) .pipe(gulp.dest(RESULT_PATH)); - }; -}))); + }, + { displayName: 'dx.messages.' + locale } +)))); gulp.task('localization-generated-sources', gulp.parallel([ { @@ -124,8 +125,8 @@ gulp.task('localization-generated-sources', gulp.parallel([ destination: 'js/localization/cldr-data' } -].map((source) => { - return function() { +].map((source) => Object.assign( + function() { return gulp .src('build/gulp/generated_js.jst') .pipe(template({ @@ -135,7 +136,8 @@ gulp.task('localization-generated-sources', gulp.parallel([ .pipe(lint.format()) .pipe(rename(source.filename)) .pipe(gulp.dest(source.destination)); - }; -}))); + }, + { displayName: source.filename } +)))); gulp.task('localization', gulp.series('localization-messages', 'localization-generated-sources')); diff --git a/build/gulp/modules_metadata.json b/build/gulp/modules_metadata.json index ddbad410b97f..c30f69179873 100644 --- a/build/gulp/modules_metadata.json +++ b/build/gulp/modules_metadata.json @@ -177,6 +177,30 @@ "triggerHandler": { "path": "events.triggerHandler" } } }, + { + "name": "file_management/file_system_item", + "exports": { + "default": { "path": "fileManagement.FileSystemItem" } + } + }, + { + "name": "file_management/custom_provider", + "exports": { + "default": { "path": "fileManagement.CustomFileSystemProvider" } + } + }, + { + "name": "file_management/object_provider", + "exports": { + "default": { "path": "fileManagement.ObjectFileSystemProvider" } + } + }, + { + "name": "file_management/remote_provider", + "exports": { + "default": { "path": "fileManagement.RemoteFileSystemProvider" } + } + }, { "name": "integration/jquery" }, @@ -362,30 +386,6 @@ "default": { "path": "ui.dxFileManager", "isWidget": true } } }, - { - "name": "ui/file_manager/file_provider/remote", - "exports": { - "default": { "path": "fileProvider.RemoteFileProvider" } - } - }, - { - "name": "ui/file_manager/file_provider/custom", - "exports": { - "default": { "path": "fileProvider.CustomFileProvider" } - } - }, - { - "name": "ui/file_manager/file_provider/array", - "exports": { - "default": { "path": "fileProvider.ArrayFileProvider" } - } - }, - { - "name": "ui/file_manager/file_provider/ajax", - "exports": { - "default": { "path": "fileProvider.AjaxFileProvider" } - } - }, { "name": "ui/form", "exports": { diff --git a/build/gulp/scss/compiler.js b/build/gulp/scss/compiler.js new file mode 100644 index 000000000000..0d1b8a6dfefb --- /dev/null +++ b/build/gulp/scss/compiler.js @@ -0,0 +1,13 @@ +const sass = require('gulp-dart-sass'); +const gulp = require('gulp'); + +const outputPath = require('./config').outputPath; + +const compileBundle = (bundleName) => { + return gulp.src(bundleName) + .pipe(sass()) + .pipe(gulp.dest('artifacts/scss-css')); +}; + +gulp.task('sass-material', () => compileBundle(`${outputPath}/bundles/dx.material.blue.light.scss`)); +gulp.task('sass-generic', () => compileBundle(`${outputPath}/bundles/dx.light.scss`)); diff --git a/build/gulp/scss/config.js b/build/gulp/scss/config.js new file mode 100644 index 000000000000..ddce5a91941f --- /dev/null +++ b/build/gulp/scss/config.js @@ -0,0 +1,4 @@ +module.exports = { + outputPath: 'scss', + unfixedScssPath: 'styles' +}; diff --git a/build/gulp/scss/generator.js b/build/gulp/scss/generator.js new file mode 100644 index 000000000000..046ccf4531c4 --- /dev/null +++ b/build/gulp/scss/generator.js @@ -0,0 +1,433 @@ +const gulp = require('gulp'); +const path = require('path'); +const fs = require('fs'); +const replace = require('gulp-replace'); +const rename = require('gulp-rename'); +const del = require('del'); +const through = require('through2'); +const exec = require('child_process').exec; + +const outputPath = require('./config').outputPath; +const unfixedScssPath = require('./config').unfixedScssPath; +const repositoryRoot = path.join(__dirname, '../../..'); + +const allImportReplacement = /@import \((once|reference|)\) (".*\/)(.*?).scss(";)/g; + +const compactMixinReplacementIndex = /@mixin dx-size-default\(\)\s*{([\w\W]*?)}\s*@mixin dx-size-compact\(\)\s*{([\w\W]*?)}/g; +const compactMixinReplacementSizes = /[\w\W]*?@mixin dx-size-default\(\)\s*{([\w\W]*?)}\s*@mixin dx-size-compact\(\)\s*{([\w\W]*?)}([\w\W]*)/g; +const compactMixinUsageReplacement = /@include\s+dx-size-(compact|default);/g; + +// replacement for parent selector (https://github.com/sass/sass/issues/1425) +const parentSelectorRegex = /^(\s*)([.\w\s-]*[\w])&/mg; +const parentSelectorReplacement = '$1@at-root $2#{&}'; + +let widgetsColorVariables = {}; + +gulp.task('scss-raw-scss-clean', () => del(`${unfixedScssPath}/**/*.scss`)); +gulp.task('scss-clean', gulp.series( + 'scss-raw-scss-clean', + () => del(outputPath) +)); + +gulp.task('less2sass', (callback) => { + exec('npx less2sass styles', (e, out, err) => { + console.log(out); + console.log(err); + callback(e); + }); +}); + +const replaceColorFunctions = (content) => { + // TODO lighten and darken is not included directly in the new module system (https://sass-lang.com/documentation/modules/color#lighten), but it works + // change fade($color, 20%) to the color.change($color, $alpha: 0.20), $color can be other function + // change fadein($color, 20%) to the color.adjust($color, $alpha: 0.20), $color can be other function + + content = content.replace(/(fadein|fade)\(([$\d\w-#]*|[\w]*\(.*\)),\s*(\d+)%\)(;|,|\))/g, (match, func, color, percent, sign) => { + const colorFunction = func === 'fade' ? 'change' : 'adjust'; + return `color.${colorFunction}(${color}, $alpha: ${percent / 100})${sign}`; + }); + return content; +}; + +gulp.task('fix-bundles', () => { + return gulp + .src(`${unfixedScssPath}/bundles/*.scss`) + // next replaces make @use "../widgets/generic" with (); + .pipe(replace(/@import \(once\).*/, '')) + .pipe(replace(/\$base-theme:\s*"(generic|material|ios7)";/, '@use "../widgets/$1" with (')) + .pipe(replace(/;/g, ',')) + .pipe(replace(/,[\W]*$/g, '\n);\n')) + .pipe(replace(/\$light/, '$mode')) + .pipe(gulp.dest(`${outputPath}/bundles`)); +}); + +gulp.task('fix-base', () => { + // the same code for different themes + return gulp + .src(`${unfixedScssPath}/widgets/base/*.scss`) + // .pipe(replace(/\.dx-font-icon\("/g, '@include dx-font-icon("')) + // icons + .pipe(replace('@mixin dx-icon-sizing', '@use "sass:map";\n\n@mixin dx-icon-sizing')) + .pipe(replace('@mixin dx-font-icon($icons[$$name]),', '@include dx-font-icon(map.get($icons, $name));')) + .pipe(replace(/\$icons:\s{([\w\W]*?)}/, (_, codes) => { + return `$icons: (${codes.replace(/;/g, ',')});`; + })) + .pipe(replace('f11d",', 'f11d"')) + .pipe(replace(/each\(\$icons,\s{([\w\W]*)}\);/, '@each $key, $val in $icons {$1}')) + + .pipe(replace(parentSelectorRegex, parentSelectorReplacement)) + .pipe(rename((path) => { + path.basename = '_' + path.basename; + })) + .pipe(gulp.dest(`${outputPath}/widgets/base`)); +}); + +gulp.task('fix-common', () => { + // for dx.common.css + // TODO + return gulp + .src(`${unfixedScssPath}/widgets/common/*.scss`) + .pipe(rename((path) => { + path.basename = '_' + path.basename; + })) + .pipe(gulp.dest(`${outputPath}/widgets/common`)); +}); + +gulp.task('fix-mixins', () => { + return gulp + .src(`${unfixedScssPath}/mixins.scss`) + .pipe(replace('user-select: $value;', 'user-select: $value;\n @if $value == none {\n -webkit-touch-callout: none;\n }')) + .pipe(replace(/@mixin user-select\(\$value\) when \(\$value = none\)[\w\W]*?}/g, '')) + .pipe(rename((path) => { + path.basename = '_' + path.basename; + })) + .pipe(gulp.dest(`${outputPath}/widgets/base`)); +}); + +const specificReplacement = (content, folder, file) => { + const widget = path.basename(folder); + const replacementTable = require('./replacements'); + + if(replacementTable[widget]) { + replacementTable[widget].forEach(r => { + if(r.regex && file === 'index') { + content = content.replace(r.regex, r.replacement); + } else if(r.import && r.type === file) { + content = content.replace(/\/\/\sadduse/, `// adduse\n@use "${r.import}" as *;`); + } + + }); + } + + return content; +}; + +gulp.task('create-widgets', () => { + return gulp + .src([`${unfixedScssPath}/widgets/generic/*.scss`, `${unfixedScssPath}/widgets/material/*.scss`], { base: `${unfixedScssPath}/` }) + .pipe(replace(compactMixinUsageReplacement, '')) + // remove all dependency imports + .pipe(replace(allImportReplacement, '')) + .pipe(rename((path) => { + const widgetName = path.basename.replace(/\.(material|generic)/g, ''); + path.dirname += `/${widgetName}`; + path.basename = '_index'; + })) + .pipe(gulp.dest(outputPath)) + .pipe(through.obj((chunk, enc, callback) => { + const folder = chunk.path.replace('_index.scss', ''); + const content = chunk.contents.toString(); + + // remove size mixins from _index + let indexContent = '@use "sass:color";\n'; + indexContent += '@use "colors" as *;\n'; + indexContent += '@use "../colors" as *;\n'; + indexContent += '@use "sizes" as *;\n'; + indexContent += '@use "../sizes" as *;\n'; + + indexContent += '// adduse\n'; + indexContent += content.replace(compactMixinReplacementIndex, ''); + indexContent = specificReplacement(indexContent, folder, 'index'); + indexContent = replaceColorFunctions(indexContent); + indexContent = indexContent.replace(parentSelectorRegex, parentSelectorReplacement); + chunk.contents = new Buffer(indexContent); + + let colorsContent = '@use "sass:color";\n'; + colorsContent += '@use "../sizes" as *;\n'; + colorsContent += '@use "../colors" as *;\n'; + colorsContent += '// adduse\n\n'; + colorsContent = specificReplacement(colorsContent, folder, 'colors'); + + fs.writeFileSync(path.join(folder, '_colors.scss'), colorsContent); + + // add size mixins into _sizes + let sizesContent = '@use "../sizes" as *;\n'; + sizesContent += '// adduse\n\n'; + sizesContent = specificReplacement(sizesContent, folder, 'sizes'); + if(compactMixinReplacementSizes.test(content)) { + sizesContent += content.replace(compactMixinReplacementSizes, (match, defaultSize, compactSize) => { + const defaultDefinition = defaultSize.replace(/^\s*(\$.*?):.*?;/gm, '$1: null !default;'); + return `${defaultDefinition}\n@if $size == "default" {${defaultSize}}\n@else if $size == "compact" {${compactSize}}`; + }); + } + + fs.writeFileSync(path.join(folder, '_sizes.scss'), sizesContent); + + callback(null, chunk); + })) + .pipe(gulp.dest(outputPath)); +}); + + +const getBaseContent = (content) => content.replace(/\/\/[\w\W]*/, ''); +const getVariableNames = (content) => { + const variableRegex = /^(\$[\w-_].*?):/gm; + const variables = []; + + let tmp; + while((tmp = variableRegex.exec(content)) !== null) { + const varName = tmp[1]; + if(variables.indexOf(varName) < 0) variables.push(varName); + } + + return variables; +}; +const generateDefaultVariablesBlock = (variables) => { + let content = ''; + variables.forEach(variable => { + content += `${variable}: null !default;\n`; + }); + return content; +}; + +const createBaseWidgetFolder = (theme) => { + const baseWidgetPath = path.join(repositoryRoot, outputPath, 'widgets', theme); + if(!fs.existsSync(baseWidgetPath)) fs.mkdirSync(baseWidgetPath); + return baseWidgetPath; +}; + +const makeIndent = (content) => { + return content.replace(/(^.*)/gm, ' $1'); +}; + +const fillWidgetColors = (theme) => { + Object.keys(widgetsColorVariables).forEach(widget => { + const targetFilePath = path.join(repositoryRoot, outputPath, 'widgets', theme, widget, '_colors.scss'); + + if(!fs.existsSync(targetFilePath)) { + console.log('Widget file not found: ', targetFilePath); + return; + } + + const currentContent = fs.readFileSync(targetFilePath).toString(); + let additionalContent = ''; + let widgetVariablesContent = ''; + + Object.keys(widgetsColorVariables[widget]).forEach(colorScheme => { + const variableName = theme === 'material' ? 'mode' : 'color'; + let variablesContent = widgetsColorVariables[widget][colorScheme]; + variablesContent = replaceColorFunctions(variablesContent); + widgetVariablesContent += variablesContent; + additionalContent += `@if $${variableName} == "${colorScheme}" {\n${makeIndent(variablesContent)}\n}\n\n`; + }); + + const widgetVariablesForDefine = getVariableNames(widgetVariablesContent); + + fs.writeFileSync(targetFilePath, [ + currentContent, + generateDefaultVariablesBlock(widgetVariablesForDefine), + additionalContent + ].join('\n\n')); + }); +}; + +const collectWidgetColorVariables = (content, schemeName) => { + const widgetContentRegex = /\/\/\s?(?!TODO)(dx)?(\w.*)([\w\W]*?)(\n\/\/|$)/g; + const aliases = { + 'normal button': 'button', + 'default button': 'button', + 'danger button': 'button', + 'success button': 'button', + 'flat button': 'button', + 'badges': 'badge', + 'color view': 'colorView', + 'normal button (buttongroup)': 'buttonGroup', + 'default button (buttongroup)': 'buttonGroup', + 'danger button (buttongroup)': 'buttonGroup', + 'success button (buttongroup)': 'buttonGroup', + 'checkbox': 'checkBox', + 'fileuploader': 'fileUploader', + 'selectbox': 'selectBox' + }; + + let regResult; + while((regResult = widgetContentRegex.exec(content)) !== null) { + let widget = regResult[2]; + widget = widget[0].toLowerCase() + widget.slice(1); + const lowerCaseWidget = widget.toLowerCase(); + if(aliases[lowerCaseWidget]) widget = aliases[lowerCaseWidget]; + const widgetContent = regResult[3]; + widgetContentRegex.lastIndex -= 2; + + widgetsColorVariables[widget] = widgetsColorVariables[widget] || {}; + widgetsColorVariables[widget][schemeName] = widgetsColorVariables[widget][schemeName] || ''; + widgetsColorVariables[widget][schemeName] += widgetContent; + } +}; + +const cleanWidgetColorVariables = () => { + widgetsColorVariables = {}; +}; + +gulp.task('create-base-widget-generic-colors', (callback) => { + const baseWidgetPath = createBaseWidgetFolder('generic'); + + // _colors + + // read all base variables (to the first widget-specific comment) + const sourcePath = path.join(repositoryRoot, unfixedScssPath, 'widgets', 'generic', 'color-schemes'); + const genericLightPath = path.join(sourcePath, 'light', 'generic.light.scss'); + const genericLightIconsPath = path.join(sourcePath, 'light', 'generic.light.icons.scss'); + const themeIconsContent = fs.readFileSync(genericLightIconsPath).toString(); + const genericContent = fs.readFileSync(genericLightPath).toString(); + const genericBaseContent = getBaseContent(genericContent) + '\n' + themeIconsContent; + const genericBaseVariables = getVariableNames(genericBaseContent); + + let colorsContent = '@use "sass:color";\n$color: null !default;\n\n'; + colorsContent += generateDefaultVariablesBlock(genericBaseVariables); + colorsContent += '\n'; + + fs.readdir(sourcePath, (e, files) => { + files.forEach(file => { + const themeDir = path.join(sourcePath, file); + const themeContent = fs.readFileSync(path.join(themeDir, `generic.${file}.scss`)).toString(); + const themeIconsContent = fs.readFileSync(path.join(themeDir, `generic.${file}.icons.scss`)).toString(); + const baseThemeContent = getBaseContent(themeContent); + colorsContent += `@if $color == "${file}" {\n${makeIndent(baseThemeContent + themeIconsContent)}\n}\n\n`; + colorsContent = replaceColorFunctions(colorsContent); + + collectWidgetColorVariables(themeContent, file); + }); + + fs.writeFileSync(path.join(baseWidgetPath, '_colors.scss'), colorsContent); + fillWidgetColors('generic'); + cleanWidgetColorVariables(); + callback(); + }); +}); + +gulp.task('create-base-widget-material-colors', (callback) => { + const baseWidgetPath = createBaseWidgetFolder('material'); + + // _colors + + // read all base variables (to the first widget-specific comment) + const sourcePath = path.join(repositoryRoot, unfixedScssPath, 'widgets', 'material', 'color-schemes'); + const materialLightPath = path.join(sourcePath, 'material.light.scss'); + const materialLightIconsPath = path.join(sourcePath, 'material.light.icons.scss'); + const materialLightColorPath = path.join(sourcePath, 'blue/material.blue.scss'); + const themeIconsContent = fs.readFileSync(materialLightIconsPath).toString(); + const materialContent = fs.readFileSync(materialLightPath).toString(); + const materialColorContent = fs.readFileSync(materialLightColorPath).toString(); + const materialBaseContent = [materialColorContent, getBaseContent(materialContent), themeIconsContent].join('\n'); + const materialBaseVariables = getVariableNames(materialBaseContent); + + let colorsContent = '@use "sass:color";\n$color: null !default;\n$mode: null !default;\n\n'; + colorsContent += generateDefaultVariablesBlock(materialBaseVariables); + colorsContent += '\n'; + + fs.readdir(sourcePath, { withFileTypes: true }, (e, files) => { + files.forEach(file => { + if(file.isFile()) return; + const themeDir = path.join(sourcePath, file.name); + const themeContent = fs.readFileSync(path.join(themeDir, `material.${file.name}.scss`)).toString(); + colorsContent += `@if $color == "${file.name}" {\n${makeIndent(themeContent)}\n}\n\n`; + }); + + ['light', 'dark'].forEach(mode => { + const themeContent = fs.readFileSync(path.join(sourcePath, `material.${mode}.scss`)).toString(); + const themeIconsContent = fs.readFileSync(path.join(sourcePath, `material.${mode}.icons.scss`)).toString(); + colorsContent += `@if $mode == "${mode}" {\n${makeIndent([getBaseContent(themeContent), themeIconsContent].join('\n'))}\n}\n\n`; + colorsContent = replaceColorFunctions(colorsContent); + + collectWidgetColorVariables(themeContent, mode); + }); + + fs.writeFileSync(path.join(baseWidgetPath, '_colors.scss'), colorsContent); + fillWidgetColors('material'); + cleanWidgetColorVariables(); + callback(); + }); +}); + +gulp.task('create-base-widget-sizes', (callback) => { + ['generic', 'material'].forEach(theme => { + const baseWidgetPath = createBaseWidgetFolder(theme); + const sourcePath = path.join(repositoryRoot, unfixedScssPath, 'widgets', theme, 'size-schemes'); + const sharedBasePath = path.join(sourcePath, 'shared/base.scss'); + const sharedMobilePath = path.join(sourcePath, 'shared/mobile.scss'); + const sharedBaseContent = fs.readFileSync(sharedBasePath).toString(); + const sharedMobileContent = fs.existsSync(sharedMobilePath) ? fs.readFileSync(sharedMobilePath).toString() : ''; + + const defaultSizePath = path.join(sourcePath, 'default.scss'); + const defaultSizeContent = fs.readFileSync(defaultSizePath).toString(); + const defaultSizeVariables = getVariableNames(defaultSizeContent); + + let sizesContent = '$size: null !default;\n@use "colors" as *;\n\n'; + sizesContent += generateDefaultVariablesBlock(defaultSizeVariables); + + ['default', 'compact'].forEach(size => { + let sizeContent = fs.readFileSync(path.join(sourcePath, `${size}.scss`)).toString(); + sizeContent = sizeContent.replace(/^@(import|include).*/gm, ''); + sizesContent += `@if $size == "${size}" {\n${makeIndent(sizeContent)}\n}\n\n`; + }); + + sizesContent += [sharedBaseContent, sharedMobileContent].join('\n'); + + fs.writeFileSync(path.join(baseWidgetPath, '_sizes.scss'), sizesContent); + }); + callback(); +}); + +gulp.task('create-base-widget', gulp.series( + 'create-base-widget-generic-colors', + 'create-base-widget-material-colors', + 'create-base-widget-sizes' +)); + +// TODO - ui - need only into dx.common.css bundle + +gulp.task('create-theme-index', (callback) => { + const source = require('./index-data'); + + const themes = ['generic', 'material']; + + themes.forEach(theme => { + const fileName = path.join(repositoryRoot, outputPath, 'widgets', theme, '_index.scss'); + let content = '$color: null !default;\n'; + content += '$size: null !default;\n'; + if(theme === 'material') { + content += '$mode: null !default;\n\n'; + } else { + content += '\n'; + } + + const modePart = theme === 'material' ? ', $mode: $mode' : ''; + content += `@use "colors" with ($color: $color${modePart});\n@use "sizes" with ($size: $size);`; + + source.forEach(item => { + if(item.task === 'comment') { + content += `// ${item.content}\n`; + } else if(item.task === 'widget') { + const privateComment = item.private ? ' // private' : ''; + content += `@use "./${item.content}";${privateComment}\n`; + } else if(item.task === 'newline') { + content += '\n'; + } + }); + + fs.writeFileSync(fileName, content); + }); + + callback(); +}); diff --git a/build/gulp/scss/index-data.js b/build/gulp/scss/index-data.js new file mode 100644 index 000000000000..5ea540578250 --- /dev/null +++ b/build/gulp/scss/index-data.js @@ -0,0 +1,75 @@ +module.exports = [ + // each object has one of these tasks: + // widget - widget reference + // comment - comment + // newline - just new line + { content: 'ex. core', task: 'comment' }, + // mixins - in place @use + // typography + { content: 'typography', task: 'widget', private: true }, + // common - used in typogrphy, in place @use + // icons + { content: 'icons', task: 'widget', private: true }, + // widget + { content: 'widget', task: 'widget', private: true }, + // card + { content: 'card', task: 'widget' }, + // fieldset + { content: 'fieldset', task: 'widget' }, + + + { content: 'public widgets', task: 'comment' }, + { content: 'box', task: 'widget' }, + { content: 'responsiveBox', task: 'widget' }, + { content: 'button', task: 'widget' }, + { content: 'buttonGroup', task: 'widget' }, + { content: 'scrollable', task: 'widget', private: true }, + { content: 'scrollView', task: 'widget' }, + { content: 'checkBox', task: 'widget' }, + { content: 'switch', task: 'widget' }, + { content: 'badge', task: 'widget', private: true }, + { content: 'tabs', task: 'widget' }, + { content: 'navBar', task: 'widget' }, + { content: 'validation', task: 'widget', private: true }, + { content: 'textEditor', task: 'widget', private: true }, + { content: 'textBox', task: 'widget', private: true }, + { content: 'dropDownEditor', task: 'widget', private: true }, + { content: 'dropDownBox', task: 'widget' }, + { content: 'list', task: 'widget' }, + { content: 'textArea', task: 'widget' }, + { content: 'numberBox', task: 'widget' }, + { content: 'dateView', task: 'widget', private: true }, + { content: 'timeView', task: 'widget', private: true }, + { content: 'calendar', task: 'widget' }, + { content: 'dateBox', task: 'widget' }, + { content: 'dropDownList', task: 'widget', private: true }, + { content: 'autocomplete', task: 'widget' }, + { content: 'loadIndicator', task: 'widget' }, + { content: 'treeView', task: 'widget' }, + { content: 'overlay', task: 'widget', private: true }, + { content: 'menu', task: 'widget' }, + { content: 'selectBox', task: 'widget' }, + { content: 'dropDownMenu', task: 'widget', private: true }, + { content: 'toolbar', task: 'widget' }, + { content: 'popup', task: 'widget' }, + { content: 'dropDownButton', task: 'widget' }, + { content: 'actionSheet', task: 'widget' }, + { content: 'tileView', task: 'widget' }, + { content: 'toast', task: 'widget' }, + { content: 'popover', task: 'widget' }, + { content: 'progressBar', task: 'widget' }, + { content: 'tooltip', task: 'widget' }, + { content: 'slider', task: 'widget' }, + { content: 'rangeSlider', task: 'widget' }, + { content: 'gallery', task: 'widget' }, + { content: 'lookup', task: 'widget' }, + { content: 'loadPanel', task: 'widget' }, + { content: 'tagBox', task: 'widget' }, + { content: 'radioGroup', task: 'widget' }, + { content: 'accordion', task: 'widget' }, + { content: 'slideOutView', task: 'widget' }, + { content: 'slideOut', task: 'widget' }, + { content: 'colorView', task: 'widget', private: true }, + { content: 'colorBox', task: 'widget' }, + { task: 'newline' } +]; diff --git a/build/gulp/scss/replacements.js b/build/gulp/scss/replacements.js new file mode 100644 index 000000000000..7962bdf7e9f9 --- /dev/null +++ b/build/gulp/scss/replacements.js @@ -0,0 +1,246 @@ +module.exports = { + // regex, replacement - replace + // import, type - additional import ( + // index - in _index.scss file + // colors - in _colors.scss file + // sizes - in _sizes.scss file) + 'typography': [ + { regex: /\(css\)\s/, replacement: '' }, + { import: '../common', type: 'index' }, + ], + 'common': [ + { regex: /([^$][\w-].*?:\s.*),$/gm, replacement: '$1;' }, + { regex: /\.user-select\(none\),/, replacement: '@include user-select(none);' }, + { regex: /@mixin badge-settings\(\),/, replacement: '@include badge-settings();' }, + { regex: /@mixin validation-badge-animation\(\),/, replacement: '@include validation-badge-animation();' }, + { import: '../../base/mixins', type: 'index' }, + { import: '../../base/validation', type: 'index' }, + { import: '../list/sizes', type: 'index' }, + ], + 'icons': [ + { regex: /@import \(once\) "..\/base\/icons.scss";/, replacement: '' }, + { import: '../../base/icons', type: 'index' }, + ], + 'widget': [ + { import: '../common', type: 'index' }, + ], + 'fieldset': [ + { import: '../common/sizes', type: 'index' }, + { import: '../common', type: 'index' }, + { import: '../typography', type: 'index' }, + ], + 'button': [ + { import: '../../base/icons', type: 'index' }, + { regex: /@mixin dx-icon-sizing\(\$ICON_SIZE\),/, replacement: '@include dx-icon-sizing($ICON_SIZE);' }, + { regex: /\.dx-icon-margin\(\$ICON_MARGIN\),/, replacement: '@include dx-icon-margin($ICON_MARGIN);' }, + { regex: /@mixin dx-button-onlyicon-sizing\(\),/, replacement: '@include dx-button-onlyicon-sizing();' }, + { regex: /.dx-button-onlyicon-sizing\(\),/, replacement: '@include dx-button-onlyicon-sizing();' }, + { regex: /.dx-button-withtext-sizing\(\),/, replacement: '@include dx-button-withtext-sizing();' }, + { regex: /.dx-button-text-and-icon-sizing\(\),/, replacement: '@include dx-button-text-and-icon-sizing();' }, + { regex: /\$MATERIAL_BUTTON_MIN_WIDTH,/, replacement: '$MATERIAL_BUTTON_MIN_WIDTH;' } + ], + 'buttonGroup': [ + { import: '../button', type: 'index' }, + { import: '../button/colors', type: 'index' }, + { import: '../button/colors', type: 'colors' }, + ], + 'scrollView': [ + { import: '../scrollable/colors', type: 'index' }, + ], + 'checkBox': [ + { import: 'colors', type: 'sizes' }, + { import: '../../base/icons', type: 'index' }, + ], + 'switch': [ + { import: '../../base/mixins', type: 'index' }, + ], + 'tabs': [ + { import: '../button', type: 'index' }, + { import: '../button/colors', type: 'index' }, + { import: '../button/colors', type: 'colors' }, + { import: '../../base/icons', type: 'index' }, + ], + 'navBar': [ + { import: '../../base/icons', type: 'index' }, + ], + 'validation': [ + { import: '../../base/validation', type: 'index' }, + ], + 'textEditor': [ + { import: '../../base/icons', type: 'index' }, + { import: '../common/sizes', type: 'index' }, + { import: '../button/sizes', type: 'index' }, + { import: '../common', type: 'index' }, + { import: '../button', type: 'index' }, + { regex: /@mixin texteditor-input-padding-filled\(\),/g, replacement: '@inclide texteditor-input-padding-filled();' }, + { regex: /@mixin texteditor-input-padding\(\),/g, replacement: '@inclide texteditor-input-padding();' }, + { regex: /.texteditor-validation-icon-offset-filled\(\),/g, replacement: '@include texteditor-validation-icon-offset-filled();' }, + { regex: /.texteditor-validation-icon-offset\(\),/g, replacement: '@include texteditor-validation-icon-offset();' }, + { regex: /@mixin dx-icon-sizing\(\$MATERIAL_TEXTEDITOR_ICON_CONTAINER_SIZE\),/, replacement: '@include dx-icon-sizing($MATERIAL_TEXTEDITOR_ICON_CONTAINER_SIZE);' }, + { regex: /@mixin dx-texteditor-icon\(\),/, replacement: '@include dx-texteditor-icon();' }, + { regex: /.dx-icon-font-centered-sizing\(\$MATERIAL_TEXTEDITOR_CLEAR_ICON_SIZE\),/, replacement: '@include dx-icon-font-centered-sizing($MATERIAL_TEXTEDITOR_CLEAR_ICON_SIZE);' }, + { regex: /\$texteditor-input-border-radius,/g, replacement: '$texteditor-input-border-radius;' }, + { regex: /relative,/g, replacement: 'relative;' } + ], + 'textBox': [ + { import: '../../base/icons', type: 'index' }, + { import: '../textEditor', type: 'index' }, + { import: '../textEditor/colors', type: 'index' }, + { import: '../textEditor/sizes', type: 'index' }, + ], + 'dropDownEditor': [ + { import: '../common', type: 'index' }, + { import: '../common/sizes', type: 'index' }, + { import: '../textEditor/sizes', type: 'index' }, + { import: '../button/colors', type: 'colors' }, + { import: '../button/colors', type: 'index' }, + { import: '../textEditor/colors', type: 'colors' }, + { import: '../../base/icons', type: 'index' }, + ], + 'dropDownBox': [ + { import: '../dropDownEditor', type: 'index' }, + ], + 'list': [ + { import: '../../base/icons', type: 'index' }, + { import: '../button/colors', type: 'colors' }, + { import: '../button/colors', type: 'index' }, + { import: '../button/sizes', type: 'index' }, + { import: '../button', type: 'index' }, + { import: '../checkBox/colors', type: 'index' }, + { import: '../list/colors', type: 'sizes' }, + { regex: /@mixin item-states\(\),/, replacement: '@include item-states();' }, + { regex: /@mixin dx-icon\(chevronnext\),/, replacement: '@include dx-icon(chevronnext);' }, + { regex: /.dx-icon-sizing\(\$GENERIC_BASE_ICON_SIZE\),/g, replacement: '@include dx-icon-sizing($GENERIC_BASE_ICON_SIZE);' }, + { regex: /margin-left: -5px,/, replacement: 'margin-left: -5px;' }, + { regex: /color: \$list-item-chevron-icon-color,/, replacement: 'color: $list-item-chevron-icon-color;' }, + { regex: /width: \$GENERIC_BASE_ICON_SIZE \+ \$GENERIC_LIST_ITEM_HORIZONTAL_PADDING,/, replacement: 'width: $GENERIC_BASE_ICON_SIZE + $GENERIC_LIST_ITEM_HORIZONTAL_PADDING;' }, + { regex: /height: \$GENERIC_BASE_ICON_SIZE,/, replacement: 'height: $GENERIC_BASE_ICON_SIZE;' }, + { regex: /vertical-align: top,/, replacement: 'vertical-align: top;' }, + { regex: /margin-bottom: \$GENERIC_LIST_SEARCHBOX_MARGIN_BOTTOM,/, replacement: 'margin-bottom: $GENERIC_LIST_SEARCHBOX_MARGIN_BOTTOM;' } + + ], + 'numberBox': [ + { import: '../../base/icons', type: 'index' }, + { import: '../textEditor', type: 'index' }, + { import: '../textEditor/sizes', type: 'index' }, + { import: '../textEditor/colors', type: 'index' }, + { import: '../button/colors', type: 'colors' }, + ], + 'dateView': [ + { import: '../../base/mixins', type: 'index' }, + ], + 'timeView': [ + { import: '../textEditor/sizes', type: 'index' }, + ], + 'calendar': [ + { import: '../button/colors', type: 'colors' }, + { import: '../button', type: 'index' }, + { import: '../button/colors', type: 'index' }, + ], + 'dateBox': [ + { import: '../../base/icons', type: 'index' }, + { import: '../dropDownEditor', type: 'index' }, + { import: '../textEditor', type: 'index' }, + { import: '../textEditor/colors', type: 'index' }, + { regex: /@mixin dx-icon\(spindown\),/, replacement: '@include dx-icon(spindown);' }, + { regex: /.dx-dropdowneditor-button-icon\(\),/, replacement: '@include dx-dropdowneditor-button-icon();' }, + { regex: /(hover-bg|opacity: 1|padding: 0|: none|_MARGIN|_MARGIN\/2|-1px),/g, replacement: '$1;' }, + { regex: /@mixin dx-icon\(event\),/, replacement: '@include dx-icon(event);' }, + ], + 'dropDownList': [ + { import: '../common', type: 'index' }, + ], + 'autocomplete': [ + { import: '../common', type: 'index' }, + ], + 'treeView': [ + { import: '../../base/treeView', type: 'index' }, + { import: '../../base/icons', type: 'index' }, + { import: '../checkBox/colors', type: 'index' }, + ], + 'overlay': [ + { import: '../common', type: 'index' }, + ], + 'menuBase': [ + { import: '../menu/colors', type: 'index' }, + { import: '../common', type: 'index' }, + { import: '../../base/icons', type: 'index' }, + { import: '../../base/mixins', type: 'index' }, + ], + 'menu': [ + { import: '../menuBase', type: 'index' }, + { import: '../menuBase/sizes', type: 'index' }, + { import: '../../base/icons', type: 'index' }, + ], + 'toolbar': [ + { import: '../../base/icons', type: 'index' }, + { import: '../list/sizes', type: 'index' }, + { import: '../button', type: 'index' }, + { regex: /@mixin dx-toolbar-item-padding\(\$MATERIAL_TOOLBAR_ITEM_SPACING\),/, replacement: '@include dx-toolbar-item-padding($MATERIAL_TOOLBAR_ITEM_SPACING);' }, + { regex: /.dx-toolbar-item-padding\(\$MATERIAL_MOBILE_TOOLBAR_ITEM_SPACING\),/, replacement: '@include dx-toolbar-item-padding($MATERIAL_MOBILE_TOOLBAR_ITEM_SPACING);' }, + { regex: /(-bg|-color|: 0|MATERIAL_LIST_ITEM_HEIGHT|MATERIAL_LIST_ITEM_HORIZONTAL_PADDING|4px|2 0|50%),/g, replacement: '$1;' }, + { regex: /@mixin dx-icon-sizing\(\$MATERIAL_BUTTON_ICON_SIZE\),/, replacement: '@include dx-icon-sizing($MATERIAL_BUTTON_ICON_SIZE);' }, + { regex: /\.dx-button-onlyicon-sizing\(\),/g, replacement: '@include dx-button-onlyicon-sizing();' }, + { regex: /\.dx-icon-margin\(6px\),/, replacement: '@include dx-icon-margin(6px);' }, + ], + 'popup': [ + { import: '../../base/icons', type: 'index' }, + { import: '../overlay/colors', type: 'index' }, + { import: '../toolbar', type: 'index' }, + { import: '../toolbar/sizes', type: 'index' }, + { import: '../button', type: 'index' }, + ], + 'dropDownButton': [ + { import: '../../base/icons', type: 'index' }, + { import: '../button', type: 'index' }, + { import: '../button/sizes', type: 'index' }, + { import: '../common', type: 'index' }, + ], + 'popover': [ + { import: '../overlay/colors', type: 'colors' }, + { import: '../overlay/colors', type: 'index' }, + { import: '../textEditor/colors', type: 'index' }, + ], + 'progressBar': [ + { import: '../../base/mixins', type: 'index' }, + ], + 'tooltip': [ + { import: '../overlay/colors', type: 'colors' }, + ], + 'gallery': [ + { import: '../../base/icons', type: 'index' }, + ], + 'lookup': [ + { import: '../../base/icons', type: 'index' }, + { import: '../textEditor/sizes', type: 'index' }, + { import: '../textEditor/colors', type: 'index' }, + { import: '../dropDownEditor', type: 'index' }, + { import: '../common', type: 'index' }, + { regex: /@mixin dx-icon\(spinnext\),/, replacement: '@include dx-icon(spinnext);' }, + { regex: /\.dx-icon-font-centered-sizing\(\$GENERIC_BASE_ICON_SIZE\),/, replacement: '@include dx-icon-font-centered-sizing($GENERIC_BASE_ICON_SIZE);' }, + { regex: /(GENERIC_BASE_INLINE_BORDEREDWIDGET_INNER_SIZE|lookup-icon-color|none|_CONTENT_PADDING|0|CONTENT_TOP|placeholder-color),/g, replacement: '$1;' }, + ], + 'loadPanel': [ + { import: '../overlay/colors', type: 'colors' }, + ], + 'tagBox': [ + { import: '../../base/icons', type: 'index' }, + { import: '../textEditor', type: 'index' }, + { import: '../common', type: 'index' }, + { regex: /@mixin dx-icon\(clear\),/, replacement: '@include dx-icon(clear);' }, + { regex: /(px|block|absolute|%|-remove-color|-active-color|-bg|none|0 0),/g, replacement: '$1;' }, + ], + 'accordion': [ + { import: '../../base/icons', type: 'index' }, + ], + 'slideOut': [ + { import: '../../base/icons', type: 'index' }, + ], + 'colorView': [ + { import: '../overlay/colors', type: 'colors' }, + { import: '../../base/colorView', type: 'index' }, + ], + 'colorBox': [ + { import: '../colorView/colors', type: 'index' }, + ], +}; diff --git a/build/gulp/scss/tasks.js b/build/gulp/scss/tasks.js new file mode 100644 index 000000000000..9257656f2986 --- /dev/null +++ b/build/gulp/scss/tasks.js @@ -0,0 +1,20 @@ +require('./compiler'); +require('./generator'); + +const gulp = require('gulp'); + +gulp.task('generate-scss', gulp.series( + 'scss-clean', + 'less2sass', + 'fix-bundles', + 'fix-base', + 'fix-common', + 'create-widgets', + 'fix-mixins', + // TODO - create common bundle + 'create-base-widget', + 'create-theme-index', + 'sass-material', + 'sass-generic', + 'scss-raw-scss-clean' +)); diff --git a/build/gulp/style-compiler.js b/build/gulp/style-compiler.js index 1ed73e396b35..a8545b26f8a4 100644 --- a/build/gulp/style-compiler.js +++ b/build/gulp/style-compiler.js @@ -20,6 +20,15 @@ const autoPrefix = new LessAutoPrefix({ browsers: browsersList }); const cssArtifactsPath = path.join(process.cwd(), 'artifacts', 'css'); const commentsRegex = /\s*\/\*[\S\s]*?\*\//g; +const DEFAULT_DEV_BUNDLE_NAMES = [ + 'common', + 'light', + 'material.blue.light', + 'ios7.default' +]; + +const getBundleSourcePath = name => `styles/bundles/dx.${name}.less`; + const compileBundles = (bundles) => { const paths = path.join(process.cwd(), 'styles'); @@ -48,9 +57,15 @@ gulp.task('copy-fonts-and-icons', () => { .pipe(gulp.dest(cssArtifactsPath)); }); -gulp.task('style-compiler-styles', () => compileBundles('styles/bundles/*.less')); +gulp.task('style-compiler-themes', gulp.parallel( + () => compileBundles(getBundleSourcePath('*')), + 'copy-fonts-and-icons' +)); -gulp.task('style-compiler-themes', gulp.parallel('style-compiler-styles', 'copy-fonts-and-icons')); +gulp.task('style-compiler-themes-ci', gulp.parallel( + () => compileBundles(DEFAULT_DEV_BUNDLE_NAMES.map(getBundleSourcePath)), + 'copy-fonts-and-icons' +)); gulp.task('style-compiler-themes-dev', () => { const args = parseArguments(process.argv); @@ -59,13 +74,13 @@ gulp.task('style-compiler-themes-dev', () => { const bundles = ( bundlesArg ? bundlesArg.split(',') - : ['common', 'light', 'material.blue.light']) + : DEFAULT_DEV_BUNDLE_NAMES) .map((bundle) => { - const bundleName = `styles/bundles/dx.${bundle}.less`; - if(fs.existsSync(bundleName)) { - return bundleName; + const sourcePath = getBundleSourcePath(bundle); + if(fs.existsSync(sourcePath)) { + return sourcePath; } - console.log(`${bundleName} file does not exists`); + console.log(`${sourcePath} file does not exists`); return null; }); diff --git a/build/gulp/ts.js b/build/gulp/ts.js index 867254df3a84..6592794d45ee 100644 --- a/build/gulp/ts.js +++ b/build/gulp/ts.js @@ -1,21 +1,17 @@ const gulp = require('gulp'); const file = require('gulp-file'); const footer = require('gulp-footer'); -const fs = require('fs'); const concat = require('gulp-concat'); -const map = require('map-stream'); const path = require('path'); const replace = require('gulp-replace'); const ts = require('gulp-typescript'); - const context = require('./context.js'); const headerPipes = require('./header-pipes.js'); const MODULES = require('./modules_metadata.json'); const PACKAGE_DIR = context.RESULT_NPM_PATH + '/devextreme'; -const DIST_DIR = PACKAGE_DIR + '/dist'; const OUTPUT_ARTIFACTS_DIR = 'artifacts/ts'; -const OUTPUT_PACKAGE_DIR = path.join(PACKAGE_DIR, 'bundles'); +const PACKAGE_BUNDLES_DIR = path.join(PACKAGE_DIR, 'bundles'); const TS_BUNDLE_FILE = './ts/dx.all.d.ts'; const TS_BUNDLE_SOURCES = [TS_BUNDLE_FILE, './ts/aliases.d.ts']; const TS_MODULES_GLOB = './js/**/*.d.ts'; @@ -25,18 +21,27 @@ gulp.task('ts-vendor', function() { .pipe(gulp.dest(OUTPUT_ARTIFACTS_DIR)); }); -gulp.task('ts-bundle', function writeTsBundle() { - return gulp.src(TS_BUNDLE_SOURCES) - .pipe(concat('dx.all.d.ts')) - .pipe(headerPipes.bangLicense()) - .pipe(gulp.dest(OUTPUT_ARTIFACTS_DIR)) // will be copied to the npm's /dist folder by another task - .pipe(replace('/*!', '/**')) - .pipe(replace(/\/\*\s*#StartGlobalDeclaration\s*\*\//g, 'declare global {')) - .pipe(replace(/\/\*\s*#EndGlobalDeclaration\s*\*\//g, '}')) - .pipe(replace(/\/\*\s*#StartJQueryAugmentation\s*\*\/[\s\S]*\/\*\s*#EndJQueryAugmentation\s*\*\//g, '')) - .pipe(footer('\nexport default DevExpress;')) - .pipe(gulp.dest(OUTPUT_PACKAGE_DIR)); -}); +gulp.task('ts-bundle', gulp.series( + + function writeTsBundle() { + return gulp.src(TS_BUNDLE_SOURCES) + .pipe(concat('dx.all.d.ts')) + .pipe(headerPipes.bangLicense()) + .pipe(gulp.dest(OUTPUT_ARTIFACTS_DIR)) // will be copied to the npm's /dist folder by another task + .pipe(replace('/*!', '/**')) + .pipe(replace(/\/\*\s*#StartGlobalDeclaration\s*\*\//g, 'declare global {')) + .pipe(replace(/\/\*\s*#EndGlobalDeclaration\s*\*\//g, '}')) + .pipe(replace(/\/\*\s*#StartJQueryAugmentation\s*\*\/[\s\S]*\/\*\s*#EndJQueryAugmentation\s*\*\//g, '')) + .pipe(footer('\nexport default DevExpress;')) + .pipe(gulp.dest(PACKAGE_BUNDLES_DIR)); + }, + + function writeAngularHack() { + return file('dx.all.js', '// This file is required to compile devextreme-angular', { src: true }) + .pipe(headerPipes.starLicense()) + .pipe(gulp.dest(PACKAGE_BUNDLES_DIR)); + } +)); gulp.task('ts-jquery-check', gulp.series('ts-bundle', function checkJQueryAugmentations() { let content = `/// \n`; @@ -92,24 +97,7 @@ gulp.task('ts-modules', function generateModules() { .pipe(gulp.dest(PACKAGE_DIR)); }); -gulp.task('ts-angular-hack', function() { - return gulp.src([PACKAGE_DIR + '/**/*.d.ts', '!' + DIST_DIR + '/**/*.*']) - .pipe(map(function(file, callback) { - const jsPath = file.path.replace('.d.ts', '.js'); - if(fs.existsSync(jsPath)) { - callback(); - return; - } - - file.path = jsPath; - file.contents = Buffer.from('// This file is required to compile devextreme-angular'); - callback(null, file); - })) - .pipe(headerPipes.starLicense()) - .pipe(gulp.dest(PACKAGE_DIR)); -}); - -gulp.task('ts-sources', gulp.series('ts-modules', 'ts-bundle', 'ts-angular-hack')); +gulp.task('ts-sources', gulp.series('ts-modules', 'ts-bundle')); gulp.task('ts-modules-check', gulp.series('ts-modules', function checkModules() { let content = 'import $ from \'jquery\';\n'; diff --git a/docker-ci.sh b/docker-ci.sh index 38c7c120f26a..c9172737d0a2 100755 --- a/docker-ci.sh +++ b/docker-ci.sh @@ -6,9 +6,12 @@ trap "echo 'Interrupted!' && kill -9 0" TERM INT export DEVEXTREME_DOCKER_CI=true export NUGET_PACKAGES=$PWD/dotnet_packages +export DOTNET_USE_POLLING_FILE_WATCHER=true function run_lint { - npm i eslint eslint-plugin-spellcheck eslint-plugin-qunit eslint-plugin-jest eslint-plugin-react stylelint stylelint-config-standard npm-run-all babel-eslint + npm i npm-run-all \ + eslint eslint-plugin-qunit eslint-plugin-spellcheck babel-eslint eslint-plugin-jest eslint-plugin-react \ + stylelint stylelint-config-standard npm run lint } @@ -46,6 +49,11 @@ function run_test { [ -z "$JQUERY" ] && url="$url&nojquery=true" [ -n "$PERF" ] && url="$url&include=DevExpress.performance&workerInWindow=true" + if [ -n "$TZ" ]; then + ln -sf "/usr/share/zoneinfo/$TZ" /etc/localtime + dpkg-reconfigure --frontend noninteractive tzdata + fi + if [ "$NO_HEADLESS" == "true" ]; then Xvfb :99 -ac -screen 0 1200x600x24 & x11vnc -display :99 2>/dev/null & @@ -56,8 +64,21 @@ function run_test { dotnet ./testing/runner/bin/runner.dll --single-run & runner_pid=$! - while ! httping -qc1 $url; do + for i in {15..0}; do + if [ -n "$runner_pid" ] && [ ! -e "/proc/$runner_pid" ]; then + echo "Runner exited unexpectedly" + exit 1 + fi + + httping -qsc1 "$url" && break + + if [ $i -eq 0 ]; then + echo "Runner not reached" + exit 1 + fi + sleep 1 + echo "Waiting for runner..." done echo "URL: $url" @@ -73,34 +94,40 @@ function run_test { ;; *) - local chrome_command="google-chrome-stable \ - --no-sandbox \ - --disable-dev-shm-usage \ - --disable-gpu \ - --disable-extensions \ - --user-data-dir=/tmp/chrome"; + local chrome_command=google-chrome-stable + local chrome_args=( + --no-sandbox + --disable-dev-shm-usage + --disable-gpu + --disable-extensions + --user-data-dir=/tmp/chrome + ) if [ "$NO_HEADLESS" != "true" ]; then echo "Headless mode" - chrome_command="$chrome_command \ - --headless \ - --remote-debugging-address=0.0.0.0 \ - --remote-debugging-port=9222"; + chrome_args+=( + --headless + --remote-debugging-address=0.0.0.0 + --remote-debugging-port=9222 + ) else - chrome_command="dbus-launch --exit-with-session $chrome_command \ - --no-first-run \ - --no-default-browser-check \ - --disable-translate"; + chrome_command="dbus-launch --exit-with-session $chrome_command" + chrome_args+=( + --no-first-run + --no-default-browser-check + --disable-translate + ) fi if [ "$PERF" == "true" ]; then echo "Performance tests" - chrome_command="$chrome_command \ - --disable-popup-blocking \ - --remote-debugging-port=9223 \ - --enable-impl-side-painting \ - --enable-skia-benchmarking \ - --disable-web-security" + chrome_args+=( + --disable-popup-blocking + --remote-debugging-port=9223 + --enable-impl-side-painting + --enable-skia-benchmarking + --disable-web-security + ) fi if [ -n "$MOBILE_UA" ]; then @@ -112,29 +139,29 @@ function run_test { exit 1 fi - echo "User agent: $user_agent" + echo "Mobile user agent: $MOBILE_UA" - chrome_command="$chrome_command \ - --user-agent=\"$user_agent\" \ - --enable-viewport \ - --touch-events \ - --enable-overlay-scrollbar \ - --enable-features=OverlayScrollbar" - else - chrome_command="$chrome_command --user-data-dir=/tmp/chrome" + chrome_args+=( + --user-agent="'$user_agent'" + --enable-viewport + --touch-events + --enable-overlay-scrollbar + --enable-features=OverlayScrollbar + ) fi - chrome_command="$chrome_command \"$url\"" - echo "Chrome cmd: $chrome_command" + tput setaf 6 + echo "$chrome_command" + printf ' %s\n' "${chrome_args[@]}" + tput setaf 9 google-chrome-stable --version - - eval "$chrome_command" &>chrome.log & - + eval "$chrome_command ${chrome_args[@]} '$url'" &>chrome.log & ;; esac + start_runner_watchdog $runner_pid wait $runner_pid || runner_result=1 exit $runner_result } @@ -155,8 +182,9 @@ function run_test_functional { npm i npm run build - local args="--browsers chrome:headless"; - [ "$COMPONENT" ] && args="$args --componentFolder $COMPONENT"; + local args="--browsers=chrome:headless"; + [ -n "$COMPONENT" ] && args="$args --componentFolder=$COMPONENT"; + [ -n "$QUARANTINE_MODE" ] && args="$args --quarantineMode=true"; npm run test-functional -- $args } @@ -170,18 +198,34 @@ function run_test_jest { npm run test-jest } +function run_test_scss { + npm i + npx gulp generate-scss +} + +function start_runner_watchdog { + local last_suite_time_file="$PWD/testing/LastSuiteTime.txt" + local last_suite_time=unknown + + while true; do + sleep 300 + + if [ ! -f $last_suite_time_file ] || [ $(cat $last_suite_time_file) == $last_suite_time ]; then + echo "Runner stalled" + kill -9 $1 + else + last_suite_time=$(cat $last_suite_time_file) + fi + done & +} + echo "node $(node -v), npm $(npm -v), dotnet $(dotnet --version)" -case "$TARGET" in - "lint") run_lint ;; - "ts") run_ts ;; - "test") run_test ;; - "test_themebuilder") run_test_themebuilder ;; - "test_functional") run_test_functional ;; - "test_jest") run_test_jest ;; +TARGET_FUNC="run_$TARGET" - *) - echo "Unknown target" - exit 1 - ;; -esac +if [ $(type -t $TARGET_FUNC) != "function" ]; then + echo "Unknown target" + exit 1 +fi + +$TARGET_FUNC diff --git a/drone-cache-clean.sh b/drone-cache-clean.sh new file mode 100644 index 000000000000..12438c53fed3 --- /dev/null +++ b/drone-cache-clean.sh @@ -0,0 +1,5 @@ +find dotnet_packages -type f -name '*.nupkg' -delete +find dotnet_packages -type f -name '*.xml' -delete +find dotnet_packages -type f -name '*.pdb' -delete +find dotnet_packages -type f -wholename '**/lib/net[2-4]*/**' -delete +find dotnet_packages -type f -wholename '**/lib/portable-net*/**' -delete diff --git a/drone-cache.sh b/drone-cache.sh index 8979c0ca626b..94d1fdea87ee 100755 --- a/drone-cache.sh +++ b/drone-cache.sh @@ -12,6 +12,8 @@ if [ "$1" == "rebuild" ]; then exit 0 fi + source drone-cache-clean.sh + for i in $CACHE_DIRS; do if [ -e $i ]; then if tar cf - $i | lz4 | curl -Lsf -X PUT -H "x-amz-acl: bucket-owner-full-control" --data-binary @- "$CACHE_URL/$i.tar.lz4"; then diff --git a/gulpfile.js b/gulpfile.js index 5457a03cbca1..47b947859072 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -22,6 +22,7 @@ require('./build/gulp/ts'); require('./build/gulp/localization'); require('./build/gulp/style-compiler'); require('./build/gulp/generator'); +require('./build/gulp/scss/tasks'); const TEST_CI = Boolean(process.env['DEVEXTREME_TEST_CI']); const DOCKER_CI = Boolean(process.env['DEVEXTREME_DOCKER_CI']); @@ -31,11 +32,10 @@ if(TEST_CI) { } function createStyleCompilerBatch() { - const tasks = ['style-compiler-themes']; - if(!TEST_CI) { - tasks.push('style-compiler-tb-assets'); - } - return gulp.series(tasks); + return gulp.series(TEST_CI + ? ['style-compiler-themes-ci'] + : ['style-compiler-themes', 'style-compiler-tb-assets'] + ); } function createMiscBatch() { diff --git a/images/widgets/common/diagram/toolbox-drag.svg b/images/widgets/common/diagram/toolbox-drag.svg new file mode 100644 index 000000000000..c7e3113b1747 --- /dev/null +++ b/images/widgets/common/diagram/toolbox-drag.svg @@ -0,0 +1,12 @@ + + + + + + + + + diff --git a/images/widgets/material/color-schemes/dark/list/delete.png b/images/widgets/material/color-schemes/dark/list/delete.png index b5a436e995624733f5699afd765fcafcb0f3d4f6..005a842a6d2237ca4fee7cc6b00cffbb9750b3fc 100644 GIT binary patch literal 452 zcmV;#0XzPQP)ot#SNj;+aG>slABLX zG7p(BXJ(Eimfl!KK!(I2Afu$BrlF;!p{AlFBfuFl$57BFqTq~t$eDr&dp_ura{Nd= z=17V=2aGuk#=0Dcr-42>_tBgn+{y9Bf+43#SeFyw7%<^7ixY$k$xv|1Z8j$eH?~8- zWFhXCOum8P0*k3GZ1@TEXZ|X$e;@xnm@m!=LjDenC+@rN`!aq7x)Z9(@ap6K1=H0y zK}erLdqjzzk|VYXMyqmy5UF6XI#@h{&X?nLiJWnIFj$=vgrEmAEnwDzr53R4!Rl$K zVULG3BOZI2r&+5Wtd)T)n^{%mqT@D>9-W!}~xsC`Mb z|1{dSh4ziFy|igB-rA2R?FX=dD~9$mwQ5SaZH=L#L!eLyI%;-!#b&r> zgl}f}Z*P(GY!0uvDauNn8}N1l!hwk(CNWXO1m?hXdnMo$?J+^8A?%b*R`;y8<>xTZ zLVzUcYF}gNh|yUHki-hHs|9@tr2j%>@W~_G9^|jKO1uZ@36N2`p5ci=PPll6gs)Ta zq#xvU`U$E1QU(dqNJJU#NMkB#;3lmOq$P;7&XE>V(uz%cEFeC6-1e~-=Q2AsAV>|t P00000NkvXXu0mjfb`f!^ diff --git a/js/aspnet.js b/js/aspnet.js index 56668cbfb93b..af38944085cb 100644 --- a/js/aspnet.js +++ b/js/aspnet.js @@ -12,7 +12,8 @@ require('./core/utils/iterator'), require('./core/utils/dom').extractTemplateMarkup, require('./core/utils/string').encodeHtml, - require('./core/utils/ajax') + require('./core/utils/ajax'), + require('./core/utils/console') ); }); } else { @@ -25,13 +26,15 @@ DevExpress.utils.iterator, DevExpress.utils.dom.extractTemplateMarkup, DevExpress.utils.string.encodeHtml, - DevExpress.utils.ajax + DevExpress.utils.ajax, + DevExpress.utils.console ); } -})(function($, setTemplateEngine, templateRendered, Guid, validationEngine, iteratorUtils, extractTemplateMarkup, encodeHtml, ajax) { +})(function($, setTemplateEngine, templateRendered, Guid, validationEngine, iteratorUtils, extractTemplateMarkup, encodeHtml, ajax, console) { var templateCompiler = createTemplateCompiler(); var pendingCreateComponentRoutines = [ ]; var enableAlternateTemplateTags = true; + var warnBug17028 = false; function createTemplateCompiler() { var OPEN_TAG = '<%', @@ -66,6 +69,13 @@ var bag = ['var _ = [];', 'with(obj||{}) {'], chunks = text.split(enableAlternateTemplateTags ? EXTENDED_OPEN_TAG : OPEN_TAG); + if(warnBug17028 && chunks.length > 1) { + if(text.indexOf(OPEN_TAG) > -1) { + console.logger.warn('Please use an alternative template syntax: https://community.devexpress.com/blogs/aspnet/archive/2020/01/29/asp-net-core-new-syntax-to-fix-razor-issue.aspx'); + warnBug17028 = false; + } + } + acceptText(bag, chunks.shift()); for(var i = 0; i < chunks.length; i++) { @@ -177,6 +187,10 @@ enableAlternateTemplateTags = value; }, + warnBug17028: function() { + warnBug17028 = true; + }, + createValidationSummaryItems: function(validationGroup, editorNames) { var summary = getValidationSummary(validationGroup), groupConfig, diff --git a/js/bundles/modules/core.js b/js/bundles/modules/core.js index 378f0311a15e..285a24f06bd8 100644 --- a/js/bundles/modules/core.js +++ b/js/bundles/modules/core.js @@ -11,7 +11,7 @@ if(DevExpress._DEVEXTREME_BUNDLE_INITIALIZED) { DevExpress._DEVEXTREME_BUNDLE_INITIALIZED = true; DevExpress.clientExporter = require('../../exporter'); -DevExpress.excelExporter = require('../../exporter/exceljs/excelExporter'); +DevExpress.excelExporter = require('../../excel_exporter'); DevExpress.VERSION = require('../../core/version'); diff --git a/js/bundles/modules/data.js b/js/bundles/modules/data.js index cc96eda4fb2c..c2a4800d0f84 100644 --- a/js/bundles/modules/data.js +++ b/js/bundles/modules/data.js @@ -56,4 +56,4 @@ DevExpress.data.utils.toComparable = require('../../core/utils/data').toComparab DevExpress.data.utils.multiLevelGroup = require('../../data/store_helper').multiLevelGroup; DevExpress.data.utils.arrangeSortingInfo = require('../../data/store_helper').arrangeSortingInfo; -DevExpress.data.utils.normalizeDataSourceOptions = require('../../data/data_source/data_source').normalizeDataSourceOptions; +DevExpress.data.utils.normalizeDataSourceOptions = require('../../data/data_source/utils').normalizeDataSourceOptions; diff --git a/js/bundles/modules/file_management.js b/js/bundles/modules/file_management.js new file mode 100644 index 000000000000..9702fc67a69f --- /dev/null +++ b/js/bundles/modules/file_management.js @@ -0,0 +1,12 @@ +import DevExpress from './core'; +import FileSystemItem from '../../file_management/file_system_item'; +import ObjectFileSystemProvider from '../../file_management/object_provider'; +import RemoteFileSystemProvider from '../../file_management/remote_provider'; +import CustomFileSystemProvider from '../../file_management/custom_provider'; + +module.exports = DevExpress.fileManagement = DevExpress.fileManagement || {}; + +DevExpress.fileManagement.FileSystemItem = FileSystemItem; +DevExpress.fileManagement.ObjectFileSystemProvider = ObjectFileSystemProvider; +DevExpress.fileManagement.RemoteFileSystemProvider = RemoteFileSystemProvider; +DevExpress.fileManagement.CustomFileSystemProvider = CustomFileSystemProvider; diff --git a/js/bundles/modules/file_providers.js b/js/bundles/modules/file_providers.js deleted file mode 100644 index 74b250bfed5a..000000000000 --- a/js/bundles/modules/file_providers.js +++ /dev/null @@ -1,8 +0,0 @@ -import DevExpress from './core'; -import RemoteFileProvider from '../../ui/file_manager/file_provider/remote'; -import CustomFileProvider from '../../ui/file_manager/file_provider/custom'; - -module.exports = DevExpress.fileProviders = DevExpress.fileProviders || {}; - -DevExpress.fileProviders.Remote = RemoteFileProvider; -DevExpress.fileProviders.Custom = CustomFileProvider; diff --git a/js/bundles/modules/parts/file_management.js b/js/bundles/modules/parts/file_management.js new file mode 100644 index 000000000000..a6f566bded92 --- /dev/null +++ b/js/bundles/modules/parts/file_management.js @@ -0,0 +1,11 @@ +import DevExpress from './core'; + +/// BUNDLER_PARTS +/* fileManagement (dx.module-core.js) */ + +import fileManagement from '../../../bundles/modules/file_management'; +DevExpress.fileManagement = fileManagement; + +/// BUNDLER_PARTS_END + +module.exports = fileManagement; diff --git a/js/bundles/modules/parts/file_providers.js b/js/bundles/modules/parts/file_providers.js deleted file mode 100644 index 965a078bcd07..000000000000 --- a/js/bundles/modules/parts/file_providers.js +++ /dev/null @@ -1,11 +0,0 @@ -import DevExpress from './core'; - -/// BUNDLER_PARTS -/* fileProviders (dx.module-core.js) */ - -import fileProviders from '../../../bundles/modules/file_providers'; -DevExpress.fileProviders = fileProviders; - -/// BUNDLER_PARTS_END - -module.exports = fileProviders; diff --git a/js/bundles/modules/parts/widgets-base.js b/js/bundles/modules/parts/widgets-base.js index 8ee2e52f1971..c63dc08d5019 100644 --- a/js/bundles/modules/parts/widgets-base.js +++ b/js/bundles/modules/parts/widgets-base.js @@ -1,6 +1,6 @@ const DevExpress = require('./core'); require('./data'); -require('./file_providers'); +require('./file_management'); /// BUNDLER_PARTS /* UI core (dx.module-core.js) */ diff --git a/js/core/utils/position.js b/js/core/utils/position.js index c6a1f6546b6e..d8390828775b 100644 --- a/js/core/utils/position.js +++ b/js/core/utils/position.js @@ -1,7 +1,7 @@ -const config = require('../config'); +import config from '../config'; const getDefaultAlignment = function(isRtlEnabled) { - const rtlEnabled = isRtlEnabled || config().rtlEnabled; + const rtlEnabled = isRtlEnabled ?? config().rtlEnabled; return rtlEnabled ? 'right' : 'left'; }; diff --git a/js/core/utils/window.js b/js/core/utils/window.js index 266e4ad9a0dc..b1f662ac9fad 100644 --- a/js/core/utils/window.js +++ b/js/core/utils/window.js @@ -2,20 +2,18 @@ const domAdapter = require('../dom_adapter'); -const hasWindow = typeof window !== 'undefined'; +const hasWindow = () => typeof window !== 'undefined'; -let windowObject = hasWindow && window; +let windowObject = hasWindow() && window; if(!windowObject) { windowObject = {}; windowObject.window = windowObject; } -const hasWindowFn = () => hasWindow; - const getWindow = () => windowObject; -const hasProperty = (prop) => hasWindowFn() && prop in windowObject; +const hasProperty = (prop) => hasWindow() && prop in windowObject; const defaultScreenFactorFunc = (width) => { if(width < 768) { @@ -36,10 +34,10 @@ const getCurrentScreenFactor = (screenFactorCallback) => { return screenFactorFunc(windowWidth); }; -const getNavigator = () => hasWindowFn() ? windowObject.navigator : { userAgent: '' }; +const getNavigator = () => hasWindow() ? windowObject.navigator : { userAgent: '' }; module.exports = { - hasWindow: hasWindowFn, + hasWindow, getWindow, hasProperty, defaultScreenFactorFunc, diff --git a/js/data/data_source/data_source.js b/js/data/data_source/data_source.js index e7de6461f2a6..e618b2acdd26 100644 --- a/js/data/data_source/data_source.js +++ b/js/data/data_source/data_source.js @@ -1,194 +1,27 @@ -const Class = require('../../core/class'); -const extend = require('../../core/utils/extend').extend; -const commonUtils = require('../../core/utils/common'); -const iteratorUtils = require('../../core/utils/iterator'); -const ajax = require('../../core/utils/ajax'); -const typeUtils = require('../../core/utils/type'); -const dataUtils = require('../utils'); -const arrayUtils = require('../array_utils'); -const Store = require('../abstract_store'); -const ArrayStore = require('../array_store'); -const CustomStore = require('../custom_store'); -const EventsStrategy = require('../../core/events_strategy').EventsStrategy; -const errors = require('../errors').errors; -const array = require('../../core/utils/array'); -const queue = require('../../core/utils/queue'); -const deferredUtils = require('../../core/utils/deferred'); -const when = deferredUtils.when; -const Deferred = deferredUtils.Deferred; - -const __isString = typeUtils.isString; -const __isNumber = typeUtils.isNumeric; -const __isBoolean = typeUtils.isBoolean; -const __isDefined = typeUtils.isDefined; - -const CANCELED_TOKEN = 'canceled'; - -function OperationManager() { - this._counter = -1; - this._deferreds = {}; -} - -OperationManager.prototype.constructor = OperationManager; -OperationManager.prototype.add = function(deferred) { - this._counter += 1; - this._deferreds[this._counter] = deferred; - return this._counter; -}; -OperationManager.prototype.remove = function(operationId) { - return delete this._deferreds[operationId]; -}; -OperationManager.prototype.cancel = function(operationId) { - if(operationId in this._deferreds) { - this._deferreds[operationId].reject(CANCELED_TOKEN); - return true; - } - - return false; -}; -OperationManager.prototype.cancelAll = function() { - while(this._counter > -1) { - this.cancel(this._counter); - this._counter--; - } -}; - -function isPending(deferred) { - return deferred.state() === 'pending'; -} - -function normalizeDataSourceOptions(options, normalizationOptions) { - let store; - - function createCustomStoreFromLoadFunc() { - const storeConfig = {}; - - iteratorUtils.each(['useDefaultSearch', 'key', 'load', 'loadMode', 'cacheRawData', 'byKey', 'lookup', 'totalCount', 'insert', 'update', 'remove'], function() { - storeConfig[this] = options[this]; - delete options[this]; - }); - - return new CustomStore(storeConfig); - } - - function createStoreFromConfig(storeConfig) { - const alias = storeConfig.type; - - delete storeConfig.type; - - return Store.create(alias, storeConfig); - } - - function createCustomStoreFromUrl(url) { - return new CustomStore({ - load: function() { - return ajax.sendRequest({ - url: url, - dataType: 'json' - }); - }, - loadMode: normalizationOptions && normalizationOptions.fromUrlLoadMode - }); - } - - if(typeof options === 'string') { - options = { - paginate: false, - store: createCustomStoreFromUrl(options) - }; - } - - if(options === undefined) { - options = []; - } - - if(Array.isArray(options) || options instanceof Store) { - options = { store: options }; - } else { - options = extend({}, options); - } - - if(options.store === undefined) { - options.store = []; - } - - store = options.store; - - if('load' in options) { - store = createCustomStoreFromLoadFunc(); - } else if(Array.isArray(store)) { - store = new ArrayStore(store); - } else if(typeUtils.isPlainObject(store)) { - store = createStoreFromConfig(extend({}, store)); - } - - options.store = store; - - return options; -} - - -function normalizeStoreLoadOptionAccessorArguments(originalArguments) { - switch(originalArguments.length) { - case 0: - return undefined; - case 1: - return originalArguments[0]; - } - return [].slice.call(originalArguments); -} - -function generateStoreLoadOptionAccessor(optionName) { - return function() { - const args = normalizeStoreLoadOptionAccessorArguments(arguments); - if(args === undefined) { - return this._storeLoadOptions[optionName]; - } - - this._storeLoadOptions[optionName] = args; - }; -} - -function mapDataRespectingGrouping(items, mapper, groupInfo) { - - function mapRecursive(items, level) { - if(!Array.isArray(items)) return items; - return level ? mapGroup(items, level) : iteratorUtils.map(items, mapper); - } - - function mapGroup(group, level) { - return iteratorUtils.map(group, function(item) { - const result = { - key: item.key, - items: mapRecursive(item.items, level - 1) - }; - if('aggregates' in item) { - result.aggregates = item.aggregates; - } - return result; - }); - } - - return mapRecursive(items, groupInfo ? dataUtils.normalizeSortingInfo(groupInfo).length : 0); -} - -function normalizeLoadResult(data, extra) { - if(data && !Array.isArray(data) && data.data) { - extra = data; - data = data.data; - } - - if(!Array.isArray(data)) { - data = [data]; - } - - return { - data, - extra - }; -} - -const DataSource = Class.inherit({ +import Class from '../../core/class'; +import { extend } from '../../core/utils/extend'; +import commonUtils from '../../core/utils/common'; +import { each } from '../../core/utils/iterator'; +import { isString, isNumeric, isBoolean, isDefined, isPlainObject } from '../../core/utils/type'; +import { throttleChanges } from '../utils'; +import arrayUtils from '../array_utils'; +import CustomStore from '../custom_store'; +import { EventsStrategy } from '../../core/events_strategy'; +import { errors } from '../errors'; +import array from '../../core/utils/array'; +import queue from '../../core/utils/queue'; +import { Deferred, when } from '../../core/utils/deferred'; +import OperationManager from './operation_manager'; +import { + normalizeDataSourceOptions, + normalizeStoreLoadOptionAccessorArguments, + CANCELED_TOKEN, + isPending, + normalizeLoadResult, + mapDataRespectingGrouping +} from './utils'; + +export const DataSource = Class.inherit({ /** * @name DataSourceMethods.ctor * @publicName ctor(url) @@ -213,8 +46,7 @@ const DataSource = Class.inherit({ * @param1 options:CustomStoreOptions|DataSourceOptions * @hidden */ - ctor: function(options) { - const that = this; + ctor(options) { options = normalizeDataSourceOptions(options); this._eventsStrategy = new EventsStrategy(this); @@ -224,12 +56,11 @@ const DataSource = Class.inherit({ */ const onPushHandler = options.pushAggregationTimeout !== 0 - ? dataUtils.throttleChanges(this._onPush, function() { - if(options.pushAggregationTimeout === undefined) { - return that._changedTime * 5; - } - return options.pushAggregationTimeout; - }) + ? throttleChanges(this._onPush, () => + options.pushAggregationTimeout === undefined + ? this._changedTime * 5 + : options.pushAggregationTimeout + ) : this._onPush; this._changedTime = 0; @@ -263,9 +94,9 @@ const DataSource = Class.inherit({ this._paginate = options.paginate; - this._reshapeOnPush = __isDefined(options.reshapeOnPush) ? options.reshapeOnPush : false; + this._reshapeOnPush = options.reshapeOnPush ?? false; - iteratorUtils.each( + each( [ 'onChanged', @@ -276,9 +107,9 @@ const DataSource = Class.inherit({ 'onCustomizeLoadResult', 'onCustomizeStoreLoadOptions' ], - function(_, optionName) { + (_, optionName) => { if(optionName in options) { - that.on(optionName.substr(2, 1).toLowerCase() + optionName.substr(3), options[optionName]); + this.on(optionName.substr(2, 1).toLowerCase() + optionName.substr(3), options[optionName]); } }); @@ -286,36 +117,34 @@ const DataSource = Class.inherit({ this._init(); }, - _init: function() { + _init() { this._items = []; this._userData = {}; this._totalCount = -1; this._isLoaded = false; - if(!__isDefined(this._paginate)) { + if(!isDefined(this._paginate)) { this._paginate = !this.group(); } this._isLastPage = !this._paginate; }, - dispose: function() { + dispose() { this._store.off('push', this._onPushHandler); this._eventsStrategy.dispose(); clearTimeout(this._aggregationTimeoutId); delete this._store; - if(this._delayedLoadTask) { - this._delayedLoadTask.abort(); - } + this._delayedLoadTask?.abort(); this._operationManager.cancelAll(); this._disposed = true; }, - _extractLoadOptions: function(options) { + _extractLoadOptions(options) { const result = {}; let names = ['sort', 'filter', 'select', 'group', 'requireTotalCount']; const customNames = this._store._customLoadOptions(); @@ -324,22 +153,22 @@ const DataSource = Class.inherit({ names = names.concat(customNames); } - iteratorUtils.each(names, function() { + each(names, function() { result[this] = options[this]; }); return result; }, - loadOptions: function() { + loadOptions() { return this._storeLoadOptions; }, - items: function() { + items() { return this._items; }, - pageIndex: function(newIndex) { - if(!__isNumber(newIndex)) { + pageIndex(newIndex) { + if(!isNumeric(newIndex)) { return this._pageIndex; } @@ -347,8 +176,8 @@ const DataSource = Class.inherit({ this._isLastPage = !this._paginate; }, - paginate: function(value) { - if(!__isBoolean(value)) { + paginate(value) { + if(!isBoolean(value)) { return this._paginate; } @@ -358,21 +187,34 @@ const DataSource = Class.inherit({ } }, - pageSize: function(value) { - if(!__isNumber(value)) { + pageSize(value) { + if(!isNumeric(value)) { return this._pageSize; } this._pageSize = value; }, - isLastPage: function() { + isLastPage() { return this._isLastPage; }, - sort: generateStoreLoadOptionAccessor('sort'), + generateStoreLoadOptionAccessor(optionName) { + return (args) => { + const normalizedArgs = normalizeStoreLoadOptionAccessorArguments(args); + if(normalizedArgs === undefined) { + return this._storeLoadOptions[optionName]; + } + + this._storeLoadOptions[optionName] = normalizedArgs; + }; + }, - filter: function() { + sort(...args) { + return this.generateStoreLoadOptionAccessor('sort')(args); + }, + + filter() { const newFilter = normalizeStoreLoadOptionAccessorArguments(arguments); if(newFilter === undefined) { return this._storeLoadOptions.filter; @@ -382,19 +224,23 @@ const DataSource = Class.inherit({ this.pageIndex(0); }, - group: generateStoreLoadOptionAccessor('group'), + group(...args) { + return this.generateStoreLoadOptionAccessor('group')(args); + }, - select: generateStoreLoadOptionAccessor('select'), + select(...args) { + return this.generateStoreLoadOptionAccessor('select')(args); + }, - requireTotalCount: function(value) { - if(!__isBoolean(value)) { + requireTotalCount(value) { + if(!isBoolean(value)) { return this._storeLoadOptions.requireTotalCount; } this._storeLoadOptions.requireTotalCount = value; }, - searchValue: function(value) { + searchValue(value) { if(arguments.length < 1) { return this._searchValue; } @@ -403,8 +249,8 @@ const DataSource = Class.inherit({ this.pageIndex(0); }, - searchOperation: function(op) { - if(!__isString(op)) { + searchOperation(op) { + if(!isString(op)) { return this._searchOperation; } @@ -412,7 +258,7 @@ const DataSource = Class.inherit({ this.pageIndex(0); }, - searchExpr: function(expr) { + searchExpr(expr) { const argc = arguments.length; if(argc === 0) { @@ -427,39 +273,39 @@ const DataSource = Class.inherit({ this.pageIndex(0); }, - store: function() { + store() { return this._store; }, - key: function() { - return this._store && this._store.key(); + key() { + return this._store?.key(); }, - totalCount: function() { + totalCount() { return this._totalCount; }, - isLoaded: function() { + isLoaded() { return this._isLoaded; }, - isLoading: function() { + isLoading() { return this._loadingCount > 0; }, - beginLoading: function() { + beginLoading() { this._changeLoadingCount(1); }, - endLoading: function() { + endLoading() { this._changeLoadingCount(-1); }, - _createLoadQueue: function() { + _createLoadQueue() { return queue.create(); }, - _changeLoadingCount: function(increment) { + _changeLoadingCount(increment) { const oldLoading = this.isLoading(); this._loadingCount += increment; @@ -470,55 +316,47 @@ const DataSource = Class.inherit({ } }, - _scheduleLoadCallbacks: function(deferred) { - const that = this; - - that.beginLoading(); + _scheduleLoadCallbacks(deferred) { + this.beginLoading(); - deferred.always(function() { - that.endLoading(); + deferred.always(() => { + this.endLoading(); }); }, - _scheduleFailCallbacks: function(deferred) { - const that = this; - - deferred.fail(function() { - if(arguments[0] === CANCELED_TOKEN) { + _scheduleFailCallbacks(deferred) { + deferred.fail((...args) => { + if(args[0] === CANCELED_TOKEN) { return; } - that._eventsStrategy.fireEvent('loadError', arguments); + this._eventsStrategy.fireEvent('loadError', args); }); }, - _fireChanged: function(args) { + _fireChanged(args) { const date = new Date(); this._eventsStrategy.fireEvent('changed', args); this._changedTime = new Date() - date; }, - _scheduleChangedCallbacks: function(deferred) { - deferred.done(() => { - this._fireChanged(); - }); + _scheduleChangedCallbacks(deferred) { + deferred.done(() => this._fireChanged()); }, - loadSingle: function(propName, propValue) { - const that = this; - + loadSingle(propName, propValue) { const d = new Deferred(); const key = this.key(); const store = this._store; const options = this._createStoreLoadOptions(); - const handleDone = function(data) { - if(!__isDefined(data) || array.isEmpty(data)) { + const handleDone = (data) => { + if(!isDefined(data) || array.isEmpty(data)) { d.reject(new errors.Error('E4009')); } else { if(!Array.isArray(data)) { data = [data]; } - d.resolve(that._applyMapFunction(data)[0]); + d.resolve(this._applyMapFunction(data)[0]); } }; @@ -535,11 +373,9 @@ const DataSource = Class.inherit({ delete options.pageIndex; delete options.searchString; - function shouldForceByKey() { - return (store instanceof CustomStore) && !store._byKeyViaLoad(); - } + const shouldForceByKey = () => (store instanceof CustomStore) && !store._byKeyViaLoad(); - (function() { + (() => { // NOTE for CustomStore always using byKey for backward compatibility with "old user datasource" if(propName === key || shouldForceByKey()) { @@ -558,12 +394,11 @@ const DataSource = Class.inherit({ return d.promise(); }, - load: function() { - const that = this; + load() { const d = new Deferred(); - function loadTask() { - if(that._disposed) { + const loadTask = () => { + if(this._disposed) { return undefined; } @@ -571,8 +406,8 @@ const DataSource = Class.inherit({ return; } - return that._loadFromStore(loadOperation, d); - } + return this._loadFromStore(loadOperation, d); + }; this._scheduleLoadCallbacks(d); this._scheduleFailCallbacks(d); @@ -582,9 +417,9 @@ const DataSource = Class.inherit({ this._eventsStrategy.fireEvent('customizeStoreLoadOptions', [loadOperation]); - this._loadQueue.add(function() { + this._loadQueue.add(() => { if(typeof loadOperation.delay === 'number') { - that._delayedLoadTask = commonUtils.executeAsync(loadTask, loadOperation.delay); + this._delayedLoadTask = commonUtils.executeAsync(loadTask, loadOperation.delay); } else { loadTask(); } @@ -596,11 +431,11 @@ const DataSource = Class.inherit({ }); }, - _onPush: function(changes) { + _onPush(changes) { if(this._reshapeOnPush) { this.load(); } else { - this._eventsStrategy.fireEvent('changing', [{ changes: changes }]); + this._eventsStrategy.fireEvent('changing', [{ changes }]); const group = this.group(); const items = this.items(); @@ -624,21 +459,19 @@ const DataSource = Class.inherit({ } }, - _createLoadOperation: function(deferred) { - const id = this._operationManager.add(deferred); - const options = this._createStoreLoadOptions(); + _createLoadOperation(deferred) { + const operationId = this._operationManager.add(deferred); + const storeLoadOptions = this._createStoreLoadOptions(); - deferred.always(function() { - this._operationManager.remove(id); - }.bind(this)); + deferred.always(() => this._operationManager.remove(operationId)); return { - operationId: id, - storeLoadOptions: options + operationId, + storeLoadOptions }; }, - reload: function() { + reload() { const store = this.store(); if(store instanceof CustomStore) { store.clearRawDataCache(); @@ -648,15 +481,15 @@ const DataSource = Class.inherit({ return this.load(); }, - cancel: function(operationId) { + cancel(operationId) { return this._operationManager.cancel(operationId); }, - cancelAll: function() { + cancelAll() { return this._operationManager.cancelAll(); }, - _addSearchOptions: function(storeLoadOptions) { + _addSearchOptions(storeLoadOptions) { if(this._disposed) { return; } @@ -670,7 +503,7 @@ const DataSource = Class.inherit({ } }, - _createStoreLoadOptions: function() { + _createStoreLoadOptions() { const result = extend({}, this._storeLoadOptions); this._addSearchOptions(result); @@ -686,7 +519,7 @@ const DataSource = Class.inherit({ return result; }, - _addSearchFilter: function(storeLoadOptions) { + _addSearchFilter(storeLoadOptions) { const value = this._searchValue; const op = this._searchOperation; let selector = this._searchExpr; @@ -706,7 +539,7 @@ const DataSource = Class.inherit({ // TODO optimize for byKey case - iteratorUtils.each(selector, function(i, item) { + each(selector, function(i, item) { if(searchFilter.length) { searchFilter.push('or'); } @@ -721,21 +554,9 @@ const DataSource = Class.inherit({ } }, - _loadFromStore: function(loadOptions, pendingDeferred) { - const that = this; - - function handleSuccess(data, extra) { - function processResult() { - const loadResult = extend(normalizeLoadResult(data, extra), loadOptions); - - that._eventsStrategy.fireEvent('customizeLoadResult', [loadResult]); - when(loadResult.data).done(function(data) { - loadResult.data = data; - that._processStoreLoadResult(loadResult, pendingDeferred); - }).fail(pendingDeferred.reject); - } - - if(that._disposed) { + _loadFromStore(loadOptions, pendingDeferred) { + const handleSuccess = (data, extra) => { + if(this._disposed) { return; } @@ -743,8 +564,15 @@ const DataSource = Class.inherit({ return; } - processResult(); - } + // Process result + const loadResult = extend(normalizeLoadResult(data, extra), loadOptions); + + this._eventsStrategy.fireEvent('customizeLoadResult', [loadResult]); + when(loadResult.data).done((data) => { + loadResult.data = data; + this._processStoreLoadResult(loadResult, pendingDeferred); + }).fail(pendingDeferred.reject); + }; if(loadOptions.data) { return new Deferred().resolve(loadOptions.data).done(handleSuccess); @@ -755,44 +583,42 @@ const DataSource = Class.inherit({ .fail(pendingDeferred.reject); }, - _processStoreLoadResult: function(loadResult, pendingDeferred) { - const that = this; + _processStoreLoadResult(loadResult, pendingDeferred) { let data = loadResult.data; let extra = loadResult.extra; const storeLoadOptions = loadResult.storeLoadOptions; - function resolvePendingDeferred() { - that._isLoaded = true; - that._totalCount = isFinite(extra.totalCount) ? extra.totalCount : -1; + const resolvePendingDeferred = () => { + this._isLoaded = true; + this._totalCount = isFinite(extra.totalCount) ? extra.totalCount : -1; return pendingDeferred.resolve(data, extra); - } - - function proceedLoadingTotalCount() { + }; - that.store().totalCount(storeLoadOptions) + const proceedLoadingTotalCount = () => { + this.store().totalCount(storeLoadOptions) .done(function(count) { extra.totalCount = count; resolvePendingDeferred(); }) .fail(pendingDeferred.reject); - } + }; - if(that._disposed) { + if(this._disposed) { return; } // todo: if operation is canceled there is no need to do data transformation - data = that._applyPostProcessFunction(that._applyMapFunction(data)); + data = this._applyPostProcessFunction(this._applyMapFunction(data)); - if(!typeUtils.isPlainObject(extra)) { + if(!isPlainObject(extra)) { extra = {}; } - that._items = data; + this._items = data; - if(!data.length || !that._paginate || (that._pageSize && (data.length < that._pageSize))) { - that._isLastPage = true; + if(!data.length || !this._paginate || (this._pageSize && (data.length < this._pageSize))) { + this._isLastPage = true; } if(storeLoadOptions.requireTotalCount && !isFinite(extra.totalCount)) { @@ -802,7 +628,7 @@ const DataSource = Class.inherit({ } }, - _applyMapFunction: function(data) { + _applyMapFunction(data) { if(this._mapFunc) { return mapDataRespectingGrouping(data, this._mapFunc, this.group()); } @@ -810,7 +636,7 @@ const DataSource = Class.inherit({ return data; }, - _applyPostProcessFunction: function(data) { + _applyPostProcessFunction(data) { if(this._postProcessFunc) { return this._postProcessFunc(data); } @@ -828,7 +654,3 @@ const DataSource = Class.inherit({ return this; }, }); - -exports.DataSource = DataSource; -exports.normalizeDataSourceOptions = normalizeDataSourceOptions; -exports.normalizeLoadResult = normalizeLoadResult; diff --git a/js/data/data_source/operation_manager.js b/js/data/data_source/operation_manager.js new file mode 100644 index 000000000000..210055ffb5a6 --- /dev/null +++ b/js/data/data_source/operation_manager.js @@ -0,0 +1,34 @@ +import { CANCELED_TOKEN } from './utils'; + +export default class OperationManager { + constructor() { + this._counter = -1; + this._deferreds = {}; + } + + add(deferred) { + this._counter++; + this._deferreds[this._counter] = deferred; + return this._counter; + } + + remove(operationId) { + return delete this._deferreds[operationId]; + } + + cancel(operationId) { + if(operationId in this._deferreds) { + this._deferreds[operationId].reject(CANCELED_TOKEN); + return true; + } + + return false; + } + + cancelAll() { + while(this._counter > -1) { + this.cancel(this._counter); + this._counter--; + } + } +} diff --git a/js/data/data_source/utils.js b/js/data/data_source/utils.js new file mode 100644 index 000000000000..426eb6607c8e --- /dev/null +++ b/js/data/data_source/utils.js @@ -0,0 +1,124 @@ +import { sendRequest } from '../../core/utils/ajax'; +import Store from '../abstract_store'; +import ArrayStore from '../array_store'; +import { each, map } from '../../core/utils/iterator'; +import CustomStore from '../custom_store'; +import { extend } from '../../core/utils/extend'; +import { isPlainObject } from '../../core/utils/type'; +import { normalizeSortingInfo } from '../utils'; + +export const CANCELED_TOKEN = 'canceled'; + +export const isPending = deferred => deferred.state() === 'pending'; + +export const normalizeStoreLoadOptionAccessorArguments = (originalArguments) => { + switch(originalArguments.length) { + case 0: + return undefined; + case 1: + return originalArguments[0]; + } + return [].slice.call(originalArguments); +}; + +const mapGroup = (group, level, mapper) => map(group, item => { + const result = { + key: item.key, + items: mapRecursive(item.items, level - 1, mapper) + }; + if('aggregates' in item) { + result.aggregates = item.aggregates; + } + return result; +}); + +const mapRecursive = (items, level, mapper) => { + if(!Array.isArray(items)) return items; + return level ? mapGroup(items, level, mapper) : map(items, mapper); +}; + +export const mapDataRespectingGrouping = (items, mapper, groupInfo) => { + const level = groupInfo ? normalizeSortingInfo(groupInfo).length : 0; + + return mapRecursive(items, level, mapper); +}; + +export const normalizeLoadResult = (data, extra) => { + if(data?.data) { + extra = data; + data = data.data; + } + + if(!Array.isArray(data)) { + data = [data]; + } + + return { + data, + extra + }; +}; + +const createCustomStoreFromLoadFunc = (options) => { + const storeConfig = {}; + + each(['useDefaultSearch', 'key', 'load', 'loadMode', 'cacheRawData', 'byKey', 'lookup', 'totalCount', 'insert', 'update', 'remove'], function() { + storeConfig[this] = options[this]; + delete options[this]; + }); + + return new CustomStore(storeConfig); +}; + +const createStoreFromConfig = (storeConfig) => { + const alias = storeConfig.type; + + delete storeConfig.type; + + return Store.create(alias, storeConfig); +}; + +const createCustomStoreFromUrl = (url, normalizationOptions) => + new CustomStore({ + load: () => sendRequest({ url, dataType: 'json' }), + loadMode: normalizationOptions?.fromUrlLoadMode + }); + +export const normalizeDataSourceOptions = (options, normalizationOptions) => { + let store; + + if(typeof options === 'string') { + options = { + paginate: false, + store: createCustomStoreFromUrl(options, normalizationOptions) + }; + } + + if(options === undefined) { + options = []; + } + + if(Array.isArray(options) || options instanceof Store) { + options = { store: options }; + } else { + options = extend({}, options); + } + + if(options.store === undefined) { + options.store = []; + } + + store = options.store; + + if('load' in options) { + store = createCustomStoreFromLoadFunc(options); + } else if(Array.isArray(store)) { + store = new ArrayStore(store); + } else if(isPlainObject(store)) { + store = createStoreFromConfig(extend({}, store)); + } + + options.store = store; + + return options; +}; diff --git a/js/data/odata/context.js b/js/data/odata/context.js index eb5801cad596..25916ab36c0c 100644 --- a/js/data/odata/context.js +++ b/js/data/odata/context.js @@ -4,14 +4,15 @@ import { isDefined, isPlainObject } from '../../core/utils/type'; import { each } from '../../core/utils/iterator'; import errorsModule from '../errors'; import ODataStore from './store'; -import { SharedMethods, formatFunctionInvocationUrl, escapeServiceOperationParams } from './mixins'; +import RequestDispatcher from './request_dispatcher'; +import { escapeServiceOperationParams, formatFunctionInvocationUrl } from './utils'; import { when, Deferred } from '../../core/utils/deferred'; import './query_adapter'; const ODataContext = Class.inherit({ ctor(options) { - this._extractServiceOptions(options); + this._requestDispatcher = new RequestDispatcher(options); this._errorHandler = options.errorHandler; @@ -20,7 +21,7 @@ const ODataContext = Class.inherit({ {}, options, { - url: `${this._url}/${encodeURIComponent(entityOptions.name || entityAlias)}` + url: `${this._requestDispatcher.url}/${encodeURIComponent(entityOptions.name || entityAlias)}` }, entityOptions )); @@ -35,7 +36,7 @@ const ODataContext = Class.inherit({ httpMethod = httpMethod.toLowerCase(); const d = new Deferred(); - let url = `${this._url}/${encodeURIComponent(operationName)}`; + let url = `${this._requestDispatcher.url}/${encodeURIComponent(operationName)}`; let payload; if(this.version() === 4) { @@ -48,7 +49,7 @@ const ODataContext = Class.inherit({ } } - when(this._sendRequest(url, httpMethod, escapeServiceOperationParams(params, this.version()), payload)) + when(this._requestDispatcher.sendRequest(url, httpMethod, escapeServiceOperationParams(params, this.version()), payload)) .done((r) => { if(isPlainObject(r) && operationName in r) { r = r[operationName]; @@ -77,9 +78,11 @@ const ODataContext = Class.inherit({ uri: store._byKeyUrl(key, true) } }; - } + }, -}) - .include(SharedMethods); + version() { + return this._requestDispatcher.version; + }, +}); export default ODataContext; diff --git a/js/data/odata/mixins.js b/js/data/odata/mixins.js deleted file mode 100644 index b056a04176c0..000000000000 --- a/js/data/odata/mixins.js +++ /dev/null @@ -1,71 +0,0 @@ -const stringUtils = require('../../core/utils/string'); -const iteratorUtils = require('../../core/utils/iterator'); -const odataUtils = require('./utils'); - -require('./query_adapter'); - -const DEFAULT_PROTOCOL_VERSION = 2; - -const formatFunctionInvocationUrl = function(baseUrl, args) { - return stringUtils.format('{0}({1})', - baseUrl, - iteratorUtils.map(args || {}, function(value, key) { - return stringUtils.format('{0}={1}', key, value); - }).join(',') - ); -}; - -const escapeServiceOperationParams = function(params, version) { - if(!params) { - return params; - } - - // From WCF Data Services docs: - // The type of each parameter must be a primitive type. - // Any data of a non-primitive type must be serialized and passed into a string parameter - const result = {}; - iteratorUtils.each(params, function(k, v) { - result[k] = odataUtils.serializeValue(v, version); - }); - return result; -}; - -const SharedMethods = { - - _extractServiceOptions: function(options) { - options = options || {}; - - this._url = String(options.url).replace(/\/+$/, ''); - this._beforeSend = options.beforeSend; - this._jsonp = options.jsonp; - this._version = options.version || DEFAULT_PROTOCOL_VERSION; - this._withCredentials = options.withCredentials; - this._deserializeDates = options.deserializeDates; - this._filterToLower = options.filterToLower; - }, - - _sendRequest: function(url, method, params, payload) { - return odataUtils.sendRequest(this.version(), - { - url: url, - method: method, - params: params || {}, - payload: payload - }, - { - beforeSend: this._beforeSend, - jsonp: this._jsonp, - withCredentials: this._withCredentials, - deserializeDates: this._deserializeDates - } - ); - }, - - version: function() { - return this._version; - } -}; - -exports.SharedMethods = SharedMethods; -exports.escapeServiceOperationParams = escapeServiceOperationParams; -exports.formatFunctionInvocationUrl = formatFunctionInvocationUrl; diff --git a/js/data/odata/request_dispatcher.js b/js/data/odata/request_dispatcher.js new file mode 100644 index 000000000000..365dbdaacd02 --- /dev/null +++ b/js/data/odata/request_dispatcher.js @@ -0,0 +1,55 @@ +import { sendRequest } from './utils'; +import './query_adapter'; + +const DEFAULT_PROTOCOL_VERSION = 2; + +export default class RequestDispatcher { + constructor(options) { + options = options || {}; + + this._url = String(options.url).replace(/\/+$/, ''); + this._beforeSend = options.beforeSend; + this._jsonp = options.jsonp; + this._version = options.version || DEFAULT_PROTOCOL_VERSION; + this._withCredentials = options.withCredentials; + this._deserializeDates = options.deserializeDates; + this._filterToLower = options.filterToLower; + } + + sendRequest(url, method, params, payload) { + return sendRequest(this.version, + { + url, + method, + params: params || {}, + payload + }, + { + beforeSend: this._beforeSend, + jsonp: this._jsonp, + withCredentials: this._withCredentials, + deserializeDates: this._deserializeDates + } + ); + } + + get version() { + return this._version; + } + + get beforeSend() { + return this._beforeSend; + } + + get url() { + return this._url; + } + + get jsonp() { + return this._jsonp; + } + + get filterToLower() { + return this._filterToLower; + } +} diff --git a/js/data/odata/store.js b/js/data/odata/store.js index a2f4beb68a14..686e2ccd4468 100644 --- a/js/data/odata/store.js +++ b/js/data/odata/store.js @@ -1,26 +1,28 @@ -const isDefined = require('../../core/utils/type').isDefined; -const config = require('../../core/config'); -const odataUtils = require('./utils'); -const proxyUrlFormatter = require('../proxy_url_formatter'); -const errors = require('../errors').errors; -const query = require('../query'); -const Store = require('../abstract_store'); -const mixins = require('./mixins'); -const deferredUtils = require('../../core/utils/deferred'); -const when = deferredUtils.when; -const Deferred = deferredUtils.Deferred; - -require('./query_adapter'); + +import { isDefined } from '../../core/utils/type'; +import config from '../../core/config'; +import { + generateExpand, + generateSelect, + serializeKey, + convertPrimitiveValue, + formatFunctionInvocationUrl, + escapeServiceOperationParams +} from './utils'; +import proxyUrlFormatter from '../proxy_url_formatter'; +import { errors } from '../errors'; +import query from '../query'; +import Store from '../abstract_store'; +import RequestDispatcher from './request_dispatcher'; +import { when, Deferred } from '../../core/utils/deferred'; + +import './query_adapter'; const ANONYMOUS_KEY_NAME = '5d46402c-7899-4ea9-bd81-8b73c47c7683'; -function expandKeyType(key, keyType) { - const result = {}; - result[key] = keyType; - return result; -} +const expandKeyType = (key, keyType) => ({ [key]: keyType }); -function mergeFieldTypesWithKeyType(fieldTypes, keyType) { +const mergeFieldTypesWithKeyType = (fieldTypes, keyType) => { const result = {}; for(const field in fieldTypes) { @@ -38,15 +40,14 @@ function mergeFieldTypesWithKeyType(fieldTypes, keyType) { } return result; -} +}; const ODataStore = Store.inherit({ - ctor: function(options) { + ctor(options) { this.callBase(options); - this._extractServiceOptions(options); - + this._requestDispatcher = new RequestDispatcher(options); let key = this.key(); let fieldTypes = options.fieldTypes; @@ -76,55 +77,48 @@ const ODataStore = Store.inherit({ } }, - _customLoadOptions: function() { + _customLoadOptions() { return ['expand', 'customQueryParams']; }, - _byKeyImpl: function(key, extraOptions) { + _byKeyImpl(key, extraOptions) { const params = {}; if(extraOptions) { - params['$expand'] = odataUtils.generateExpand(this._version, extraOptions.expand, extraOptions.select) || undefined; - params['$select'] = odataUtils.generateSelect(this._version, extraOptions.select) || undefined; + params['$expand'] = generateExpand(this.version(), extraOptions.expand, extraOptions.select) || undefined; + params['$select'] = generateSelect(this.version(), extraOptions.select) || undefined; } - return this._sendRequest(this._byKeyUrl(key), 'GET', params); + return this._requestDispatcher.sendRequest(this._byKeyUrl(key), 'GET', params); }, - createQuery: function(loadOptions) { + createQuery(loadOptions) { let url; - - loadOptions = loadOptions || {}; const queryOptions = { adapter: 'odata', - - beforeSend: this._beforeSend, + beforeSend: this._requestDispatcher.beforeSend, errorHandler: this._errorHandler, - jsonp: this._jsonp, - version: this._version, - withCredentials: this._withCredentials, - expand: loadOptions.expand, - requireTotalCount: loadOptions.requireTotalCount, - deserializeDates: this._deserializeDates, + jsonp: this._requestDispatcher.jsonp, + version: this._requestDispatcher.version, + withCredentials: this._requestDispatcher._withCredentials, + expand: loadOptions?.expand, + requireTotalCount: loadOptions?.requireTotalCount, + deserializeDates: this._requestDispatcher._deserializeDates, fieldTypes: this._fieldTypes }; // NOTE: For AppBuilder, do not remove - if(isDefined(loadOptions.urlOverride)) { - url = loadOptions.urlOverride; - } else { - url = this._url; - } + url = loadOptions?.urlOverride ?? this._requestDispatcher.url; - if(isDefined(this._filterToLower)) { - queryOptions.filterToLower = this._filterToLower; + if(isDefined(this._requestDispatcher.filterToLower)) { + queryOptions.filterToLower = this._requestDispatcher.filterToLower; } - if(loadOptions.customQueryParams) { - const params = mixins.escapeServiceOperationParams(loadOptions.customQueryParams, this.version()); + if(loadOptions?.customQueryParams) { + const params = escapeServiceOperationParams(loadOptions?.customQueryParams, this.version()); if(this.version() === 4) { - url = mixins.formatFunctionInvocationUrl(url, params); + url = formatFunctionInvocationUrl(url, params); } else { queryOptions.params = params; } @@ -133,54 +127,49 @@ const ODataStore = Store.inherit({ return query(url, queryOptions); }, - _insertImpl: function(values) { + _insertImpl(values) { this._requireKey(); - const that = this; const d = new Deferred(); - when(this._sendRequest(this._url, 'POST', null, values)) - .done(function(serverResponse) { - d.resolve(config().useLegacyStoreResult ? values : (serverResponse || values), that.keyOf(serverResponse)); - }) + when(this._requestDispatcher.sendRequest(this._requestDispatcher.url, 'POST', null, values)) + .done(serverResponse => + d.resolve( + serverResponse && !config().useLegacyStoreResult ? serverResponse : values, + this.keyOf(serverResponse) + ) + ) .fail(d.reject); return d.promise(); }, - _updateImpl: function(key, values) { + _updateImpl(key, values) { const d = new Deferred(); when( - this._sendRequest(this._byKeyUrl(key), this._updateMethod, null, values) - ).done( - function(serverResponse) { - if(config().useLegacyStoreResult) { - d.resolve(key, values); - } else { - d.resolve(serverResponse || values, key); - } - } - ).fail(d.reject); + this._requestDispatcher.sendRequest(this._byKeyUrl(key), this._updateMethod, null, values) + ).done(serverResponse => + config().useLegacyStoreResult + ? d.resolve(key, values) + : d.resolve(serverResponse || values, key) + ) + .fail(d.reject); return d.promise(); }, - _removeImpl: function(key) { + _removeImpl(key) { const d = new Deferred(); - when( - this._sendRequest(this._byKeyUrl(key), 'DELETE') - ).done( - function() { - d.resolve(key); - } - ).fail(d.reject); + when(this._requestDispatcher.sendRequest(this._byKeyUrl(key), 'DELETE')) + .done(() => d.resolve(key)) + .fail(d.reject); return d.promise(); }, - _convertKey: function(value) { + _convertKey(value) { let result = value; const fieldTypes = this._fieldTypes; const key = this.key() || this._legacyAnonymousKey; @@ -189,25 +178,30 @@ const ODataStore = Store.inherit({ result = {}; for(let i = 0; i < key.length; i++) { const keyName = key[i]; - result[keyName] = odataUtils.convertPrimitiveValue(fieldTypes[keyName], value[keyName]); + result[keyName] = convertPrimitiveValue(fieldTypes[keyName], value[keyName]); } } else if(fieldTypes[key]) { - result = odataUtils.convertPrimitiveValue(fieldTypes[key], value); + result = convertPrimitiveValue(fieldTypes[key], value); } return result; }, - _byKeyUrl: function(value, useOriginalHost) { + _byKeyUrl(value, useOriginalHost) { const baseUrl = useOriginalHost - ? proxyUrlFormatter.formatLocalUrl(this._url) - : this._url; + ? proxyUrlFormatter.formatLocalUrl(this._requestDispatcher.url) + : this._requestDispatcher.url; const convertedKey = this._convertKey(value); - return baseUrl + '(' + encodeURIComponent(odataUtils.serializeKey(convertedKey, this._version)) + ')'; + return `${baseUrl}(${encodeURIComponent(serializeKey(convertedKey, this.version()))})`; + }, + + version() { + return this._requestDispatcher.version; } -}, 'odata').include(mixins.SharedMethods); +}, 'odata'); +// TODO: replace by "export default" after "odata/context" refactor module.exports = ODataStore; diff --git a/js/data/odata/utils.js b/js/data/odata/utils.js index ea6cf2066478..9b47641b36d4 100644 --- a/js/data/odata/utils.js +++ b/js/data/odata/utils.js @@ -8,6 +8,7 @@ import { grep } from '../../core/utils/common'; import { Deferred } from '../../core/utils/deferred'; import { errors } from '../errors'; import { XHR_ERROR_UNLOAD, errorMessageFromXhr } from '../utils'; +import { format as stringFormat } from '../../core/utils/string'; const GUID_REGEX = /^(\{{0,1}([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}\}{0,1})$/; @@ -599,6 +600,28 @@ export const generateExpand = (oDataVersion, expand, select) => ? generatorV2(expand, select) : generatorV4(expand, select); +export const formatFunctionInvocationUrl = (baseUrl, args) => + stringFormat( + '{0}({1})', + baseUrl, + map(args || {}, (value, key) => stringFormat('{0}={1}', key, value)).join(',') + ); + +export const escapeServiceOperationParams = (params, version) => { + if(!params) { + return params; + } + + // From WCF Data Services docs: + // The type of each parameter must be a primitive type. + // Any data of a non-primitive type must be serialized and passed into a string parameter + const result = {}; + each(params, (k, v) => { + result[k] = serializeValue(v, version); + }); + return result; +}; + ///#DEBUG export const OData__internals = { interpretJsonFormat diff --git a/js/data_helper.js b/js/data_helper.js index 4a918574b048..a61ec486e174 100644 --- a/js/data_helper.js +++ b/js/data_helper.js @@ -1,6 +1,6 @@ const DataSource = require('./data/data_source/data_source').DataSource; const extend = require('./core/utils/extend').extend; -const normalizeDataSourceOptions = require('./data/data_source/data_source').normalizeDataSourceOptions; +const normalizeDataSourceOptions = require('./data/data_source/utils').normalizeDataSourceOptions; const DATA_SOURCE_OPTIONS_METHOD = '_dataSourceOptions'; const DATA_SOURCE_CHANGED_METHOD = '_dataSourceChangedHandler'; diff --git a/js/docEnums.js b/js/docEnums.js index a990a6a13831..cc59ab1f179f 100644 --- a/js/docEnums.js +++ b/js/docEnums.js @@ -1053,7 +1053,7 @@ /** * @typedef {string} Enums.FileManagerToolbarItem - * @enum {'showNavPane'|'create'|'upload'|'refresh'|'viewSwitcher'|'download'|'move'|'copy'|'rename'|'delete'|'clear'|'separator'} + * @enum {'showNavPane'|'create'|'upload'|'refresh'|'switchView'|'download'|'move'|'copy'|'rename'|'delete'|'clear'|'separator'} */ /** @@ -1112,7 +1112,7 @@ /** * @typedef {string} Enums.DiagramToolbarCommand - * @enum {'separator'|'export'|'undo'|'redo'|'cut'|'copy'|'paste'|'selectAll'|'delete'|'fontName'|'fontSize'|'bold'|'italic'|'underline'|'fontColor'|'lineColor'|'fillColor'|'textAlignLeft'|'textAlignCenter'|'textAlignRight'|'lock'|'unlock'|'sendToBack'|'bringToFront'|'insertShapeImage'|'editShapeImage'|'deleteShapeImage'|'connectorLineType'|'connectorLineStart'|'connectorLineEnd'|'autoLayout'|'fullScreen'} + * @enum {'separator'|'export'|'undo'|'redo'|'cut'|'copy'|'paste'|'selectAll'|'delete'|'fontName'|'fontSize'|'bold'|'italic'|'underline'|'fontColor'|'lineColor'|'fillColor'|'textAlignLeft'|'textAlignCenter'|'textAlignRight'|'lock'|'unlock'|'sendToBack'|'bringToFront'|'insertShapeImage'|'editShapeImage'|'deleteShapeImage'|'connectorLineType'|'connectorLineStart'|'connectorLineEnd'|'autoLayout'|'fullScreen'|'zoomLevel'|'autoZoom'|'showGrid'|'snapToGrid'|'gridSize'|'units'} */ /** diff --git a/js/events.d.ts b/js/events.d.ts deleted file mode 100644 index 6bd8425fb220..000000000000 --- a/js/events.d.ts +++ /dev/null @@ -1,245 +0,0 @@ -import { - event -} from './events/index'; - -/** - * @docid eventsMethods.off - * @publicName off(element) - * @namespace DevExpress.events - * @param1 element:Node|Array - * @module events - * @export off - * @prevFileNamespace DevExpress.events - * @public - */ -export function off(element: Element | Array): void; - -/** - * @docid eventsMethods.off - * @publicName off(element, eventName) - * @namespace DevExpress.events - * @param1 element:Node|Array - * @param2 eventName:string - * @module events - * @export off - * @prevFileNamespace DevExpress.events - * @public - */ -export function off(element: Element | Array, eventName: string): void; - -/** - * @docid eventsMethods.off - * @publicName off(element, eventName, handler) - * @namespace DevExpress.events - * @param1 element:Node|Array - * @param2 eventName:string - * @param3 handler:function - * @module events - * @export off - * @prevFileNamespace DevExpress.events - * @public - */ -export function off(element: Element | Array, eventName: string, handler: Function): void; - -/** - * @docid eventsMethods.off - * @publicName off(element, eventName, selector) - * @namespace DevExpress.events - * @param1 element:Node|Array - * @param2 eventName:string - * @param3 selector:string - * @module events - * @export off - * @prevFileNamespace DevExpress.events - * @public - */ -export function off(element: Element | Array, eventName: string, selector: string): void; - -/** - * @docid eventsMethods.off - * @publicName off(element, eventName, selector, handler) - * @namespace DevExpress.events - * @param1 element:Node|Array - * @param2 eventName:string - * @param3 selector:string - * @param4 handler:function - * @module events - * @export off - * @prevFileNamespace DevExpress.events - * @public - */ -export function off(element: Element | Array, eventName: string, selector: string, handler: Function): void; - -/** - * @docid eventsMethods.on - * @publicName on(element, eventName, data, handler) - * @namespace DevExpress.events - * @param1 element:Node|Array - * @param2 eventName:string - * @param3 data:object - * @param4 handler:function - * @module events - * @export on - * @prevFileNamespace DevExpress.events - * @public - */ -export function on(element: Element | Array, eventName: string, data: any, handler: Function): void; - -/** - * @docid eventsMethods.on - * @publicName on(element, eventName, handler) - * @namespace DevExpress.events - * @param1 element:Node|Array - * @param2 eventName:string - * @param3 handler:function - * @module events - * @export on - * @prevFileNamespace DevExpress.events - * @public - */ -export function on(element: Element | Array, eventName: string, handler: Function): void; - -/** - * @docid eventsMethods.on - * @publicName on(element, eventName, selector, data, handler) - * @namespace DevExpress.events - * @param1 element:Node|Array - * @param2 eventName:string - * @param3 selector:string - * @param4 data:object - * @param5 handler:function - * @module events - * @export on - * @prevFileNamespace DevExpress.events - * @public - */ -export function on(element: Element | Array, eventName: string, selector: string, data: any, handler: Function): void; - -/** - * @docid eventsMethods.on - * @publicName on(element, eventName, selector, handler) - * @namespace DevExpress.events - * @param1 element:Node|Array - * @param2 eventName:string - * @param3 selector:string - * @param4 handler:function - * @module events - * @export on - * @prevFileNamespace DevExpress.events - * @public - */ -export function on(element: Element | Array, eventName: string, selector: string, handler: Function): void; - -/** - * @docid eventsMethods.one - * @publicName one(element, eventName, data, handler) - * @namespace DevExpress.events - * @param1 element:Node|Array - * @param2 eventName:string - * @param3 data:object - * @param4 handler:function - * @module events - * @export one - * @prevFileNamespace DevExpress.events - * @public - */ -export function one(element: Element | Array, eventName: string, data: any, handler: Function): void; - -/** - * @docid eventsMethods.one - * @publicName one(element, eventName, handler) - * @namespace DevExpress.events - * @param1 element:Node|Array - * @param2 eventName:string - * @param3 handler:function - * @module events - * @export one - * @prevFileNamespace DevExpress.events - * @public - */ -export function one(element: Element | Array, eventName: string, handler: Function): void; - -/** - * @docid eventsMethods.one - * @publicName one(element, eventName, selector, data, handler) - * @namespace DevExpress.events - * @param1 element:Node|Array - * @param2 eventName:string - * @param3 selector:string - * @param4 data:object - * @param5 handler:function - * @module events - * @export one - * @prevFileNamespace DevExpress.events - * @public - */ -export function one(element: Element | Array, eventName: string, selector: string, data: any, handler: Function): void; - -/** - * @docid eventsMethods.one - * @publicName one(element, eventName, selector, handler) - * @namespace DevExpress.events - * @param1 element:Node|Array - * @param2 eventName:string - * @param3 selector:string - * @param4 handler:function - * @module events - * @export one - * @prevFileNamespace DevExpress.events - * @public - */ -export function one(element: Element | Array, eventName: string, selector: string, handler: Function): void; - -/** - * @docid eventsMethods.trigger - * @publicName trigger(element, event) - * @namespace DevExpress.events - * @param1 element:Node|Array - * @param2 event:string|event - * @module events - * @export trigger - * @prevFileNamespace DevExpress.events - * @public - */ -export function trigger(element: Element | Array, event: string | event): void; - -/** - * @docid eventsMethods.trigger - * @publicName trigger(element, event, extraParameters) - * @namespace DevExpress.events - * @param1 element:Node|Array - * @param2 event:string|event - * @param3 extraParameters:object - * @module events - * @export trigger - * @prevFileNamespace DevExpress.events - * @public - */ -export function trigger(element: Element | Array, event: string | event, extraParameters: any): void; - -/** - * @docid eventsMethods.triggerHandler - * @publicName triggerHandler(element, event) - * @namespace DevExpress.events - * @param1 element:Node|Array - * @param2 event:string|event - * @module events - * @export triggerHandler - * @hidden - * @prevFileNamespace DevExpress.events - */ -export function triggerHandler(element: Element | Array, event: string | event): void; - -/** - * @docid eventsMethods.triggerHandler - * @publicName triggerHandler(element, event, extraParameters) - * @namespace DevExpress.events - * @param1 element:Node|Array - * @param2 event:string|event - * @param3 extraParameters:object - * @module events - * @export triggerHandler - * @hidden - * @prevFileNamespace DevExpress.events - */ -export function triggerHandler(element: Element | Array, event: string | event, extraParameters: any): void; diff --git a/js/events/index.d.ts b/js/events/index.d.ts index 65e8e69733bb..46360d121390 100644 --- a/js/events/index.d.ts +++ b/js/events/index.d.ts @@ -96,7 +96,6 @@ export class dxEvent { */ export type event = dxEvent | JQueryEventObject; - /** * @docid eventsHandler * @publicName handler(event, extraParameters) @@ -108,3 +107,245 @@ export type event = dxEvent | JQueryEventObject; * @prevFileNamespace DevExpress.events */ export function eventsHandler(event: dxEvent, extraParameters: any): boolean; + +/** + * @docid eventsMethods.off + * @publicName off(element) + * @namespace DevExpress.events + * @param1 element:Node|Array + * @module events + * @export off + * @prevFileNamespace DevExpress.events + * @public + */ +export function off(element: Element | Array): void; + +/** + * @docid eventsMethods.off + * @publicName off(element, eventName) + * @namespace DevExpress.events + * @param1 element:Node|Array + * @param2 eventName:string + * @module events + * @export off + * @prevFileNamespace DevExpress.events + * @public + */ +export function off(element: Element | Array, eventName: string): void; + +/** + * @docid eventsMethods.off + * @publicName off(element, eventName, handler) + * @namespace DevExpress.events + * @param1 element:Node|Array + * @param2 eventName:string + * @param3 handler:function + * @module events + * @export off + * @prevFileNamespace DevExpress.events + * @public + */ +export function off(element: Element | Array, eventName: string, handler: Function): void; + +/** + * @docid eventsMethods.off + * @publicName off(element, eventName, selector) + * @namespace DevExpress.events + * @param1 element:Node|Array + * @param2 eventName:string + * @param3 selector:string + * @module events + * @export off + * @prevFileNamespace DevExpress.events + * @public + */ +export function off(element: Element | Array, eventName: string, selector: string): void; + +/** + * @docid eventsMethods.off + * @publicName off(element, eventName, selector, handler) + * @namespace DevExpress.events + * @param1 element:Node|Array + * @param2 eventName:string + * @param3 selector:string + * @param4 handler:function + * @module events + * @export off + * @prevFileNamespace DevExpress.events + * @public + */ +export function off(element: Element | Array, eventName: string, selector: string, handler: Function): void; + +/** + * @docid eventsMethods.on + * @publicName on(element, eventName, data, handler) + * @namespace DevExpress.events + * @param1 element:Node|Array + * @param2 eventName:string + * @param3 data:object + * @param4 handler:function + * @module events + * @export on + * @prevFileNamespace DevExpress.events + * @public + */ +export function on(element: Element | Array, eventName: string, data: any, handler: Function): void; + +/** + * @docid eventsMethods.on + * @publicName on(element, eventName, handler) + * @namespace DevExpress.events + * @param1 element:Node|Array + * @param2 eventName:string + * @param3 handler:function + * @module events + * @export on + * @prevFileNamespace DevExpress.events + * @public + */ +export function on(element: Element | Array, eventName: string, handler: Function): void; + +/** + * @docid eventsMethods.on + * @publicName on(element, eventName, selector, data, handler) + * @namespace DevExpress.events + * @param1 element:Node|Array + * @param2 eventName:string + * @param3 selector:string + * @param4 data:object + * @param5 handler:function + * @module events + * @export on + * @prevFileNamespace DevExpress.events + * @public + */ +export function on(element: Element | Array, eventName: string, selector: string, data: any, handler: Function): void; + +/** + * @docid eventsMethods.on + * @publicName on(element, eventName, selector, handler) + * @namespace DevExpress.events + * @param1 element:Node|Array + * @param2 eventName:string + * @param3 selector:string + * @param4 handler:function + * @module events + * @export on + * @prevFileNamespace DevExpress.events + * @public + */ +export function on(element: Element | Array, eventName: string, selector: string, handler: Function): void; + +/** + * @docid eventsMethods.one + * @publicName one(element, eventName, data, handler) + * @namespace DevExpress.events + * @param1 element:Node|Array + * @param2 eventName:string + * @param3 data:object + * @param4 handler:function + * @module events + * @export one + * @prevFileNamespace DevExpress.events + * @public + */ +export function one(element: Element | Array, eventName: string, data: any, handler: Function): void; + +/** + * @docid eventsMethods.one + * @publicName one(element, eventName, handler) + * @namespace DevExpress.events + * @param1 element:Node|Array + * @param2 eventName:string + * @param3 handler:function + * @module events + * @export one + * @prevFileNamespace DevExpress.events + * @public + */ +export function one(element: Element | Array, eventName: string, handler: Function): void; + +/** + * @docid eventsMethods.one + * @publicName one(element, eventName, selector, data, handler) + * @namespace DevExpress.events + * @param1 element:Node|Array + * @param2 eventName:string + * @param3 selector:string + * @param4 data:object + * @param5 handler:function + * @module events + * @export one + * @prevFileNamespace DevExpress.events + * @public + */ +export function one(element: Element | Array, eventName: string, selector: string, data: any, handler: Function): void; + +/** + * @docid eventsMethods.one + * @publicName one(element, eventName, selector, handler) + * @namespace DevExpress.events + * @param1 element:Node|Array + * @param2 eventName:string + * @param3 selector:string + * @param4 handler:function + * @module events + * @export one + * @prevFileNamespace DevExpress.events + * @public + */ +export function one(element: Element | Array, eventName: string, selector: string, handler: Function): void; + +/** + * @docid eventsMethods.trigger + * @publicName trigger(element, event) + * @namespace DevExpress.events + * @param1 element:Node|Array + * @param2 event:string|event + * @module events + * @export trigger + * @prevFileNamespace DevExpress.events + * @public + */ +export function trigger(element: Element | Array, event: string | event): void; + +/** + * @docid eventsMethods.trigger + * @publicName trigger(element, event, extraParameters) + * @namespace DevExpress.events + * @param1 element:Node|Array + * @param2 event:string|event + * @param3 extraParameters:object + * @module events + * @export trigger + * @prevFileNamespace DevExpress.events + * @public + */ +export function trigger(element: Element | Array, event: string | event, extraParameters: any): void; + +/** + * @docid eventsMethods.triggerHandler + * @publicName triggerHandler(element, event) + * @namespace DevExpress.events + * @param1 element:Node|Array + * @param2 event:string|event + * @module events + * @export triggerHandler + * @hidden + * @prevFileNamespace DevExpress.events + */ +export function triggerHandler(element: Element | Array, event: string | event): void; + +/** + * @docid eventsMethods.triggerHandler + * @publicName triggerHandler(element, event, extraParameters) + * @namespace DevExpress.events + * @param1 element:Node|Array + * @param2 event:string|event + * @param3 extraParameters:object + * @module events + * @export triggerHandler + * @hidden + * @prevFileNamespace DevExpress.events + */ +export function triggerHandler(element: Element | Array, event: string | event, extraParameters: any): void; diff --git a/js/excel_exporter.d.ts b/js/excel_exporter.d.ts new file mode 100644 index 000000000000..229b2adcc352 --- /dev/null +++ b/js/excel_exporter.d.ts @@ -0,0 +1,207 @@ +import dxDataGrid, { dxDataGridColumn } from './ui/data_grid'; + +export interface ExcelDataGridCell { + /** + * @docid ExcelDataGridCell.column + * @type dxDataGridColumn + * @public + */ + column?: dxDataGridColumn; + /** + * @docid ExcelDataGridCell.data + * @type Object + * @public + */ + data?: any; + /** + * @docid ExcelDataGridCell.groupIndex + * @type number + * @public + */ + groupIndex?: number; + /** + * @docid ExcelDataGridCell.groupSummaryItems + * @type Array + * @public + */ + groupSummaryItems?: Array<{ name?: string, value?: any }>; + /** + * @docid ExcelDataGridCell.rowType + * @type string + * @public + */ + rowType?: string; + /** + * @docid ExcelDataGridCell.totalSummaryItemName + * @type string + * @public + */ + totalSummaryItemName?: string; + /** + * @docid ExcelDataGridCell.value + * @type any + * @public + */ + value?: any; +} + +export interface CellAddress { + /** + * @docid CellAddress.row + * @type number + * @public + */ + row?: number; + /** + * @docid CellAddress.column + * @type number + * @public + */ + column?: number; +} + +export interface CellRange { + /** + * @docid CellRange.from + * @type CellAddress + * @public + */ + from?: CellAddress; + /** + * @docid CellRange.to + * @type CellAddress + * @public + */ + to?: CellAddress; +} + +export interface ExportLoadPanel { + /** + * @docid ExportLoadPanel.enabled + * @type boolean + * @default true + */ + enabled?: boolean; + /** + * @docid ExportLoadPanel.text + * @type string + * @default "Exporting..." + */ + text?: string; + /** + * @docid ExportLoadPanel.width + * @type number + * @default 200 + */ + width?: number; + /** + * @docid ExportLoadPanel.height + * @type number + * @default 90 + */ + height?: number; + /** + * @docid ExportLoadPanel.showIndicator + * @type boolean + * @default true + */ + showIndicator?: boolean; + /** + * @docid ExportLoadPanel.indicatorSrc + * @type string + * @default "" + */ + indicatorSrc?: string; + /** + * @docid ExportLoadPanel.showPane + * @type boolean + * @default true + */ + showPane?: boolean; + /** + * @docid ExportLoadPanel.shading + * @type boolean + * @default false + */ + shading?: boolean; + /** + * @docid ExportLoadPanel.shadingColor + * @type string + * @default '' + */ + shadingColor?: string; +} + +export interface ExportDataGridProps { + /** + * @docid ExportDataGridProps.component + * @type dxDataGrid + * @default undefined + * @public + */ + component?: dxDataGrid; + /** + * @docid ExportDataGridProps.worksheet + * @type Object + * @default undefined + * @public + */ + worksheet?: object; + /** + * @docid ExportDataGridProps.topLeftCell + * @type CellAddress + * @default { row: 1, column: 1 } + * @public + */ + topLeftCell?: CellAddress; + /** + * @docid ExportDataGridProps.selectedRowsOnly + * @type boolean + * @default false + * @public + */ + selectedRowsOnly?: boolean; + /** + * @docid ExportDataGridProps.autoFilterEnabled + * @type boolean + * @default false + * @public + */ + autoFilterEnabled?: boolean; + /** + * @docid ExportDataGridProps.keepColumnWidths + * @type boolean + * @default true + * @public + */ + keepColumnWidths?: boolean; + /** + * @docid ExportDataGridProps.customizeCell + * @type function(options) + * @type_function_param1 options:Object + * @type_function_param1_field1 gridCell:ExcelDataGridCell + * @type_function_param1_field2 excelCell:Object + * @public + */ + customizeCell?: ((options: { gridCell?: ExcelDataGridCell, excelCell?: object}) => any); + /** + * @docid ExportDataGridProps.loadPanel + * @type ExportLoadPanel + * @public + */ + loadPanel?: ExportLoadPanel; +} + +/** + * @docid excelExporter.exportDataGrid + * @publicName exportDataGrid(options) + * @param1 options:ExportDataGridProps + * @return Promise + * @namespace DevExpress.excelExporter + * @module excel_exporter + * @static + * @prevFileNamespace DevExpress + * @public + */ +export function exportDataGrid(options: ExportDataGridProps): Promise & JQueryPromise; + diff --git a/js/excel_exporter.js b/js/excel_exporter.js new file mode 100644 index 000000000000..82568e83d26a --- /dev/null +++ b/js/excel_exporter.js @@ -0,0 +1,41 @@ +import { exportDataGrid } from './exporter/exceljs/export_data_grid'; + +/** +* @name excelExporter +* @section utils +*/ +/** +* @name CellAddress +* @namespace DevExpress.excelExporter +* @type object +*/ +/** +* @name ExportDataGridProps +* @namespace DevExpress.excelExporter +* @type object +*/ +/** +* @name CellRange +* @namespace DevExpress.excelExporter +* @type object +*/ +/** +* @name ExportLoadPanel +* @namespace DevExpress.excelExporter +* @type object +*/ +/** +* @name ExcelDataGridCell +* @namespace DevExpress.excelExporter +* @type object +*/ +/** +* @name ExcelDataGridCell.groupSummaryItems.name +* @type string +*/ +/** +* @name ExcelDataGridCell.groupSummaryItems.value +* @type any +*/ + +export { exportDataGrid }; diff --git a/js/exporter/excel/excel.doc_comments.d.ts b/js/exporter/excel/excel.doc_comments.d.ts index 6fccd2189e9a..45a5137dc5bf 100644 --- a/js/exporter/excel/excel.doc_comments.d.ts +++ b/js/exporter/excel/excel.doc_comments.d.ts @@ -1,59 +1,3 @@ -import { - dxDataGridColumn -} from '../../ui/data_grid'; - -export interface ExcelDataGridCell { - /** - * @docid ExcelDataGridCell.column - * @type dxDataGridColumn - * @prevFileNamespace DevExpress.exporter - * @public - */ - column?: dxDataGridColumn; - /** - * @docid ExcelDataGridCell.data - * @type object - * @prevFileNamespace DevExpress.exporter - * @public - */ - data?: any; - /** - * @docid ExcelDataGridCell.groupIndex - * @type number - * @prevFileNamespace DevExpress.exporter - * @public - */ - groupIndex?: number; - /** - * @docid ExcelDataGridCell.groupSummaryItems - * @type Array - * @prevFileNamespace DevExpress.exporter - * @public - */ - groupSummaryItems?: Array<{ name?: string, value?: any }>; - /** - * @docid ExcelDataGridCell.rowType - * @type string - * @prevFileNamespace DevExpress.exporter - * @public - */ - rowType?: string; - /** - * @docid ExcelDataGridCell.totalSummaryItemName - * @type string - * @prevFileNamespace DevExpress.exporter - * @public - */ - totalSummaryItemName?: string; - /** - * @docid ExcelDataGridCell.value - * @type any - * @prevFileNamespace DevExpress.exporter - * @public - */ - value?: any; -} - export interface ExcelFont { /** * @docid ExcelFont.bold diff --git a/js/exporter/excel/excel.doc_comments.js b/js/exporter/excel/excel.doc_comments.js index 417fea0b06ff..55f999021e87 100644 --- a/js/exporter/excel/excel.doc_comments.js +++ b/js/exporter/excel/excel.doc_comments.js @@ -2,16 +2,3 @@ * @name ExcelFont * @type object */ - -/** -* @name ExcelDataGridCell -* @type object -*/ -/** -* @name ExcelDataGridCell.groupSummaryItems.name -* @type string -*/ -/** -* @name ExcelDataGridCell.groupSummaryItems.value -* @type any -*/ diff --git a/js/exporter/exceljs/excelExporter.js b/js/exporter/exceljs/excelExporter.js deleted file mode 100644 index 74c25eab4db2..000000000000 --- a/js/exporter/exceljs/excelExporter.js +++ /dev/null @@ -1,3 +0,0 @@ -import { exportDataGrid } from './exportDataGrid'; - -export { exportDataGrid }; diff --git a/js/exporter/exceljs/exportDataGrid.js b/js/exporter/exceljs/export_data_grid.js similarity index 88% rename from js/exporter/exceljs/exportDataGrid.js rename to js/exporter/exceljs/export_data_grid.js index 372431c1393e..cee5e6f9adbe 100644 --- a/js/exporter/exceljs/exportDataGrid.js +++ b/js/exporter/exceljs/export_data_grid.js @@ -30,12 +30,14 @@ function exportDataGrid(options) { } component.option('loadPanel', loadPanel); + const wrapText = !!component.option('wordWrapEnabled'); + worksheet.properties.outlineProperties = { summaryBelow: false, summaryRight: false }; - const cellsRange = { + const cellRange = { from: { row: topLeftCell.row, column: topLeftCell.column }, to: { row: topLeftCell.row, column: topLeftCell.column } }; @@ -49,28 +51,28 @@ function exportDataGrid(options) { const dataRowsCount = dataProvider.getRowsCount(); if(keepColumnWidths) { - _setColumnsWidth(worksheet, columns, cellsRange.from.column); + _setColumnsWidth(worksheet, columns, cellRange.from.column); } const mergedCells = []; const mergeRanges = []; for(let rowIndex = 0; rowIndex < dataRowsCount; rowIndex++) { - const row = worksheet.getRow(cellsRange.from.row + rowIndex); + const row = worksheet.getRow(cellRange.from.row + rowIndex); - _exportRow(rowIndex, columns.length, row, cellsRange.from.column, dataProvider, customizeCell, headerRowCount, mergedCells, mergeRanges); + _exportRow(rowIndex, columns.length, row, cellRange.from.column, dataProvider, customizeCell, headerRowCount, mergedCells, mergeRanges, wrapText); if(rowIndex >= headerRowCount) { row.outlineLevel = dataProvider.getGroupLevel(rowIndex); } if(rowIndex >= 1) { - cellsRange.to.row++; + cellRange.to.row++; } } _mergeCells(worksheet, topLeftCell, mergeRanges); - cellsRange.to.column += columns.length > 0 ? columns.length - 1 : 0; + cellRange.to.column += columns.length > 0 ? columns.length - 1 : 0; const worksheetViewSettings = worksheet.views[0] || {}; @@ -80,16 +82,16 @@ function exportDataGrid(options) { if(headerRowCount > 0) { if(Object.keys(worksheetViewSettings).indexOf('state') === -1) { - extend(worksheetViewSettings, { state: 'frozen', ySplit: cellsRange.from.row + dataProvider.getFrozenArea().y - 1 }); + extend(worksheetViewSettings, { state: 'frozen', ySplit: cellRange.from.row + dataProvider.getFrozenArea().y - 1 }); } - _setAutoFilter(dataProvider, worksheet, component, cellsRange, autoFilterEnabled); + _setAutoFilter(dataProvider, worksheet, component, cellRange, autoFilterEnabled); } if(Object.keys(worksheetViewSettings).length > 0) { worksheet.views = [worksheetViewSettings]; } - resolve(cellsRange); + resolve(cellRange); }).always(() => { component.option('loadPanel', initialLoadPanelOptions); }); @@ -116,14 +118,14 @@ function _getFullOptions(options) { if(!isDefined(fullOptions.loadPanel.text)) { fullOptions.loadPanel.text = messageLocalization.format('dxDataGrid-exporting'); } - if(!isDefined(fullOptions.autoFilterEnabled) && isDefined(fullOptions.component)) { - fullOptions.autoFilterEnabled = !!fullOptions.component.option('export.excelFilterEnabled'); + if(!isDefined(fullOptions.autoFilterEnabled)) { + fullOptions.autoFilterEnabled = false; } return fullOptions; } -function _exportRow(rowIndex, cellCount, row, startColumnIndex, dataProvider, customizeCell, headerRowCount, mergedCells, mergeRanges) { +function _exportRow(rowIndex, cellCount, row, startColumnIndex, dataProvider, customizeCell, headerRowCount, mergedCells, mergeRanges, wrapText) { const styles = dataProvider.getStyles(); for(let cellIndex = 0; cellIndex < cellCount; cellIndex++) { @@ -134,7 +136,7 @@ function _exportRow(rowIndex, cellCount, row, startColumnIndex, dataProvider, cu excelCell.value = cellData.value; if(isDefined(excelCell.value)) { - const { bold, alignment, wrapText, format, dataType } = styles[dataProvider.getStyleId(rowIndex, cellIndex)]; + const { bold, alignment: horizontalAlignment, format, dataType } = styles[dataProvider.getStyleId(rowIndex, cellIndex)]; let numberFormat = _tryConvertToExcelNumberFormat(format, dataType); if(isDefined(numberFormat)) { @@ -145,7 +147,7 @@ function _exportRow(rowIndex, cellCount, row, startColumnIndex, dataProvider, cu _setNumberFormat(excelCell, numberFormat); _setFont(excelCell, bold); - _setAlignment(excelCell, wrapText, alignment); + _setAlignment(excelCell, wrapText, horizontalAlignment); } if(isDefined(customizeCell)) { @@ -165,10 +167,10 @@ function _exportRow(rowIndex, cellCount, row, startColumnIndex, dataProvider, cu } } -function _setAutoFilter(dataProvider, worksheet, component, cellsRange, autoFilterEnabled) { +function _setAutoFilter(dataProvider, worksheet, component, cellRange, autoFilterEnabled) { if(autoFilterEnabled) { if(!isDefined(worksheet.autoFilter) && dataProvider.getRowsCount() > 0) { - worksheet.autoFilter = cellsRange; + worksheet.autoFilter = cellRange; } } } @@ -213,12 +215,15 @@ function _setFont(excelCell, bold) { function _setAlignment(excelCell, wrapText, horizontalAlignment) { excelCell.alignment = excelCell.alignment || {}; + if(isDefined(wrapText)) { excelCell.alignment.wrapText = wrapText; } if(isDefined(horizontalAlignment)) { excelCell.alignment.horizontal = horizontalAlignment; } + + excelCell.alignment.vertical = 'top'; } function _setColumnsWidth(worksheet, columns, startColumnIndex) { diff --git a/js/file_management/custom_provider.d.ts b/js/file_management/custom_provider.d.ts new file mode 100644 index 000000000000..593c46ca54cb --- /dev/null +++ b/js/file_management/custom_provider.d.ts @@ -0,0 +1,135 @@ +import FileSystemProviderBase, { + FileSystemProviderBaseOptions +} from './provider_base'; + +import FileSystemItem from './file_system_item'; +import UploadInfo from './upload_info'; + +export interface CustomFileSystemProviderOptions extends FileSystemProviderBaseOptions { + /** + * @docid CustomFileSystemProviderOptions.abortFileUpload + * @type function + * @type_function_param1 file:File + * @type_function_param2 uploadInfo?:UploadInfo + * @type_function_return Promise|any + * @prevFileNamespace DevExpress.fileManagement + * @public + */ + abortFileUpload?: ((file: File, uploadInfo?: UploadInfo) => Promise | JQueryPromise | any); + + /** + * @docid CustomFileSystemProviderOptions.copyItem + * @type function + * @type_function_param1 item:FileSystemItem + * @type_function_param2 destinationDirectory:FileSystemItem + * @type_function_return Promise|any + * @prevFileNamespace DevExpress.fileManagement + * @public + */ + copyItem?: ((item: FileSystemItem, destinationDirectory: FileSystemItem) => Promise | JQueryPromise | any); + + /** + * @docid CustomFileSystemProviderOptions.createDirectory + * @type function + * @type_function_param1 parentDirectory:FileSystemItem + * @type_function_param2 name:string + * @type_function_return Promise|any + * @prevFileNamespace DevExpress.fileManagement + * @public + */ + createDirectory?: ((parentDirectory: FileSystemItem, name: string) => Promise | JQueryPromise | any); + + /** + * @docid CustomFileSystemProviderOptions.deleteItem + * @type function + * @type_function_param1 item:FileSystemItem + * @type_function_return Promise|any + * @prevFileNamespace DevExpress.fileManagement + * @public + */ + deleteItem?: ((item: FileSystemItem) => Promise | JQueryPromise | any); + + /** + * @docid CustomFileSystemProviderOptions.downloadItems + * @type function + * @type_function_param1 items:Array + * @prevFileNamespace DevExpress.fileManagement + * @public + */ + downloadItems?: ((items: Array) => any); + + /** + * @docid CustomFileSystemProviderOptions.getItems + * @type function + * @type_function_param1 parentDirectory:FileSystemItem + * @type_function_return Promise>|Array + * @prevFileNamespace DevExpress.fileManagement + * @public + */ + getItems?: ((parentDirectory: FileSystemItem) => Promise> | JQueryPromise> | Array); + + /** + * @docid CustomFileSystemProviderOptions.getItemsContent + * @type function + * @type_function_param1 items:Array + * @type_function_return Promise|object + * @prevFileNamespace DevExpress.fileManagement + * @public + */ + getItemsContent?: ((items: Array) => Promise | JQueryPromise | any); + + /** + * @docid CustomFileSystemProviderOptions.hasSubDirectoriesExpr + * @type string|function(fileSystemItem) + * @prevFileNamespace DevExpress.fileManagement + * @public + */ + hasSubDirectoriesExpr?: string | Function; + + /** + * @docid CustomFileSystemProviderOptions.moveItem + * @type function + * @type_function_param1 item:FileSystemItem + * @type_function_param2 destinationDirectory:FileSystemItem + * @type_function_return Promise|any + * @prevFileNamespace DevExpress.fileManagement + * @public + */ + moveItem?: ((item: FileSystemItem, destinationDirectory: FileSystemItem) => Promise | JQueryPromise | any); + + /** + * @docid CustomFileSystemProviderOptions.renameItem + * @type function + * @type_function_param1 item:FileSystemItem + * @type_function_param2 newName:string + * @type_function_return Promise|any + * @prevFileNamespace DevExpress.fileManagement + * @public + */ + renameItem?: ((item: FileSystemItem, newName: string) => Promise | JQueryPromise | any); + + /** + * @docid CustomFileSystemProviderOptions.uploadFileChunk + * @type function + * @type_function_param1 file:File + * @type_function_param2 uploadInfo:UploadInfo + * @type_function_return Promise|any + * @prevFileNamespace DevExpress.fileManagement + * @public + */ + uploadFileChunk?: ((file: File, uploadInfo: UploadInfo) => Promise | JQueryPromise | any); +} + +/** + * @docid CustomFileSystemProvider + * @inherits FileSystemProviderBase + * @type object + * @module file_management/custom_provider + * @namespace DevExpress.fileManagement + * @export default + * @prevFileNamespace DevExpress.fileManagement + * @public + */ +export default class CustomFileSystemProvider extends FileSystemProviderBase { + constructor(options?: CustomFileSystemProviderOptions) +} diff --git a/js/ui/file_manager/file_provider/custom.js b/js/file_management/custom_provider.js similarity index 57% rename from js/ui/file_manager/file_provider/custom.js rename to js/file_management/custom_provider.js index 8881efcac297..3649986fd75b 100644 --- a/js/ui/file_manager/file_provider/custom.js +++ b/js/file_management/custom_provider.js @@ -1,11 +1,10 @@ -import { ensureDefined, noop } from '../../../core/utils/common'; -import { isFunction } from '../../../core/utils/type'; -import { when } from '../../../core/utils/deferred'; -import { compileGetter } from '../../../core/utils/data'; +import { ensureDefined, noop } from '../core/utils/common'; +import { isFunction } from '../core/utils/type'; +import { compileGetter } from '../core/utils/data'; -import { FileProvider } from './file_provider'; +import FileSystemProviderBase from './provider_base'; -class CustomFileProvider extends FileProvider { +class CustomFileSystemProvider extends FileSystemProviderBase { constructor(options) { options = ensureDefined(options, { }); @@ -32,53 +31,48 @@ class CustomFileProvider extends FileProvider { this._downloadItemsFunction = this._ensureFunction(options.downloadItems); this._getItemsContentFunction = this._ensureFunction(options.getItemsContent); - - this._uploadChunkSize = options.uploadChunkSize; } - getItems(pathInfo) { - return when(this._getItemsFunction(pathInfo)) + getItems(parentDir) { + const pathInfo = parentDir.getFullPathInfo(); + return this._executeActionAsDeferred(() => this._getItemsFunction(parentDir), true) .then(dataItems => this._convertDataObjectsToFileItems(dataItems, pathInfo)); } renameItem(item, name) { - return this._renameItemFunction(item, name); + return this._executeActionAsDeferred(() => this._renameItemFunction(item, name)); } - createFolder(parentDir, name) { - return this._createDirectoryFunction(parentDir, name); + createDirectory(parentDir, name) { + return this._executeActionAsDeferred(() => this._createDirectoryFunction(parentDir, name)); } deleteItems(items) { - return items.map(item => this._deleteItemFunction(item)); + return items.map(item => this._executeActionAsDeferred(() => this._deleteItemFunction(item))); } moveItems(items, destinationDirectory) { - return items.map(item => this._moveItemFunction(item, destinationDirectory)); + return items.map(item => this._executeActionAsDeferred(() => this._moveItemFunction(item, destinationDirectory))); } copyItems(items, destinationFolder) { - return items.map(item => this._copyItemFunction(item, destinationFolder)); + return items.map(item => this._executeActionAsDeferred(() => this._copyItemFunction(item, destinationFolder))); } uploadFileChunk(fileData, chunksInfo, destinationDirectory) { - return this._uploadFileChunkFunction(fileData, chunksInfo, destinationDirectory); + return this._executeActionAsDeferred(() => this._uploadFileChunkFunction(fileData, chunksInfo, destinationDirectory)); } abortFileUpload(fileData, chunksInfo, destinationDirectory) { - return this._abortFileUploadFunction(fileData, chunksInfo, destinationDirectory); + return this._executeActionAsDeferred(() => this._abortFileUploadFunction(fileData, chunksInfo, destinationDirectory)); } downloadItems(items) { return this._downloadItemsFunction(items); } - getItemContent(items) { - return this._getItemsContentFunction(items); - } - - getFileUploadChunkSize() { - return ensureDefined(this._uploadChunkSize, super.getFileUploadChunkSize()); + getItemsContent(items) { + return this._executeActionAsDeferred(() => this._getItemsContentFunction(items)); } _hasSubDirs(dataObj) { @@ -94,7 +88,6 @@ class CustomFileProvider extends FileProvider { defaultFunction = defaultFunction || noop; return isFunction(functionObject) ? functionObject : defaultFunction; } - } -module.exports = CustomFileProvider; +module.exports = CustomFileSystemProvider; diff --git a/js/file_management/errors.js b/js/file_management/errors.js new file mode 100644 index 000000000000..a8a48000471e --- /dev/null +++ b/js/file_management/errors.js @@ -0,0 +1,13 @@ +const ErrorCode = { + NoAccess: 0, + FileExists: 1, + FileNotFound: 2, + DirectoryExists: 3, + DirectoryNotFound: 4, + WrongFileExtension: 5, + MaxFileSizeExceeded: 6, + InvalidSymbols: 7, + Other: 32767 +}; + +module.exports = ErrorCode; diff --git a/js/file_management/file_system_item.d.ts b/js/file_management/file_system_item.d.ts new file mode 100644 index 000000000000..8fb35a42099f --- /dev/null +++ b/js/file_management/file_system_item.d.ts @@ -0,0 +1,84 @@ +/** + * @docid FileSystemItem + * @type object + * @module file_management/file_system_item + * @namespace DevExpress.fileManagement + * @export default + * @prevFileNamespace DevExpress.fileManagement + * @public + */ +export default class FileSystemItem { + constructor(path: string, isDirectory: boolean, pathKeys?: Array); + + /** + * @docid FileSystemItemFields.path + * @type string + * @prevFileNamespace DevExpress.fileManagement + * @public + */ + path: string; + + /** + * @docid FileSystemItemFields.pathKeys + * @type Array + * @prevFileNamespace DevExpress.fileManagement + * @public + */ + pathKeys: Array; + + /** + * @docid FileSystemItemFields.key + * @type string + * @prevFileNamespace DevExpress.fileManagement + * @public + */ + key: string; + + /** + * @docid FileSystemItemFields.name + * @type string + * @prevFileNamespace DevExpress.fileManagement + * @public + */ + name: string; + + /** + * @docid FileSystemItemFields.dateModified + * @type Date + * @prevFileNamespace DevExpress.fileManagement + * @public + */ + dateModified: Date; + + /** + * @docid FileSystemItemFields.size + * @type number + * @prevFileNamespace DevExpress.fileManagement + * @public + */ + size: number; + + /** + * @docid FileSystemItemFields.isDirectory + * @type boolean + * @prevFileNamespace DevExpress.fileManagement + * @public + */ + isDirectory: boolean; + + /** + * @docid FileSystemItemFields.thumbnail + * @type string + * @prevFileNamespace DevExpress.fileManagement + * @public + */ + thumbnail: string; + + /** + * @docid FileSystemItemFields.dataItem + * @type object + * @prevFileNamespace DevExpress.fileManagement + * @public + */ + dataItem: any; +} diff --git a/js/file_management/file_system_item.js b/js/file_management/file_system_item.js new file mode 100644 index 000000000000..db815ffaa741 --- /dev/null +++ b/js/file_management/file_system_item.js @@ -0,0 +1,104 @@ +import { isString } from '../core/utils/type'; +import { pathCombine, getFileExtension, getPathParts, getName, PATH_SEPARATOR } from './utils'; + +class FileSystemItem { + constructor() { + const ctor = isString(arguments[0]) ? this._publicCtor : this._internalCtor; + ctor.apply(this, arguments); + } + + _internalCtor(pathInfo, name, isDirectory) { + this.name = name; + + this.pathInfo = pathInfo && [...pathInfo] || []; + this.parentPath = this._getPathByPathInfo(this.pathInfo); + this.key = this.relativeName = pathCombine(this.parentPath, name); + + this.path = pathCombine(this.parentPath, name); + this.pathKeys = this.pathInfo.map(({ key }) => key); + this.pathKeys.push(this.key); + + this._initialize(isDirectory); + } + + _publicCtor(path, isDirectory, pathKeys) { + this.path = path || ''; + this.pathKeys = pathKeys || []; + + const pathInfo = []; + + const parts = getPathParts(path, true); + for(let i = 0; i < parts.length - 1; i++) { + const part = parts[i]; + const pathInfoPart = { + key: this.pathKeys[i] || part, + name: getName(part) + }; + pathInfo.push(pathInfoPart); + } + + this.pathInfo = pathInfo; + + this.relativeName = path; + this.name = getName(path); + this.key = this.pathKeys.length ? this.pathKeys[this.pathKeys.length - 1] : path; + this.parentPath = parts.length > 1 ? parts[parts.length - 2] : ''; + + this._initialize(isDirectory); + } + + _initialize(isDirectory) { + this.isDirectory = !!isDirectory; + + this.size = 0; + this.dateModified = new Date(); + + this.thumbnail = ''; + this.tooltipText = ''; + } + + getFullPathInfo() { + const pathInfo = [...this.pathInfo]; + + if(!this.isRoot()) { + pathInfo.push({ + key: this.key, + name: this.name + }); + } + + return pathInfo; + } + + isRoot() { + return this.path === ''; + } + + getExtension() { + return this.isDirectory ? '' : getFileExtension(this.name); + } + + equals(item) { + return item && this.key === item.key; + } + + createClone() { + const result = new FileSystemItem(this.pathInfo, this.name, this.isDirectory); + result.key = this.key; + result.size = this.size; + result.dateModified = this.dateModified; + result.thumbnail = this.thumbnail; + result.tooltipText = this.tooltipText; + result.hasSubDirs = this.hasSubDirs; + result.dataItem = this.dataItem; + return result; + } + + _getPathByPathInfo(pathInfo) { + return pathInfo + .map(info => info.name) + .join(PATH_SEPARATOR); + } +} + +module.exports = FileSystemItem; diff --git a/js/file_management/object_provider.d.ts b/js/file_management/object_provider.d.ts new file mode 100644 index 000000000000..ffc33d57de38 --- /dev/null +++ b/js/file_management/object_provider.d.ts @@ -0,0 +1,40 @@ +import FileSystemProviderBase, { + FileSystemProviderBaseOptions +} from './provider_base'; + +export interface ObjectFileSystemProviderOptions extends FileSystemProviderBaseOptions { + /** + * @docid ObjectFileSystemProviderOptions.contentExpr + * @type string|function(fileSystemItem) + * @prevFileNamespace DevExpress.fileManagement + * @public + */ + contentExpr?: string | Function; + /** + * @docid ObjectFileSystemProviderOptions.data + * @type Array + * @prevFileNamespace DevExpress.fileManagement + * @public + */ + data?: Array; + /** + * @docid ObjectFileSystemProviderOptions.itemsExpr + * @type string|function(fileSystemItem) + * @prevFileNamespace DevExpress.fileManagement + * @public + */ + itemsExpr?: string | Function; +} +/** + * @docid ObjectFileSystemProvider + * @inherits FileSystemProviderBase + * @type object + * @module file_management/object_provider + * @namespace DevExpress.fileManagement + * @export default + * @prevFileNamespace DevExpress.fileManagement + * @public + */ +export default class ObjectFileSystemProvider extends FileSystemProviderBase { + constructor(options?: ObjectFileSystemProviderOptions) +} diff --git a/js/ui/file_manager/file_provider/array.js b/js/file_management/object_provider.js similarity index 86% rename from js/ui/file_manager/file_provider/array.js rename to js/file_management/object_provider.js index 57a9bffc0578..6d757a902f80 100644 --- a/js/ui/file_manager/file_provider/array.js +++ b/js/file_management/object_provider.js @@ -1,21 +1,21 @@ -import { find } from '../../../core/utils/array'; -import { ensureDefined } from '../../../core/utils/common'; -import { compileGetter, compileSetter } from '../../../core/utils/data'; -import Guid from '../../../core/guid'; -import typeUtils from '../../../core/utils/type'; -import { errors } from '../../../data/errors'; -import { Deferred } from '../../../core/utils/deferred'; -import { getWindow } from '../../../core/utils/window'; -import { fileSaver } from '../../../exporter/file_saver'; -import Errors from '../../widget/ui.errors'; - -import { FileProvider } from './file_provider'; -import { ErrorCode } from '../ui.file_manager.common'; -import { pathCombine } from '../ui.file_manager.utils'; +import { find } from '../core/utils/array'; +import { ensureDefined } from '../core/utils/common'; +import { compileGetter, compileSetter } from '../core/utils/data'; +import Guid from '../core/guid'; +import typeUtils from '../core/utils/type'; +import { errors } from '../data/errors'; +import { Deferred } from '../core/utils/deferred'; +import { getWindow } from '../core/utils/window'; +import { fileSaver } from '../exporter/file_saver'; +import Errors from '../ui/widget/ui.errors'; + +import FileSystemProviderBase from './provider_base'; +import ErrorCode from './errors'; +import { pathCombine } from './utils'; const window = getWindow(); -class ArrayFileProvider extends FileProvider { +class ObjectFileSystemProvider extends FileSystemProviderBase { constructor(options) { options = ensureDefined(options, { }); @@ -53,11 +53,15 @@ class ArrayFileProvider extends FileProvider { this._data = initialArray || [ ]; } - getItems(pathInfo) { - return this._getItems(pathInfo); + getItems(parentDir) { + return this._executeActionAsDeferred(() => this._getItems(parentDir), true); } renameItem(item, name) { + return this._executeActionAsDeferred(() => this._renameItemCore(item, name)); + } + + _renameItemCore(item, name) { if(!item) { return; } @@ -66,34 +70,44 @@ class ArrayFileProvider extends FileProvider { item.key = this._ensureDataObjectKey(item.dataItem); } - createFolder(parentDir, name) { - this._validateDirectoryExists(parentDir); - this._createDataObject(parentDir, name, true); + createDirectory(parentDir, name) { + return this._executeActionAsDeferred(() => { + this._validateDirectoryExists(parentDir); + this._createDataObject(parentDir, name, true); + }); } deleteItems(items) { - items.forEach(item => this._deleteItem(item)); + return items.map(item => this._executeActionAsDeferred(() => this._deleteItem(item))); } moveItems(items, destinationDir) { const array = this._getDirectoryDataItems(destinationDir.dataItem); - items.forEach(item => { + + const deferreds = items.map(item => this._executeActionAsDeferred(() => { this._checkAbilityToMoveOrCopyItem(item, destinationDir); this._deleteItem(item); array.push(item.dataItem); - }); + })); + this._updateHasSubDirs(destinationDir); + + return deferreds; } copyItems(items, destinationDir) { const array = this._getDirectoryDataItems(destinationDir.dataItem); - items.forEach(item => { + + const deferreds = items.map(item => this._executeActionAsDeferred(() => { this._checkAbilityToMoveOrCopyItem(item, destinationDir); const copiedItem = this._createCopy(item.dataItem); array.push(copiedItem); - }); + })); + this._updateHasSubDirs(destinationDir); + + return deferreds; } uploadFileChunk(fileData, chunksInfo, destinationDirectory) { @@ -260,7 +274,8 @@ class ArrayFileProvider extends FileProvider { return dataItems; } - _getItems(pathInfo) { + _getItems(parentDir) { + const pathInfo = parentDir.getFullPathInfo(); const parentDirKey = pathInfo && pathInfo.length > 0 ? pathInfo[pathInfo.length - 1].key : null; let dirFileObjects = this._data; if(parentDirKey) { @@ -328,7 +343,7 @@ class ArrayFileProvider extends FileProvider { } _updateHasSubDirs(dir) { - if(dir && !dir.isRoot) { + if(dir && !dir.isRoot()) { dir.hasSubDirs = this._hasSubDirs(dir.dataItem); } } @@ -353,7 +368,7 @@ class ArrayFileProvider extends FileProvider { } _isFileItemExists(fileItem) { - return fileItem.isDirectory && fileItem.isRoot || !!this._findFileItemObj(fileItem.getFullPathInfo()); + return fileItem.isDirectory && fileItem.isRoot() || !!this._findFileItemObj(fileItem.getFullPathInfo()); } _createFileReader() { @@ -383,4 +398,4 @@ function requestJSZip() { return jsZip; } -module.exports = ArrayFileProvider; +module.exports = ObjectFileSystemProvider; diff --git a/js/file_management/provider_base.d.ts b/js/file_management/provider_base.d.ts new file mode 100644 index 000000000000..28aa33a9d16b --- /dev/null +++ b/js/file_management/provider_base.d.ts @@ -0,0 +1,166 @@ +import '../jquery_augmentation'; +import FileSystemItem from './file_system_item'; + +export interface FileSystemProviderBaseOptions { + /** + * @docid FileSystemProviderBaseOptions.dateModifiedExpr + * @type string|function(fileSystemItem) + * @prevFileNamespace DevExpress.fileManagement + * @public + */ + dateModifiedExpr?: string | Function; + /** + * @docid FileSystemProviderBaseOptions.isDirectoryExpr + * @type string|function(fileSystemItem) + * @prevFileNamespace DevExpress.fileManagement + * @public + */ + isDirectoryExpr?: string | Function; + /** + * @docid FileSystemProviderBaseOptions.keyExpr + * @type string|function(fileSystemItem) + * @prevFileNamespace DevExpress.fileManagement + * @public + */ + keyExpr?: string | Function; + /** + * @docid FileSystemProviderBaseOptions.nameExpr + * @type string|function(fileSystemItem) + * @prevFileNamespace DevExpress.fileManagement + * @public + */ + nameExpr?: string | Function; + /** + * @docid FileSystemProviderBaseOptions.sizeExpr + * @type string|function(fileSystemItem) + * @prevFileNamespace DevExpress.fileManagement + * @public + */ + sizeExpr?: string | Function; + /** + * @docid FileSystemProviderBaseOptions.thumbnailExpr + * @type string|function(fileSystemItem) + * @prevFileNamespace DevExpress.fileManagement + * @public + */ + thumbnailExpr?: string | Function; +} +/** + * @docid FileSystemProviderBase + * @type object + * @module file_management/provider_base + * @namespace DevExpress.fileManagement + * @export default + * @hidden + * @prevFileNamespace DevExpress.fileManagement + */ +export default class FileSystemProviderBase { + constructor(options?: FileSystemProviderBaseOptions) + /** + * @docid FileSystemProviderBaseMethods.getItems + * @publicName getItems() + * @param1 parentDirectory:FileSystemItem + * @return Promise> + * @prevFileNamespace DevExpress.fileManagement + * @public + */ + getItems(parentDirectory: FileSystemItem): Promise> & JQueryPromise>; + + /** + * @docid FileSystemProviderBaseMethods.renameItem + * @publicName renameItem() + * @param1 item:FileSystemItem + * @param2 newName:string + * @return Promise + * @prevFileNamespace DevExpress.fileManagement + * @public + */ + renameItem(item: FileSystemItem, newName: string): Promise & JQueryPromise; + + /** + * @docid FileSystemProviderBaseMethods.createDirectory + * @publicName createDirectory() + * @param1 parentDirectory:FileSystemItem + * @param2 name:string + * @return Promise + * @prevFileNamespace DevExpress.fileManagement + * @public + */ + createDirectory(parentDirectory: FileSystemItem, name: string): Promise & JQueryPromise; + + /** + * @docid FileSystemProviderBaseMethods.deleteItems + * @publicName deleteItems() + * @param1 items:Array + * @return Array> + * @prevFileNamespace DevExpress.fileManagement + * @public + */ + deleteItems(items: Array): Array & JQueryPromise>; + + /** + * @docid FileSystemProviderBaseMethods.moveItems + * @publicName moveItems() + * @param1 items:Array + * @param2 destinationDirectory:FileSystemItem + * @return Array> + * @prevFileNamespace DevExpress.fileManagement + * @public + */ + moveItems(items: Array, destinationDirectory: FileSystemItem): Array & JQueryPromise>; + + /** + * @docid FileSystemProviderBaseMethods.copyItems + * @publicName copyItems() + * @param1 items:Array + * @param2 destinationDirectory:FileSystemItem + * @return Array> + * @prevFileNamespace DevExpress.fileManagement + * @public + */ + copyItems(items: Array, destinationDirectory: FileSystemItem): Array & JQueryPromise>; + + /** + * @docid FileSystemProviderBaseMethods.uploadFileChunk + * @publicName uploadFileChunk() + * @param1 fileData:File + * @param2 uploadInfo:object + * @param3 destinationDirectory:FileSystemItem + * @return Promise + * @prevFileNamespace DevExpress.fileManagement + * @public + */ + uploadFileChunk(fileData: File, uploadInfo: any, destinationDirectory: FileSystemItem): Promise & JQueryPromise; + + /** + * @docid FileSystemProviderBaseMethods.abortFileUpload + * @publicName abortFileUpload() + * @param1 fileData:File + * @param2 uploadInfo:object + * @param3 destinationDirectory:FileSystemItem + * @return Promise + * @prevFileNamespace DevExpress.fileManagement + * @public + */ + abortFileUpload(fileData: File, uploadInfo: any, destinationDirectory: FileSystemItem): Promise & JQueryPromise; + + /** + * @docid FileSystemProviderBaseMethods.downloadItems + * @publicName downloadItems() + * @param1 items:Array + * @return any + * @prevFileNamespace DevExpress.fileManagement + * @public + */ + downloadItems(items: Array): any; + + /** + * @docid FileSystemProviderBaseMethods.getItemsContent + * @publicName getItemsContent() + * @param1 items:Array + * @return Promise + * @prevFileNamespace DevExpress.fileManagement + * @public + */ + getItemsContent(items: Array): Promise & JQueryPromise; +} diff --git a/js/ui/file_manager/file_provider/file_provider.js b/js/file_management/provider_base.js similarity index 53% rename from js/ui/file_manager/file_provider/file_provider.js rename to js/file_management/provider_base.js index 1d7b8907d9cd..914d9a31bd28 100644 --- a/js/ui/file_manager/file_provider/file_provider.js +++ b/js/file_management/provider_base.js @@ -1,12 +1,14 @@ -import { compileGetter } from '../../../core/utils/data'; -import { pathCombine, getFileExtension, PATH_SEPARATOR } from '../ui.file_manager.utils'; -import { ensureDefined } from '../../../core/utils/common'; -import { deserializeDate } from '../../../core/utils/date_serialization'; -import { each } from '../../../core/utils/iterator'; +import { compileGetter } from '../core/utils/data'; +import { ensureDefined } from '../core/utils/common'; +import { deserializeDate } from '../core/utils/date_serialization'; +import { each } from '../core/utils/iterator'; +import { isPromise } from '../core/utils/type'; +import { Deferred } from '../core/utils/deferred'; +import FileSystemItem from './file_system_item'; const DEFAULT_FILE_UPLOAD_CHUNK_SIZE = 200000; -class FileProvider { +class FileSystemProviderBase { constructor(options) { options = ensureDefined(options, {}); @@ -19,23 +21,23 @@ class FileProvider { this._thumbnailGetter = compileGetter(options.thumbnailExpr || 'thumbnail'); } - getItems(pathInfo) { + getItems(parentDirectory) { return []; } renameItem(item, name) { } - createFolder(parentFolder, name) { + createDirectory(parentDirectory, name) { } deleteItems(items) { } - moveItems(items, destinationFolder) { + moveItems(items, destinationDirectory) { } - copyItems(items, destinationFolder) { + copyItems(items, destinationDirectory) { } uploadFileChunk(fileData, chunksInfo, destinationDirectory) { @@ -47,7 +49,7 @@ class FileProvider { downloadItems(items) { } - getItemContent(items) { + getItemsContent(items) { } getFileUploadChunkSize() { @@ -67,7 +69,7 @@ class FileProvider { return result; } _createFileItem(dataObj, pathInfo) { - const fileItem = new FileManagerItem(pathInfo, this._nameGetter(dataObj), !!this._isDirGetter(dataObj)); + const fileItem = new FileSystemItem(pathInfo, this._nameGetter(dataObj), !!this._isDirGetter(dataObj)); fileItem.size = this._sizeGetter(dataObj); if(fileItem.size === undefined) { @@ -125,71 +127,26 @@ class FileProvider { return options.dateModifiedExpr || 'dateModified'; } -} - -class FileManagerItem { - constructor(pathInfo, name, isDirectory) { - this.name = name; - - this.pathInfo = pathInfo && [...pathInfo] || []; - this.parentPath = this._getPathByPathInfo(this.pathInfo); - this.key = this.relativeName = pathCombine(this.parentPath, name); - - this.isDirectory = isDirectory || false; - this.isRoot = false; - - this.size = 0; - this.dateModified = new Date(); - - this.thumbnail = ''; - this.tooltipText = ''; - } - - getFullPathInfo() { - const pathInfo = [...this.pathInfo]; - !this.isRoot && pathInfo.push({ - key: this.key, - name: this.name - }); - return pathInfo; - } + _executeActionAsDeferred(action, keepResult) { + const deferred = new Deferred(); - getExtension() { - return this.isDirectory ? '' : getFileExtension(this.name); - } + try { + const result = action(); - equals(item) { - return item && this.key === item.key; - } + if(isPromise(result)) { + result + .done(userResult => deferred.resolve(keepResult && userResult || undefined)) + .fail(error => deferred.reject(error)); + } else { + deferred.resolve(keepResult && result || undefined); + } - createClone() { - const result = new FileManagerItem(this.pathInfo, this.name, this.isDirectory); - result.key = this.key; - result.size = this.size; - result.dateModified = this.dateModified; - result.thumbnail = this.thumbnail; - result.tooltipText = this.tooltipText; - result.hasSubDirs = this.hasSubDirs; - result.dataItem = this.dataItem; - return result; - } - - _getPathByPathInfo(pathInfo) { - return pathInfo - .map(info => info.name) - .join(PATH_SEPARATOR); - } -} + } catch(error) { + return deferred.reject(error); + } -class FileManagerRootItem extends FileManagerItem { - constructor() { - super(null, 'Files', true); - this.key = '__dxfmroot_394CED1B-58CF-4925-A5F8-042BC0822B31_51558CB8-C170-4655-A9E0-C454ED8EA2C1'; - this.relativeName = ''; - this.isRoot = true; + return deferred.promise(); } } -module.exports.FileProvider = FileProvider; -module.exports.FileManagerItem = FileManagerItem; -module.exports.FileManagerRootItem = FileManagerRootItem; +module.exports = FileSystemProviderBase; diff --git a/js/file_management/remote_provider.d.ts b/js/file_management/remote_provider.d.ts new file mode 100644 index 000000000000..8b21bcc73026 --- /dev/null +++ b/js/file_management/remote_provider.d.ts @@ -0,0 +1,33 @@ +import FileSystemProviderBase, { + FileSystemProviderBaseOptions +} from './provider_base'; + +export interface RemoteFileSystemProviderOptions extends FileSystemProviderBaseOptions { + /** + * @docid RemoteFileSystemProviderOptions.endpointUrl + * @type string + * @prevFileNamespace DevExpress.fileManagement + * @public + */ + endpointUrl?: string; + /** + * @docid RemoteFileSystemProviderOptions.hasSubDirectoriesExpr + * @type string|function(fileSystemItem) + * @prevFileNamespace DevExpress.fileManagement + * @public + */ + hasSubDirectoriesExpr?: string | Function; +} +/** + * @docid RemoteFileSystemProvider + * @inherits FileSystemProviderBase + * @type object + * @module file_management/remote_provider + * @namespace DevExpress.fileManagement + * @export default + * @prevFileNamespace DevExpress.fileManagement + * @public + */ +export default class RemoteFileSystemProvider extends FileSystemProviderBase { + constructor(options?: RemoteFileSystemProviderOptions) +} diff --git a/js/ui/file_manager/file_provider/remote.js b/js/file_management/remote_provider.js similarity index 89% rename from js/ui/file_manager/file_provider/remote.js rename to js/file_management/remote_provider.js index 0474169f1a34..66626f7c6cae 100644 --- a/js/ui/file_manager/file_provider/remote.js +++ b/js/file_management/remote_provider.js @@ -1,19 +1,19 @@ -import $ from '../../../core/renderer'; -import ajax from '../../../core/utils/ajax'; -import { ensureDefined, noop } from '../../../core/utils/common'; -import Guid from '../../../core/guid'; -import { getWindow } from '../../../core/utils/window'; -import { each } from '../../../core/utils/iterator'; -import { Deferred } from '../../../core/utils/deferred'; -import eventsEngine from '../../../events/core/events_engine'; - -import { FileProvider } from './file_provider'; -import { compileGetter } from '../../../core/utils/data'; +import $ from '../core/renderer'; +import ajax from '../core/utils/ajax'; +import { ensureDefined, noop } from '../core/utils/common'; +import Guid from '../core/guid'; +import { getWindow } from '../core/utils/window'; +import { each } from '../core/utils/iterator'; +import { Deferred } from '../core/utils/deferred'; +import eventsEngine from '../events/core/events_engine'; + +import FileSystemProviderBase from './provider_base'; +import { compileGetter } from '../core/utils/data'; const window = getWindow(); const FILE_CHUNK_BLOB_NAME = 'chunk'; -class RemoteFileProvider extends FileProvider { +class RemoteFileSystemProvider extends FileSystemProviderBase { constructor(options) { options = ensureDefined(options, { }); @@ -22,7 +22,8 @@ class RemoteFileProvider extends FileProvider { this._hasSubDirsGetter = compileGetter(options.hasSubDirectoriesExpr || 'hasSubDirectories'); } - getItems(pathInfo) { + getItems(parentDir) { + const pathInfo = parentDir.getFullPathInfo(); return this._getEntriesByPath(pathInfo) .then(result => this._convertDataObjectsToFileItems(result.result, pathInfo)); } @@ -34,12 +35,12 @@ class RemoteFileProvider extends FileProvider { }); } - createFolder(parentDir, name) { + createDirectory(parentDir, name) { return this._executeRequest('CreateDir', { pathInfo: parentDir.getFullPathInfo(), name }).done(() => { - if(parentDir && !parentDir.isRoot) { + if(parentDir && !parentDir.isRoot()) { parentDir.hasSubDirs = true; } }); @@ -134,7 +135,7 @@ class RemoteFileProvider extends FileProvider { setTimeout(() => $form.remove()); } - getItemContent(items) { + getItemsContent(items) { const args = this._getDownloadArgs(items); const formData = new window.FormData(); @@ -248,4 +249,4 @@ class RemoteFileProvider extends FileProvider { } -module.exports = RemoteFileProvider; +module.exports = RemoteFileSystemProvider; diff --git a/js/file_management/upload_info.d.ts b/js/file_management/upload_info.d.ts new file mode 100644 index 000000000000..bf7e8c84a7c0 --- /dev/null +++ b/js/file_management/upload_info.d.ts @@ -0,0 +1,50 @@ +/** + * @docid UploadInfo + * @type object + * @module file_management/upload_info + * @namespace DevExpress.fileManagement + * @export default + * @prevFileNamespace DevExpress.fileManagement + * @hidden + */ +export default interface UploadInfo { + /** + * @docid UploadInfo.bytesUploaded + * @type Number + * @prevFileNamespace DevExpress.fileManagement + * @public + */ + bytesUploaded: number; + + /** + * @docid UploadInfo.chunkCount + * @type Number + * @prevFileNamespace DevExpress.fileManagement + * @public + */ + chunkCount: number; + + /** + * @docid UploadInfo.customData + * @type object + * @prevFileNamespace DevExpress.fileManagement + * @public + */ + customData: any; + + /** + * @docid UploadInfo.chunkBlob + * @type Blob + * @prevFileNamespace DevExpress.fileManagement + * @public + */ + chunkBlob: Blob; + + /** + * @docid UploadInfo.chunkIndex + * @type Number + * @prevFileNamespace DevExpress.fileManagement + * @public + */ + chunkIndex: number; +} \ No newline at end of file diff --git a/js/ui/file_manager/ui.file_manager.utils.js b/js/file_management/utils.js similarity index 80% rename from js/ui/file_manager/ui.file_manager.utils.js rename to js/file_management/utils.js index 7f09f855d39c..8d0b0b2d5612 100644 --- a/js/ui/file_manager/ui.file_manager.utils.js +++ b/js/file_management/utils.js @@ -1,4 +1,4 @@ -import { each } from '../../core/utils/iterator'; +import { each } from '../core/utils/iterator'; const PATH_SEPARATOR = '/'; @@ -73,23 +73,10 @@ const pathCombine = function() { return result; }; -const getDisplayFileSize = function(byteSize) { - const sizesTitles = [ 'B', 'KB', 'MB', 'GB', 'TB' ]; - let index = 0; - let displaySize = byteSize; - while(displaySize >= 1024 && index <= sizesTitles.length - 1) { - displaySize /= 1024; - index++; - } - displaySize = Math.round(displaySize * 10) / 10; - return `${displaySize} ${sizesTitles[index]}`; -}; - module.exports.getFileExtension = getFileExtension; module.exports.getName = getName; module.exports.getParentPath = getParentPath; module.exports.getPathParts = getPathParts; module.exports.getEscapedFileName = getEscapedFileName; module.exports.pathCombine = pathCombine; -module.exports.getDisplayFileSize = getDisplayFileSize; module.exports.PATH_SEPARATOR = PATH_SEPARATOR; diff --git a/js/localization/messages/de.json b/js/localization/messages/de.json index 4fc7365fc3d5..caad1b2062af 100644 --- a/js/localization/messages/de.json +++ b/js/localization/messages/de.json @@ -270,11 +270,11 @@ "dxFileManager-errorMaxFileSizeExceeded": "Die Dateigröße übersteigt die maximal erlaubte Größe.", "dxFileManager-errorInvalidSymbols": "Der Dateiname enthält ungültige Zeichen.", "dxFileManager-errorDefault": "Unbekannter Fehler", - + "dxFileManager-commandCreate": "Neues Verzeichnis", "dxFileManager-commandRename": "Umbenennen", - "dxFileManager-commandMove": "Verschieben", - "dxFileManager-commandCopy": "Kopieren", + "dxFileManager-commandMove": "TODO", + "dxFileManager-commandCopy": "TODO", "dxFileManager-commandDelete": "Löschen", "dxFileManager-commandDownload": "Herunterladen", "dxFileManager-commandUpload": "Dateien hochladen", @@ -283,8 +283,10 @@ "dxFileManager-commandDetails": "Detailansicht", "dxFileManager-commandClear": "Auswahl aufheben", - "dxFileManager-dialogDirectoryChooserTitle": "Zielverzeichnis auswählen", - "dxFileManager-dialogDirectoryChooserButtonText": "Auswählen", + "dxFileManager-dialogDirectoryChooserMoveTitle": "TODO", + "dxFileManager-dialogDirectoryChooserMoveButtonText": "Verschieben", + "dxFileManager-dialogDirectoryChooserCopyTitle": "TODO", + "dxFileManager-dialogDirectoryChooserCopyButtonText": "Kopieren", "dxFileManager-dialogRenameItemTitle": "Umbenennen", "dxFileManager-dialogRenameItemButtonText": "Speichern", "dxFileManager-dialogCreateDirectoryTitle": "Neues Verzeichnis", diff --git a/js/localization/messages/en.json b/js/localization/messages/en.json index dabbe15ba227..620f789c1fac 100644 --- a/js/localization/messages/en.json +++ b/js/localization/messages/en.json @@ -303,77 +303,79 @@ "dxFileManager-errorInvalidSymbols": "This name contains invalid characters.", "dxFileManager-errorDefault": "Unspecified error.", - "dxFileManager-commandCreate": "New directory", - "dxFileManager-commandRename": "Rename", - "dxFileManager-commandMove": "Move", - "dxFileManager-commandCopy": "Copy", - "dxFileManager-commandDelete": "Delete", - "dxFileManager-commandDownload": "Download", - "dxFileManager-commandUpload": "Upload files", - "dxFileManager-commandRefresh": "Refresh", - "dxFileManager-commandThumbnails": "Thumbnails View", - "dxFileManager-commandDetails": "Details View", - "dxFileManager-commandClear": "Clear selection", - - "dxFileManager-dialogDirectoryChooserTitle": "Select Destination Directory", - "dxFileManager-dialogDirectoryChooserButtonText": "Select", - "dxFileManager-dialogRenameItemTitle": "Rename", - "dxFileManager-dialogRenameItemButtonText": "Save", - "dxFileManager-dialogCreateDirectoryTitle": "New directory", - "dxFileManager-dialogCreateDirectoryButtonText": "Create", - - "dxFileManager-editingCreateSingleItemProcessingMessage": "Creating a directory inside {0}", - "dxFileManager-editingCreateSingleItemSuccessMessage": "Created a directory inside {0}", - "dxFileManager-editingCreateSingleItemErrorMessage": "Directory wasn't created", - "dxFileManager-editingCreateCommonErrorMessage": "Directory wasn't created", - - "dxFileManager-editingRenameSingleItemProcessingMessage": "Renaming an item inside {0}", - "dxFileManager-editingRenameSingleItemSuccessMessage": "Renamed an item inside {0}", - "dxFileManager-editingRenameSingleItemErrorMessage": "Item wasn't renamed", - "dxFileManager-editingRenameCommonErrorMessage": "Item wasn't renamed", - - "dxFileManager-editingDeleteSingleItemProcessingMessage": "Deleting an item from {0}", - "dxFileManager-editingDeleteMultipleItemsProcessingMessage": "Deleting {0} items from {1}", - "dxFileManager-editingDeleteSingleItemSuccessMessage": "Deleted an item from {0}", - "dxFileManager-editingDeleteMultipleItemsSuccessMessage": "Deleted {0} items from {1}", - "dxFileManager-editingDeleteSingleItemErrorMessage": "Item wasn't deleted", - "dxFileManager-editingDeleteMultipleItemsErrorMessage": "{0} items weren't deleted", - "dxFileManager-editingDeleteCommonErrorMessage": "Some items weren't deleted", - - "dxFileManager-editingMoveSingleItemProcessingMessage": "Moving an item to {0}", - "dxFileManager-editingMoveMultipleItemsProcessingMessage": "Moving {0} items to {1}", - "dxFileManager-editingMoveSingleItemSuccessMessage": "Moved an item to {0}", - "dxFileManager-editingMoveMultipleItemsSuccessMessage": "Moved {0} items to {1}", - "dxFileManager-editingMoveSingleItemErrorMessage": "Item wasn't moved", - "dxFileManager-editingMoveMultipleItemsErrorMessage": "{0} items weren't moved", - "dxFileManager-editingMoveCommonErrorMessage": "Some items weren't moved", - - "dxFileManager-editingCopySingleItemProcessingMessage": "Copying an item to {0}", - "dxFileManager-editingCopyMultipleItemsProcessingMessage": "Copying {0} items to {1}", - "dxFileManager-editingCopySingleItemSuccessMessage": "Copied an item to {0}", - "dxFileManager-editingCopyMultipleItemsSuccessMessage": "Copied {0} items to {1}", - "dxFileManager-editingCopySingleItemErrorMessage": "Item wasn't copied", - "dxFileManager-editingCopyMultipleItemsErrorMessage": "{0} items weren't copied", - "dxFileManager-editingCopyCommonErrorMessage": "Some items weren't copied", - - "dxFileManager-editingUploadSingleItemProcessingMessage": "Uploading an item to {0}", - "dxFileManager-editingUploadMultipleItemsProcessingMessage": "Uploading {0} items to {1}", - "dxFileManager-editingUploadSingleItemSuccessMessage": "Uploaded an item to {0}", - "dxFileManager-editingUploadMultipleItemsSuccessMessage": "Uploaded {0} items to {1}", - "dxFileManager-editingUploadSingleItemErrorMessage": "Item wasn't uploaded", - "dxFileManager-editingUploadMultipleItemsErrorMessage": "{0} items weren't uploaded", - "dxFileManager-editingUploadCanceledMessage": "Canceled", - - "dxFileManager-listDetailsColumnCaptionName": "Name", - "dxFileManager-listDetailsColumnCaptionDateModified": "Date Modified", - "dxFileManager-listDetailsColumnCaptionFileSize": "File Size", - - "dxFileManager-listThumbnailsTooltipTextSize": "Size", - "dxFileManager-listThumbnailsTooltipTextDateModified": "Date Modified", - - "dxFileManager-notificationProgressPanelTitle": "Progress", - "dxFileManager-notificationProgressPanelEmptyListText": "No operations", - "dxFileManager-notificationProgressPanelOperationCanceled": "Canceled", + "dxFileManager-commandCreate": "New directory", + "dxFileManager-commandRename": "Rename", + "dxFileManager-commandMove": "Move to", + "dxFileManager-commandCopy": "Copy to", + "dxFileManager-commandDelete": "Delete", + "dxFileManager-commandDownload": "Download", + "dxFileManager-commandUpload": "Upload files", + "dxFileManager-commandRefresh": "Refresh", + "dxFileManager-commandThumbnails": "Thumbnails View", + "dxFileManager-commandDetails": "Details View", + "dxFileManager-commandClear": "Clear selection", + + "dxFileManager-dialogDirectoryChooserMoveTitle": "Move to", + "dxFileManager-dialogDirectoryChooserMoveButtonText": "Move", + "dxFileManager-dialogDirectoryChooserCopyTitle": "Copy to", + "dxFileManager-dialogDirectoryChooserCopyButtonText": "Copy", + "dxFileManager-dialogRenameItemTitle": "Rename", + "dxFileManager-dialogRenameItemButtonText": "Save", + "dxFileManager-dialogCreateDirectoryTitle": "New directory", + "dxFileManager-dialogCreateDirectoryButtonText": "Create", + + "dxFileManager-editingCreateSingleItemProcessingMessage": "Creating a directory inside {0}", + "dxFileManager-editingCreateSingleItemSuccessMessage": "Created a directory inside {0}", + "dxFileManager-editingCreateSingleItemErrorMessage": "Directory wasn't created", + "dxFileManager-editingCreateCommonErrorMessage": "Directory wasn't created", + + "dxFileManager-editingRenameSingleItemProcessingMessage": "Renaming an item inside {0}", + "dxFileManager-editingRenameSingleItemSuccessMessage": "Renamed an item inside {0}", + "dxFileManager-editingRenameSingleItemErrorMessage": "Item wasn't renamed", + "dxFileManager-editingRenameCommonErrorMessage": "Item wasn't renamed", + + "dxFileManager-editingDeleteSingleItemProcessingMessage": "Deleting an item from {0}", + "dxFileManager-editingDeleteMultipleItemsProcessingMessage": "Deleting {0} items from {1}", + "dxFileManager-editingDeleteSingleItemSuccessMessage": "Deleted an item from {0}", + "dxFileManager-editingDeleteMultipleItemsSuccessMessage": "Deleted {0} items from {1}", + "dxFileManager-editingDeleteSingleItemErrorMessage": "Item wasn't deleted", + "dxFileManager-editingDeleteMultipleItemsErrorMessage": "{0} items weren't deleted", + "dxFileManager-editingDeleteCommonErrorMessage": "Some items weren't deleted", + + "dxFileManager-editingMoveSingleItemProcessingMessage": "Moving an item to {0}", + "dxFileManager-editingMoveMultipleItemsProcessingMessage": "Moving {0} items to {1}", + "dxFileManager-editingMoveSingleItemSuccessMessage": "Moved an item to {0}", + "dxFileManager-editingMoveMultipleItemsSuccessMessage": "Moved {0} items to {1}", + "dxFileManager-editingMoveSingleItemErrorMessage": "Item wasn't moved", + "dxFileManager-editingMoveMultipleItemsErrorMessage": "{0} items weren't moved", + "dxFileManager-editingMoveCommonErrorMessage": "Some items weren't moved", + + "dxFileManager-editingCopySingleItemProcessingMessage": "Copying an item to {0}", + "dxFileManager-editingCopyMultipleItemsProcessingMessage": "Copying {0} items to {1}", + "dxFileManager-editingCopySingleItemSuccessMessage": "Copied an item to {0}", + "dxFileManager-editingCopyMultipleItemsSuccessMessage": "Copied {0} items to {1}", + "dxFileManager-editingCopySingleItemErrorMessage": "Item wasn't copied", + "dxFileManager-editingCopyMultipleItemsErrorMessage": "{0} items weren't copied", + "dxFileManager-editingCopyCommonErrorMessage": "Some items weren't copied", + + "dxFileManager-editingUploadSingleItemProcessingMessage": "Uploading an item to {0}", + "dxFileManager-editingUploadMultipleItemsProcessingMessage": "Uploading {0} items to {1}", + "dxFileManager-editingUploadSingleItemSuccessMessage": "Uploaded an item to {0}", + "dxFileManager-editingUploadMultipleItemsSuccessMessage": "Uploaded {0} items to {1}", + "dxFileManager-editingUploadSingleItemErrorMessage": "Item wasn't uploaded", + "dxFileManager-editingUploadMultipleItemsErrorMessage": "{0} items weren't uploaded", + "dxFileManager-editingUploadCanceledMessage": "Canceled", + + "dxFileManager-listDetailsColumnCaptionName": "Name", + "dxFileManager-listDetailsColumnCaptionDateModified": "Date Modified", + "dxFileManager-listDetailsColumnCaptionFileSize": "File Size", + + "dxFileManager-listThumbnailsTooltipTextSize": "Size", + "dxFileManager-listThumbnailsTooltipTextDateModified": "Date Modified", + + "dxFileManager-notificationProgressPanelTitle": "Progress", + "dxFileManager-notificationProgressPanelEmptyListText": "No operations", + "dxFileManager-notificationProgressPanelOperationCanceled": "Canceled", "dxDiagram-categoryGeneral": "General", "dxDiagram-categoryFlowchart": "Flowchart", diff --git a/js/localization/messages/ja.json b/js/localization/messages/ja.json index 49eb63d7ea42..5df415f5ab05 100644 --- a/js/localization/messages/ja.json +++ b/js/localization/messages/ja.json @@ -110,11 +110,11 @@ "dxDataGrid-editingSaveAllChanges": "変更を保存", "dxDataGrid-editingCancelAllChanges": "変更を破棄", "dxDataGrid-editingAddRow": "行を追加", - "dxDataGrid-summaryMin": "Min: {0}", + "dxDataGrid-summaryMin": "最小: {0}", "dxDataGrid-summaryMinOtherColumn": "{1} の最小は {0}", - "dxDataGrid-summaryMax": "Max: {0}", + "dxDataGrid-summaryMax": "最大: {0}", "dxDataGrid-summaryMaxOtherColumn": "{1} の最小は {0}", - "dxDataGrid-summaryAvg": "Avg: {0}", + "dxDataGrid-summaryAvg": "平均: {0}", "dxDataGrid-summaryAvgOtherColumn": "{1} の平均は {0}", "dxDataGrid-summarySum": "合計: {0}", "dxDataGrid-summarySumOtherColumn": "{1} の合計は {0}", @@ -270,11 +270,11 @@ "dxFileManager-errorMaxFileSizeExceeded": "ファイルのサイズが最大許容サイズを超えています。", "dxFileManager-errorInvalidSymbols": "名前に無効な文字が含まれています。", "dxFileManager-errorDefault": "特定できないエラー", - + "dxFileManager-commandCreate": "新しいディレクトリ", "dxFileManager-commandRename": "名前の変更", - "dxFileManager-commandMove": "移動", - "dxFileManager-commandCopy": "コピー", + "dxFileManager-commandMove": "TODO", + "dxFileManager-commandCopy": "TODO", "dxFileManager-commandDelete": "削除", "dxFileManager-commandDownload": "ダウンロード", "dxFileManager-commandUpload": "ファイルのアップロード", @@ -283,8 +283,10 @@ "dxFileManager-commandDetails": "詳細表示", "dxFileManager-commandClear": "選択のクリア", - "dxFileManager-dialogDirectoryChooserTitle": "移動先のディレクトリを選択してください", - "dxFileManager-dialogDirectoryChooserButtonText": "選択", + "dxFileManager-dialogDirectoryChooserMoveTitle": "TODO", + "dxFileManager-dialogDirectoryChooserMoveButtonText": "移動", + "dxFileManager-dialogDirectoryChooserCopyTitle": "TODO", + "dxFileManager-dialogDirectoryChooserCopyButtonText": "コピー", "dxFileManager-dialogRenameItemTitle": "名前の変更", "dxFileManager-dialogRenameItemButtonText": "保存", "dxFileManager-dialogCreateDirectoryTitle": "新しいディレクトリ", diff --git a/js/localization/messages/ru.json b/js/localization/messages/ru.json index f5fdf64c9982..6d24f628001b 100644 --- a/js/localization/messages/ru.json +++ b/js/localization/messages/ru.json @@ -270,77 +270,79 @@ "dxFileManager-errorInvalidSymbols": "Введённое имя содержит недопустимые символы.", "dxFileManager-errorDefault": "Неизвестная ошибка", - "dxFileManager-commandCreate": "Новая папка", - "dxFileManager-commandRename": "Переименовать", - "dxFileManager-commandMove": "Переместить", - "dxFileManager-commandCopy": "Копировать", - "dxFileManager-commandDelete": "Удалить", - "dxFileManager-commandDownload": "Скачать", - "dxFileManager-commandUpload": "Загрузить файлы", - "dxFileManager-commandRefresh": "Обновить", - "dxFileManager-commandThumbnails": "Режим эксизов", - "dxFileManager-commandDetails": "Режим списка", - "dxFileManager-commandClear": "Очистить выделение", + "dxFileManager-commandCreate": "Новая папка", + "dxFileManager-commandRename": "Переименовать", + "dxFileManager-commandMove": "Переместить в", + "dxFileManager-commandCopy": "Копировать в", + "dxFileManager-commandDelete": "Удалить", + "dxFileManager-commandDownload": "Скачать", + "dxFileManager-commandUpload": "Загрузить файлы", + "dxFileManager-commandRefresh": "Обновить", + "dxFileManager-commandThumbnails": "Режим эксизов", + "dxFileManager-commandDetails": "Режим списка", + "dxFileManager-commandClear": "Очистить выделение", - "dxFileManager-dialogDirectoryChooserTitle": "Выберите папку назначения", - "dxFileManager-dialogDirectoryChooserButtonText": "Выбрать", - "dxFileManager-dialogRenameItemTitle": "Переименовать", - "dxFileManager-dialogRenameItemButtonText": "Сохранить", - "dxFileManager-dialogCreateDirectoryTitle": "Новая папка", - "dxFileManager-dialogCreateDirectoryButtonText": "Создать", + "dxFileManager-dialogDirectoryChooserMoveTitle": "Переместить в", + "dxFileManager-dialogDirectoryChooserMoveButtonText": "Переместить", + "dxFileManager-dialogDirectoryChooserCopyTitle": "Копировать в", + "dxFileManager-dialogDirectoryChooserCopyButtonText": "Копировать", + "dxFileManager-dialogRenameItemTitle": "Переименовать", + "dxFileManager-dialogRenameItemButtonText": "Сохранить", + "dxFileManager-dialogCreateDirectoryTitle": "Новая папка", + "dxFileManager-dialogCreateDirectoryButtonText": "Создать", - "dxFileManager-editingCreateSingleItemProcessingMessage": "Создаётся папка в {0}", - "dxFileManager-editingCreateSingleItemSuccessMessage": "Создана папка в {0}", - "dxFileManager-editingCreateSingleItemErrorMessage": "Не удалось создать папку", - "dxFileManager-editingCreateCommonErrorMessage": "Не удалось создать папку", + "dxFileManager-editingCreateSingleItemProcessingMessage": "Создаётся папка в {0}", + "dxFileManager-editingCreateSingleItemSuccessMessage": "Создана папка в {0}", + "dxFileManager-editingCreateSingleItemErrorMessage": "Не удалось создать папку", + "dxFileManager-editingCreateCommonErrorMessage": "Не удалось создать папку", - "dxFileManager-editingRenameSingleItemProcessingMessage": "Переименовывается элемент в {0}", - "dxFileManager-editingRenameSingleItemSuccessMessage": "Переименован элемент в {0}", - "dxFileManager-editingRenameSingleItemErrorMessage": "Не удалось переименовать элемент", - "dxFileManager-editingRenameCommonErrorMessage": "Не удалось переименовать элемент", + "dxFileManager-editingRenameSingleItemProcessingMessage": "Переименовывается элемент в {0}", + "dxFileManager-editingRenameSingleItemSuccessMessage": "Переименован элемент в {0}", + "dxFileManager-editingRenameSingleItemErrorMessage": "Не удалось переименовать элемент", + "dxFileManager-editingRenameCommonErrorMessage": "Не удалось переименовать элемент", - "dxFileManager-editingDeleteSingleItemProcessingMessage": "Элемент удаляется из {0}", - "dxFileManager-editingDeleteMultipleItemsProcessingMessage": "Удаление {0} элементов из {1}", - "dxFileManager-editingDeleteSingleItemSuccessMessage": "Элемент удалён из {0}", - "dxFileManager-editingDeleteMultipleItemsSuccessMessage": "{0} элементов удалено из {1}", - "dxFileManager-editingDeleteSingleItemErrorMessage": "Не удалось удалить элемент", - "dxFileManager-editingDeleteMultipleItemsErrorMessage": "{0} элементов не были удалены", - "dxFileManager-editingDeleteCommonErrorMessage": "Некоторые элементы не были удалены", + "dxFileManager-editingDeleteSingleItemProcessingMessage": "Элемент удаляется из {0}", + "dxFileManager-editingDeleteMultipleItemsProcessingMessage": "Удаление {0} элементов из {1}", + "dxFileManager-editingDeleteSingleItemSuccessMessage": "Элемент удалён из {0}", + "dxFileManager-editingDeleteMultipleItemsSuccessMessage": "{0} элементов удалено из {1}", + "dxFileManager-editingDeleteSingleItemErrorMessage": "Не удалось удалить элемент", + "dxFileManager-editingDeleteMultipleItemsErrorMessage": "{0} элементов не были удалены", + "dxFileManager-editingDeleteCommonErrorMessage": "Некоторые элементы не были удалены", - "dxFileManager-editingMoveSingleItemProcessingMessage": "Элемент перемещается в {0}", - "dxFileManager-editingMoveMultipleItemsProcessingMessage": "Перемещение {0} элементов в {1}", - "dxFileManager-editingMoveSingleItemSuccessMessage": "Элемент перемещён в {0}", - "dxFileManager-editingMoveMultipleItemsSuccessMessage": "{0} элементов перемещено в {1}", - "dxFileManager-editingMoveSingleItemErrorMessage": "Не удалось переместить элемент", - "dxFileManager-editingMoveMultipleItemsErrorMessage": "{0} элементов не были перемещены", - "dxFileManager-editingMoveCommonErrorMessage": "Некоторые элементы не были перемещены", + "dxFileManager-editingMoveSingleItemProcessingMessage": "Элемент перемещается в {0}", + "dxFileManager-editingMoveMultipleItemsProcessingMessage": "Перемещение {0} элементов в {1}", + "dxFileManager-editingMoveSingleItemSuccessMessage": "Элемент перемещён в {0}", + "dxFileManager-editingMoveMultipleItemsSuccessMessage": "{0} элементов перемещено в {1}", + "dxFileManager-editingMoveSingleItemErrorMessage": "Не удалось переместить элемент", + "dxFileManager-editingMoveMultipleItemsErrorMessage": "{0} элементов не были перемещены", + "dxFileManager-editingMoveCommonErrorMessage": "Некоторые элементы не были перемещены", - "dxFileManager-editingCopySingleItemProcessingMessage": "Элемент копируется в {0}", - "dxFileManager-editingCopyMultipleItemsProcessingMessage": "Коипрование {0} элементов в {1}", - "dxFileManager-editingCopySingleItemSuccessMessage": "Элемент скопирован в {0}", - "dxFileManager-editingCopyMultipleItemsSuccessMessage": "{0} элементов скопировано в {1}", - "dxFileManager-editingCopySingleItemErrorMessage": "Не удалось скопировать элемент", - "dxFileManager-editingCopyMultipleItemsErrorMessage": "{0} элементов не были скопированы", - "dxFileManager-editingCopyCommonErrorMessage": "Некоторые элементы не были скопированы", + "dxFileManager-editingCopySingleItemProcessingMessage": "Элемент копируется в {0}", + "dxFileManager-editingCopyMultipleItemsProcessingMessage": "Коипрование {0} элементов в {1}", + "dxFileManager-editingCopySingleItemSuccessMessage": "Элемент скопирован в {0}", + "dxFileManager-editingCopyMultipleItemsSuccessMessage": "{0} элементов скопировано в {1}", + "dxFileManager-editingCopySingleItemErrorMessage": "Не удалось скопировать элемент", + "dxFileManager-editingCopyMultipleItemsErrorMessage": "{0} элементов не были скопированы", + "dxFileManager-editingCopyCommonErrorMessage": "Некоторые элементы не были скопированы", - "dxFileManager-editingUploadSingleItemProcessingMessage": "Элемент загружается в {0}", - "dxFileManager-editingUploadMultipleItemsProcessingMessage": "Загрузка {0} элементов в {1}", - "dxFileManager-editingUploadSingleItemSuccessMessage": "Элемент загружен в {0}", - "dxFileManager-editingUploadMultipleItemsSuccessMessage": "{0} элементов загружено в {1}", - "dxFileManager-editingUploadSingleItemErrorMessage": "Не удалось загрузить элемент", - "dxFileManager-editingUploadMultipleItemsErrorMessage": "{0} элементов не были загружены", - "dxFileManager-editingUploadCanceledMessage": "Отменено", + "dxFileManager-editingUploadSingleItemProcessingMessage": "Элемент загружается в {0}", + "dxFileManager-editingUploadMultipleItemsProcessingMessage": "Загрузка {0} элементов в {1}", + "dxFileManager-editingUploadSingleItemSuccessMessage": "Элемент загружен в {0}", + "dxFileManager-editingUploadMultipleItemsSuccessMessage": "{0} элементов загружено в {1}", + "dxFileManager-editingUploadSingleItemErrorMessage": "Не удалось загрузить элемент", + "dxFileManager-editingUploadMultipleItemsErrorMessage": "{0} элементов не были загружены", + "dxFileManager-editingUploadCanceledMessage": "Отменено", - "dxFileManager-listDetailsColumnCaptionName": "Название", - "dxFileManager-listDetailsColumnCaptionDateModified": "Дата изменения", - "dxFileManager-listDetailsColumnCaptionFileSize": "Размер файла", + "dxFileManager-listDetailsColumnCaptionName": "Название", + "dxFileManager-listDetailsColumnCaptionDateModified": "Дата изменения", + "dxFileManager-listDetailsColumnCaptionFileSize": "Размер файла", - "dxFileManager-listThumbnailsTooltipTextSize": "Размер", - "dxFileManager-listThumbnailsTooltipTextDateModified": "Дата изменения", + "dxFileManager-listThumbnailsTooltipTextSize": "Размер", + "dxFileManager-listThumbnailsTooltipTextDateModified": "Дата изменения", - "dxFileManager-notificationProgressPanelTitle": "Прогресс", - "dxFileManager-notificationProgressPanelEmptyListText": "Операции отсутствуют", - "dxFileManager-notificationProgressPanelOperationCanceled": "Отменено", + "dxFileManager-notificationProgressPanelTitle": "Прогресс", + "dxFileManager-notificationProgressPanelEmptyListText": "Операции отсутствуют", + "dxFileManager-notificationProgressPanelOperationCanceled": "Отменено", "dxDiagram-categoryGeneral": "Общие", "dxDiagram-categoryFlowchart": "Блок-схема", diff --git a/js/ui/calendar/ui.calendar.base_view.js b/js/ui/calendar/ui.calendar.base_view.js index 7459f49d6129..d5c97420ab85 100644 --- a/js/ui/calendar/ui.calendar.base_view.js +++ b/js/ui/calendar/ui.calendar.base_view.js @@ -1,17 +1,18 @@ -const $ = require('../../core/renderer'); -const domAdapter = require('../../core/dom_adapter'); -const eventsEngine = require('../../events/core/events_engine'); -const dataUtils = require('../../core/element_data'); -const domUtils = require('../../core/utils/dom'); -const Widget = require('../widget/ui.widget'); -const dateUtils = require('../../core/utils/date'); -const extend = require('../../core/utils/extend').extend; -const noop = require('../../core/utils/common').noop; -const dateSerialization = require('../../core/utils/date_serialization'); -const eventUtils = require('../../events/utils'); -const clickEvent = require('../../events/click'); - -const abstract = Widget.abstract; +import $ from '../../core/renderer'; +import domAdapter from '../../core/dom_adapter'; +import eventsEngine from '../../events/core/events_engine'; +import dataUtils from '../../core/element_data'; +import domUtils from '../../core/utils/dom'; +import Widget from '../widget/ui.widget'; +import { fixTimezoneGap, getShortDateFormat, getFirstDateView } from '../../core/utils/date'; +import { extend } from '../../core/utils/extend'; +import { noop } from '../../core/utils/common'; +import { serializeDate } from '../../core/utils/date_serialization'; +import { format as formatMessage } from '../../localization/message'; +import { addNamespace } from '../../events/utils'; +import { name as clickEventName } from '../../events/click'; + +const { abstract } = Widget; const CALENDAR_OTHER_VIEW_CLASS = 'dx-calendar-other-view'; const CALENDAR_CELL_CLASS = 'dx-calendar-cell'; @@ -20,7 +21,7 @@ const CALENDAR_TODAY_CLASS = 'dx-calendar-today'; const CALENDAR_SELECTED_DATE_CLASS = 'dx-calendar-selected-date'; const CALENDAR_CONTOURED_DATE_CLASS = 'dx-calendar-contoured-date'; -const CALENDAR_DXCLICK_EVENT_NAME = eventUtils.addNamespace(clickEvent.name, 'dxCalendar'); +const CALENDAR_DXCLICK_EVENT_NAME = addNamespace(clickEventName, 'dxCalendar'); const CALENDAR_DATE_VALUE_KEY = 'dxDateValueKey'; @@ -63,8 +64,7 @@ const BaseView = Widget.inherit({ }, _renderImpl: function() { - this._$table = $(''); - this.$element().append(this._$table); + this.$element().append(this._createTable()); this._createDisabledDatesHandler(); this._renderBody(); @@ -73,106 +73,139 @@ const BaseView = Widget.inherit({ this._renderEvents(); }, + _createTable: function() { + this._$table = $('
'); + + this.setAria({ + label: formatMessage('dxCalendar-ariaWidgetName'), + role: 'grid' + }, this._$table); + + return this._$table; + }, + _renderBody: function() { this.$body = $('').appendTo(this._$table); - const that = this; - const cellTemplate = this.option('cellTemplate'); + const rowData = { + cellDate: this._getFirstCellData(), + prevCellDate: null + }; - const appendChild = this.option('rtl') - ? function(row, cell) { - row.insertBefore(cell, row.firstChild); - } : function(row, cell) { - row.appendChild(cell); - }; + for(let rowIndex = 0, rowCount = this.option('rowCount'); rowIndex < rowCount; rowIndex++) { + rowData.row = this._createRow(); + for(let colIndex = 0, colCount = this.option('colCount'); colIndex < colCount; colIndex++) { + this._renderCell(rowData, colIndex); + } + } + }, - let cellDate = this._getFirstCellData(); - let row; + _createRow: function() { + const row = domAdapter.createElement('tr'); - function renderCell(cellIndex) { - // T425127 - if(prevCellDate) { - dateUtils.fixTimezoneGap(prevCellDate, cellDate); - } + this.setAria('role', 'row', $(row)); + this.$body.get(0).appendChild(row); - prevCellDate = cellDate; + return row; + }, - const cell = domAdapter.createElement('td'); - const $cell = $(cell); - let className = CALENDAR_CELL_CLASS; + _appendCell: function(row, cell) { + if(!this._appendMethodName) { + this._cacheAppendMethodName(); + } - if(that._isTodayCell(cellDate)) { - className = className + ' ' + CALENDAR_TODAY_CLASS; - } + $(row)[this._appendMethodName](cell); + }, - if(that._isDateOutOfRange(cellDate) || that.isDateDisabled(cellDate)) { - className = className + ' ' + CALENDAR_EMPTY_CELL_CLASS; - } + _cacheAppendMethodName: function(rtlEnabled) { + this._appendMethodName = rtlEnabled ?? this.option('rtlEnabled') ? + 'prepend' : + 'append'; + }, - if(that._isOtherView(cellDate)) { - className = className + ' ' + CALENDAR_OTHER_VIEW_CLASS; - } + _createCell: function(cellDate) { + const cell = domAdapter.createElement('td'); + const $cell = $(cell); - cell.className = className; + cell.className = this._getClassNameByDate(cellDate); - cell.setAttribute('data-value', dateSerialization.serializeDate(cellDate, dateUtils.getShortDateFormat())); - dataUtils.data(cell, CALENDAR_DATE_VALUE_KEY, cellDate); + cell.setAttribute('data-value', serializeDate(cellDate, getShortDateFormat())); + dataUtils.data(cell, CALENDAR_DATE_VALUE_KEY, cellDate); - that.setAria({ - 'role': 'option', - 'label': that.getCellAriaLabel(cellDate) - }, $cell); + this.setAria({ + 'role': 'gridcell', + 'label': this.getCellAriaLabel(cellDate) + }, $cell); - appendChild(row, cell); + return { cell, $cell }; + }, - if(cellTemplate) { - cellTemplate.render({ - model: { - text: that._getCellText(cellDate), - date: cellDate, - view: that._getViewName() - }, - container: domUtils.getPublicElement($cell), - index: cellIndex - }); - } else { - cell.innerHTML = that._getCellText(cellDate); - } + _renderCell: function(params, cellIndex) { + const { cellDate, prevCellDate, row } = params; - cellDate = that._getNextCellData(cellDate); + // T425127 + if(prevCellDate) { + fixTimezoneGap(prevCellDate, cellDate); } - const colCount = this.option('colCount'); - let prevCellDate; + params.prevCellDate = cellDate; + + const { cell, $cell } = this._createCell(cellDate); + const cellTemplate = this.option('cellTemplate'); - for(let indexRow = 0, len = this.option('rowCount'); indexRow < len; indexRow++) { - row = domAdapter.createElement('tr'); - this.$body.get(0).appendChild(row); - this._iterateCells(colCount, renderCell); + this._appendCell(row, cell); + + if(cellTemplate) { + cellTemplate.render(this._prepareCellTemplateData(cellDate, cellIndex, $cell)); + } else { + cell.innerHTML = this._getCellText(cellDate); } + + params.cellDate = this._getNextCellData(cellDate); }, - _iterateCells: function(colCount, delegate) { - let i = 0; + _getClassNameByDate: function(cellDate) { + let className = CALENDAR_CELL_CLASS; + + if(this._isTodayCell(cellDate)) { + className += ` ${CALENDAR_TODAY_CLASS}`; + } + + if(this._isDateOutOfRange(cellDate) || this.isDateDisabled(cellDate)) { + className += ` ${CALENDAR_EMPTY_CELL_CLASS}`; + } - while(i < colCount) { - delegate(i); - ++i; + if(this._isOtherView(cellDate)) { + className += ` ${CALENDAR_OTHER_VIEW_CLASS}`; } + + return className; + }, + + _prepareCellTemplateData: function(cellDate, cellIndex, $cell) { + return { + model: { + text: this._getCellText(cellDate), + date: cellDate, + view: this._getViewName() + }, + container: domUtils.getPublicElement($cell), + index: cellIndex + }; }, _renderEvents: function() { this._createCellClickAction(); eventsEngine.off(this._$table, CALENDAR_DXCLICK_EVENT_NAME); - eventsEngine.on(this._$table, CALENDAR_DXCLICK_EVENT_NAME, 'td', (function(e) { + eventsEngine.on(this._$table, CALENDAR_DXCLICK_EVENT_NAME, 'td', ((e) => { if(!$(e.currentTarget).hasClass(CALENDAR_EMPTY_CELL_CLASS)) { this._cellClickAction({ event: e, value: $(e.currentTarget).data(CALENDAR_DATE_VALUE_KEY) }); } - }).bind(this)); + })); }, _createCellClickAction: function() { @@ -217,7 +250,7 @@ const BaseView = Widget.inherit({ contouredDate = contouredDate || this.option('contouredDate'); - const $oldContouredCell = this._$table.find('.' + CALENDAR_CONTOURED_DATE_CLASS); + const $oldContouredCell = this._$table.find(`.${CALENDAR_CONTOURED_DATE_CLASS}`); const $newContouredCell = this._getCellByDate(contouredDate); $oldContouredCell.removeClass(CALENDAR_CONTOURED_DATE_CLASS); @@ -264,7 +297,7 @@ const BaseView = Widget.inherit({ let date = this.option('date'); const min = this.option('min'); - date = dateUtils.getFirstDateView(this._getViewName(), date); + date = getFirstDateView(this._getViewName(), date); return new Date(min && date < min ? min : date); }, @@ -273,13 +306,13 @@ const BaseView = Widget.inherit({ isBoundary: abstract, _optionChanged: function(args) { - const name = args.name; + const { name, value } = args; switch(name) { case 'value': this._renderValue(); break; case 'contouredDate': - this._renderContouredDate(args.value); + this._renderContouredDate(value); break; case 'onCellClick': this._createCellClickAction(); @@ -288,6 +321,10 @@ const BaseView = Widget.inherit({ case 'cellTemplate': this._invalidate(); break; + case 'rtlEnabled': + this._cacheAppendMethodName(value); + this.callBase(args); + break; default: this.callBase(args); } diff --git a/js/ui/calendar/ui.calendar.js b/js/ui/calendar/ui.calendar.js index 4c67064e1325..6abf3f4f3557 100644 --- a/js/ui/calendar/ui.calendar.js +++ b/js/ui/calendar/ui.calendar.js @@ -569,10 +569,6 @@ const Calendar = Editor.inherit({ this._renderSwipeable(); this._renderFooter(); - this.setAria({ - 'role': 'listbox', - 'label': messageLocalization.format('dxCalendar-ariaWidgetName') - }); this._updateAriaSelected(); this._updateAriaId(); @@ -635,7 +631,7 @@ const Calendar = Editor.inherit({ max: this._getMaxDate(), firstDayOfWeek: this.option('firstDayOfWeek'), value: this._dateOption('value'), - rtl: this.option('rtlEnabled'), + rtlEnabled: this.option('rtlEnabled'), disabled: this.option('disabled'), tabIndex: undefined, focusStateEnabled: this.option('focusStateEnabled'), diff --git a/js/ui/calendar/ui.calendar.views.js b/js/ui/calendar/ui.calendar.views.js index a7ea3e416d3f..a18e26441db9 100644 --- a/js/ui/calendar/ui.calendar.views.js +++ b/js/ui/calendar/ui.calendar.views.js @@ -1,11 +1,28 @@ -const $ = require('../../core/renderer'); -const noop = require('../../core/utils/common').noop; -const BaseView = require('./ui.calendar.base_view'); -const dateUtils = require('../../core/utils/date'); -const extend = require('../../core/utils/extend').extend; -const dateLocalization = require('../../localization/date'); -const dateSerialization = require('../../core/utils/date_serialization'); -const typeUtils = require('../../core/utils/type'); +import $ from '../../core/renderer'; +import BaseView from './ui.calendar.base_view'; +import { noop } from '../../core/utils/common'; +import { + sameDate, + dateInRange, + getFirstMonthDate, + getShortDateFormat, + sameMonthAndYear, + getLastMonthDate, + getFirstYearInDecade, + getFirstDecadeInCentury, + sameYear, + sameDecade, + sameCentury +} from '../../core/utils/date'; +import { extend } from '../../core/utils/extend'; +import { + format as formatMessage, + getDayNames, + firstDayOfWeekIndex, + getMonthNames +} from '../../localization/date'; +import { serializeDate } from '../../core/utils/date_serialization'; +import { isDefined } from '../../core/utils/type'; const CALENDAR_OTHER_MONTH_CLASS = 'dx-calendar-other-month'; const CALENDAR_OTHER_VIEW_CLASS = 'dx-calendar-other-view'; @@ -34,55 +51,56 @@ const Views = { _renderBody: function() { this.callBase(); - this._$table.find('.' + CALENDAR_OTHER_VIEW_CLASS).addClass(CALENDAR_OTHER_MONTH_CLASS); + this._$table.find(`.${CALENDAR_OTHER_VIEW_CLASS}`).addClass(CALENDAR_OTHER_MONTH_CLASS); }, _renderFocusTarget: noop, getCellAriaLabel: function(date) { - return dateLocalization.format(date, 'longdate'); + return formatMessage(date, 'longdate'); }, _renderHeader: function() { - const that = this; + const $headerRow = $(''); + const $header = $('').append($headerRow); - const $header = $(''); this._$table.prepend($header); - const $headerRow = $(''); - $header.append($headerRow); - - const appendCell = this.option('rtl') - ? function(row, cell) { - row.prepend(cell); - } - : function(row, cell) { - row.append(cell); - }; + for(let colIndex = 0, colCount = this.option('colCount'); colIndex < colCount; colIndex++) { + this._renderHeaderCell(colIndex, $headerRow); + } + }, - this._iterateCells(this.option('colCount'), function(i) { - const $cell = $('').appendTo(container); + }; + this.setupModules(this); + this.clock.tick(30); + + const rowsView = this.rowsView; + const $testElement = $('#container'); + + rowsView.render($testElement); + + this.editRow(0); + this.cellValue(0, 'name', 'Test'); + + let $rowElement = $(this.getRowElement(0)); + const $saveButton = $rowElement.find('.dx-button').first(); + + // assert + assert.ok($rowElement.hasClass('dx-datagrid-edit-form'), 'has edit form'); + assert.strictEqual($saveButton.text(), 'Save', 'has save button'); + + // act + $saveButton.trigger('dxclick'); + this.clock.tick(30); + + // assert + $rowElement = $(this.getRowElement(0)); + assert.notOk($rowElement.hasClass('dx-datagrid-edit-form'), 'has not edit form'); + assert.strictEqual(onRowClick.callCount, 0, 'onRowClick event is not fired'); +}); + QUnit.module('Editing - "popup" mode', { beforeEach: function() { diff --git a/testing/tests/DevExpress.ui.widgets.dataGrid/exportController.tests.js b/testing/tests/DevExpress.ui.widgets.dataGrid/exportController.tests.js index 03d6560adfeb..087e366f39b3 100644 --- a/testing/tests/DevExpress.ui.widgets.dataGrid/exportController.tests.js +++ b/testing/tests/DevExpress.ui.widgets.dataGrid/exportController.tests.js @@ -2535,7 +2535,7 @@ QUnit.test('Context menu is removed when the allowExportSelectedData option is c $exportMenu = $('.dx-context-menu.dx-datagrid-export-menu').first(); - assert.ok($exportMenu.length === 0); + assert.strictEqual($exportMenu.length, 0); }); QUnit.test('Hide export button via option', function(assert) { @@ -2607,7 +2607,7 @@ QUnit.test('Show export button via option when the enabled option is disabled', assert.ok(this.headerPanel.isVisible(), 'is visible'); $exportButton = $container.find('.dx-datagrid-export-button'); assert.equal($exportButton.length, 1, 'export button is contained in a DOM'); - assert.ok($exportButton.css('display') !== 'none', 'export button is shown'); + assert.notStrictEqual($exportButton.css('display'), 'none', 'export button is shown'); }); QUnit.test('The export context menu is shown', function(assert) { @@ -2905,7 +2905,7 @@ QUnit.test('Customize a data and a columns before exporting', function(assert) { assert.equal(exportedItems[3].values[1], 'TEST 30', '4 exported item of data'); assert.equal(exportedItems[4].values[1], 'TEST 30', '5 exported item of data'); - assert.ok(columns[2].width !== 333, 'third column\'s width'); + assert.notStrictEqual(columns[2].width, 333, 'third column\'s width'); assert.equal(items[1].values[2], '3', '2 item of data'); assert.equal(items[2].values[2], '3', '3 item of data'); assert.equal(items[3].values[2], '3', '4 item of data'); diff --git a/testing/tests/DevExpress.ui.widgets.dataGrid/fixedColumns.tests.js b/testing/tests/DevExpress.ui.widgets.dataGrid/fixedColumns.tests.js index 1b73817af853..e27d812c463f 100644 --- a/testing/tests/DevExpress.ui.widgets.dataGrid/fixedColumns.tests.js +++ b/testing/tests/DevExpress.ui.widgets.dataGrid/fixedColumns.tests.js @@ -1144,8 +1144,8 @@ QUnit.test('Synchronize rows for main table', function(assert) { that.rowsView.resize(); // assert - assert.ok($table[0].offsetHeight === $fixTable[0].offsetHeight, 'height table and fixed table'); - assert.ok($table.find('tbody > tr')[0].offsetHeight === $fixTable.find('tbody > tr')[0].offsetHeight, 'height row and fixed row'); + assert.strictEqual($table[0].offsetHeight, $fixTable[0].offsetHeight, 'height table and fixed table'); + assert.strictEqual($table.find('tbody > tr')[0].offsetHeight, $fixTable.find('tbody > tr')[0].offsetHeight, 'height row and fixed row'); }); QUnit.test('Synchronize rows for fixed table', function(assert) { @@ -1173,8 +1173,8 @@ QUnit.test('Synchronize rows for fixed table', function(assert) { that.rowsView.resize(); // assert - assert.ok($table[0].offsetHeight === $fixTable[0].offsetHeight, 'height table and fixed table'); - assert.ok($table.find('tbody > tr')[0].offsetHeight === $fixTable.find('tbody > tr')[0].offsetHeight, 'height row and fixed row'); + assert.strictEqual($table[0].offsetHeight, $fixTable[0].offsetHeight, 'height table and fixed table'); + assert.strictEqual($table.find('tbody > tr')[0].offsetHeight, $fixTable.find('tbody > tr')[0].offsetHeight, 'height row and fixed row'); }); // T234513 @@ -1210,8 +1210,8 @@ QUnit.test('Synchronize rows for fixed table with master detail', function(asser assert.equal($table.find('tbody > tr').length, 4, 'count rows'); assert.equal($fixTable.find('tbody > tr').length, 4, 'count fixed rows'); - assert.ok($table.find('tbody > tr')[0].getBoundingClientRect().height === $fixTable.find('tbody > tr')[0].getBoundingClientRect().height, 'height first row'); - assert.ok($table.find('tbody > tr')[1].getBoundingClientRect().height === $fixTable.find('tbody > tr')[1].getBoundingClientRect().height, 'height second row'); + assert.strictEqual($table.find('tbody > tr')[0].getBoundingClientRect().height, $fixTable.find('tbody > tr')[0].getBoundingClientRect().height, 'height first row'); + assert.strictEqual($table.find('tbody > tr')[1].getBoundingClientRect().height, $fixTable.find('tbody > tr')[1].getBoundingClientRect().height, 'height second row'); assert.roughEqual($table.find('tbody > tr')[2].getBoundingClientRect().height, $fixTable.find('tbody > tr')[2].getBoundingClientRect().height, 0.1, 'height third row'); }); @@ -1240,7 +1240,7 @@ QUnit.test('Synchronize rows with floating-point height', function(assert) { that.columnHeadersView.resize(); // assert - assert.ok(that.columnHeadersView._getClientHeight($table.find('tbody > tr').get(0)) === that.columnHeadersView._getClientHeight($fixTable.find('tbody > tr').get(0)), 'height row and fixed row'); + assert.strictEqual(that.columnHeadersView._getClientHeight($table.find('tbody > tr').get(0)), that.columnHeadersView._getClientHeight($fixTable.find('tbody > tr').get(0)), 'height row and fixed row'); }); // T246724 @@ -2062,7 +2062,7 @@ QUnit.test('Updating position of the fixed table (when scrollbar at the bottom) that.rowsView.resize(); // assert - assert.ok($fixedTable.position().top !== positionTop, 'scroll top of the fixed table is changed'); + assert.notStrictEqual($fixedTable.position().top, positionTop, 'scroll top of the fixed table is changed'); done(); }); }); diff --git a/testing/tests/DevExpress.ui.widgets.dataGrid/focus.tests.js b/testing/tests/DevExpress.ui.widgets.dataGrid/focus.tests.js index 327afea63e17..4346c8b5682e 100644 --- a/testing/tests/DevExpress.ui.widgets.dataGrid/focus.tests.js +++ b/testing/tests/DevExpress.ui.widgets.dataGrid/focus.tests.js @@ -75,10 +75,8 @@ const getModuleConfig = function(keyboardNavigationEnabled) { }; }; -QUnit.module('FocusedRow with real dataController, keyboard and columnsController', getModuleConfig(true), () => { +QUnit.module('Focused row', getModuleConfig(true), () => { QUnit.testInActiveWindow('TabIndex should set for the [focusedRowIndex; focusedColumnIndex] cell', function(assert) { - let rowsView; - // arrange this.options = { focusedRowIndex: 1, @@ -91,7 +89,7 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle // act this.gridView.render($('#container')); - rowsView = this.gridView.getView('rowsView'); + const rowsView = this.gridView.getView('rowsView'); // assert assert.equal(rowsView.getRow(0).attr('tabindex'), undefined, 'Row 0 tabIndex'); @@ -212,9 +210,6 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle }); QUnit.testInActiveWindow('Arrow Up key should decrease focusedRowIndex', function(assert) { - let rowsView; - let keyboardController; - // arrange this.$element = function() { return $('#container'); @@ -229,8 +224,8 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle this.clock.tick(); - rowsView = this.gridView.getView('rowsView'); - keyboardController = this.getController('keyboardNavigation'); + const rowsView = this.gridView.getView('rowsView'); + const keyboardController = this.getController('keyboardNavigation'); keyboardController._focusedView = rowsView; // assert @@ -242,9 +237,6 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle }); QUnit.testInActiveWindow('Arrow keys should move focused row if columnHidingEnabled is true', function(assert) { - let rowsView; - let keyboardController; - // arrange this.$element = function() { return $('#container'); @@ -262,15 +254,15 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle this.clock.tick(); - rowsView = this.gridView.getView('rowsView'); - keyboardController = this.getController('keyboardNavigation'); + const rowsView = this.gridView.getView('rowsView'); + const keyboardController = this.getController('keyboardNavigation'); keyboardController._focusedView = rowsView; // assert assert.equal(this.option('focusedRowIndex'), 1, 'FocusedRowIndex is 1'); assert.ok(rowsView.getRow(1).hasClass('dx-row-focused'), 'FocusedRow'); // act - $(this.getCellElement(1, 0)).trigger(pointerEvents.up).click(); + $(this.getCellElement(1, 0)).trigger(CLICK_EVENT).click(); keyboardController._upDownKeysHandler({ key: 'ArrowUp', keyName: 'upArrow' }); this.clock.tick(); // assert @@ -279,9 +271,6 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle }); QUnit.testInActiveWindow('Handle arrow keys without focused cell if focusedRowIndex and columnHidingEnabled is true', function(assert) { - let rowsView; - let keyboardController; - // arrange this.$element = function() { return $('#container'); @@ -299,8 +288,8 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle this.clock.tick(); - rowsView = this.gridView.getView('rowsView'); - keyboardController = this.getController('keyboardNavigation'); + const rowsView = this.gridView.getView('rowsView'); + const keyboardController = this.getController('keyboardNavigation'); keyboardController._focusedView = rowsView; try { @@ -316,9 +305,6 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle }); QUnit.testInActiveWindow('Arrow Down key should increase focusedRowIndex', function(assert) { - let rowsView; - let keyboardController; - // arrange this.$element = function() { return $('#container'); @@ -332,8 +318,8 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle this.clock.tick(); - rowsView = this.gridView.getView('rowsView'); - keyboardController = this.getController('keyboardNavigation'); + const rowsView = this.gridView.getView('rowsView'); + const keyboardController = this.getController('keyboardNavigation'); keyboardController._focusedView = rowsView; // assert assert.equal(this.option('focusedRowIndex'), 0, 'FocusedRowIndex is 0'); @@ -344,9 +330,6 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle }); QUnit.testInActiveWindow('Click by cell should focus the row', function(assert) { - let rowsView; - let keyboardController; - // arrange this.$element = function() { return $('#container'); @@ -363,8 +346,8 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle this.clock.tick(); - rowsView = this.gridView.getView('rowsView'); - keyboardController = this.getController('keyboardNavigation'); + const keyboardController = this.getController('keyboardNavigation'); + let rowsView = this.gridView.getView('rowsView'); // assert assert.equal(this.option('focusedRowIndex'), undefined, 'FocusedRowIndex is undefined'); @@ -397,8 +380,6 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle }); QUnit.testInActiveWindow('Tab key should focus the cell', function(assert) { - let rowsView; - // arrange this.$element = function() { return $('#container'); @@ -418,13 +399,13 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle this.clock.tick(); - rowsView = this.gridView.getView('rowsView'); + const rowsView = this.gridView.getView('rowsView'); // assert assert.equal(this.option('focusedRowIndex'), undefined, 'FocusedRowIndex is undefined'); this.clock.tick(); // act - $(rowsView.getRow(1).find('td').eq(0)).trigger(pointerEvents.up).click(); + $(rowsView.getRow(1).find('td').eq(0)).trigger(CLICK_EVENT).click(); this.triggerKeyDown('tab', false, false, rowsView.element().find(':focus').get(0)); // assert assert.equal(this.option('focusedRowIndex'), 1, 'focusedRowIndex'); @@ -437,7 +418,6 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle QUnit.testInActiveWindow('Tab key before grid should focus the first row (legacyKbn)', function(assert) { const that = this; - let rowsView; // arrange this.$element = function() { @@ -459,7 +439,7 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle this.clock.tick(); - rowsView = this.gridView.getView('rowsView'); + const rowsView = this.gridView.getView('rowsView'); // assert assert.equal(this.option('focusedRowIndex'), undefined, 'FocusedRowIndex is undefined'); @@ -504,7 +484,6 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle QUnit.testInActiveWindow('Tab key before rows view should focus the first row', function(assert) { const that = this; - let rowsView; // arrange this.$element = function() { @@ -525,7 +504,7 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle this.clock.tick(); - rowsView = this.gridView.getView('rowsView'); + const rowsView = this.gridView.getView('rowsView'); // assert assert.equal(this.option('focusedRowIndex'), undefined, 'FocusedRowIndex is undefined'); @@ -539,8 +518,6 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle }); QUnit.testInActiveWindow('LeftArrow key should focus the cell', function(assert) { - let rowsView; - // arrange this.$element = function() { return $('#container'); @@ -560,13 +537,13 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle this.clock.tick(); - rowsView = this.gridView.getView('rowsView'); + const rowsView = this.gridView.getView('rowsView'); // assert assert.equal(this.option('focusedRowIndex'), undefined, 'FocusedRowIndex is undefined'); this.clock.tick(); // act - $(rowsView.getRow(1).find('td').eq(0)).trigger(pointerEvents.up).click(); + $(rowsView.getRow(1).find('td').eq(0)).trigger(CLICK_EVENT).click(); this.triggerKeyDown('leftArrow', false, false, rowsView.element().find(':focus').get(0)); // assert assert.equal(this.option('focusedRowIndex'), 1, 'FocusedRowIndex = 1'); @@ -578,8 +555,6 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle }); QUnit.testInActiveWindow('RightArrow key should focus the cell', function(assert) { - let rowsView; - // arrange this.$element = function() { return $('#container'); @@ -599,13 +574,13 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle this.clock.tick(); - rowsView = this.gridView.getView('rowsView'); + const rowsView = this.gridView.getView('rowsView'); // assert assert.equal(this.option('focusedRowIndex'), undefined, 'FocusedRowIndex is undefined'); this.clock.tick(); // act - $(rowsView.getRow(1).find('td').eq(0)).trigger(pointerEvents.up).click(); + $(rowsView.getRow(1).find('td').eq(0)).trigger(CLICK_EVENT).click(); this.triggerKeyDown('rightArrow', false, false, rowsView.element().find(':focus').get(0)); // assert assert.equal(this.option('focusedRowIndex'), 1, 'FocusedRowIndex = 1'); @@ -617,8 +592,6 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle }); QUnit.testInActiveWindow('ArrowUp / ArrowDown should not change focus type', function(assert) { - let rowsView; - // arrange this.options = { focusedRowEnabled: true @@ -634,7 +607,8 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle addOptionChangedHandlers(this); this.gridView.render($('#container')); this.clock.tick(); - rowsView = this.gridView.getView('rowsView'); + + const rowsView = this.gridView.getView('rowsView'); // assert assert.equal(this.option('focusedRowIndex'), undefined, 'FocusedRowIndex'); @@ -660,8 +634,6 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle }); QUnit.testInActiveWindow('Focus row by click if virtual scrolling mode', function(assert) { - let rowsView; - // arrange this.options = { focusedRowEnabled: true, @@ -692,7 +664,7 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle this.clock.tick(); - rowsView = this.gridView.getView('rowsView'); + const rowsView = this.gridView.getView('rowsView'); // assert assert.equal(this.option('focusedRowIndex'), undefined, 'FocusedRowIndex is undefined'); @@ -704,9 +676,6 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle }); QUnit.testInActiveWindow('DataGrid should restore focused row when data without focused row was filtered', function(assert) { - let rowsView; - let visibleRows; - // arrange this.data = [ { team: 'internal', name: 'Alex', age: 30 }, @@ -729,15 +698,15 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle this.clock.tick(); - $(this.getCellElement(5, 0)).trigger(pointerEvents.up).focus(); + $(this.getCellElement(5, 0)).trigger(CLICK_EVENT).focus(); // act this.dataController.filter('team', '=', 'public'); this.dataController.load(); this.clock.tick(); - rowsView = this.gridView.getView('rowsView'); - visibleRows = this.dataController.getVisibleRows(); + const rowsView = this.gridView.getView('rowsView'); + const visibleRows = this.dataController.getVisibleRows(); // assert assert.equal(this.option('focusedRowIndex'), 1, 'focusedRowIndex'); @@ -747,9 +716,6 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle }); QUnit.testInActiveWindow('DataGrid should restore focused row when focused row data was filtered', function(assert) { - let rowsView; - let visibleRows; - // arrange this.data = [ { team: 'internal', name: 'Alex', age: 30 }, @@ -772,15 +738,15 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle this.clock.tick(); - $(this.getCellElement(5, 0)).trigger(pointerEvents.up).focus(); + $(this.getCellElement(5, 0)).trigger(CLICK_EVENT).focus(); // act this.dataController.filter('team', '=', 'internal'); this.dataController.load(); this.clock.tick(); - rowsView = this.gridView.getView('rowsView'); - visibleRows = this.dataController.getVisibleRows(); + const rowsView = this.gridView.getView('rowsView'); + const visibleRows = this.dataController.getVisibleRows(); // assert assert.equal(this.option('focusedRowIndex'), 1, 'focusedRowIndex'); @@ -791,9 +757,8 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle // T848606 QUnit.testInActiveWindow('DataGrid should not infinitly load data when filter with no suitable rows was applied', function(assert) { // arrange - let visibleRows; let loadCallCount = 0; - let items = []; + const items = []; for(let i = 0; i < 60; i++) { items.push({ @@ -849,7 +814,7 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle this.dataController.load(); this.clock.tick(100); - visibleRows = this.dataController.getVisibleRows(); + const visibleRows = this.dataController.getVisibleRows(); // assert assert.equal(this.option('focusedRowKey'), 40, 'focusedRowKey'); @@ -859,8 +824,6 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle }); QUnit.testInActiveWindow('Tab index should not exist for the previous focused row', function(assert) { - let rowsView; - // arrange this.options = { focusedRowEnabled: true, @@ -876,13 +839,13 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle this.clock.tick(); - rowsView = this.gridView.getView('rowsView'); + const rowsView = this.gridView.getView('rowsView'); // act - $(rowsView.getRow(0).find('td').eq(0)).trigger(pointerEvents.up).click(); + $(rowsView.getRow(0).find('td').eq(0)).trigger(CLICK_EVENT).click(); this.clock.tick(); this.triggerKeyDown('rightArrow', false, false, rowsView.element().find(':focus').get(0)); - $(rowsView.getRow(1).find('td').eq(0)).trigger(pointerEvents.up).click(); + $(rowsView.getRow(1).find('td').eq(0)).trigger(CLICK_EVENT).click(); // assert assert.equal($(rowsView.getRow(0)).find('[tabindex="0"]').length, 1, 'Row 0 has tabindex'); // act @@ -894,8 +857,6 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle }); QUnit.testInActiveWindow('Set focusedRowIndex, focusedColumnIndex should focus the cell', function(assert) { - let rowsView; - // arrange this.options = { focusedRowIndex: 1, @@ -911,7 +872,7 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle this.clock.tick(); - rowsView = this.gridView.getView('rowsView'); + const rowsView = this.gridView.getView('rowsView'); // assert assert.equal(this.option('focusedRowIndex'), 1, 'FocusedRowIndex = 1'); @@ -948,8 +909,6 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle }); QUnit.testInActiveWindow('Escape should change focus type from cell to row if focusedRowEnabled', function(assert) { - let rowsView; - // arrange this.$element = function() { return $('#container'); @@ -965,13 +924,13 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle this.clock.tick(); - rowsView = this.gridView.getView('rowsView'); + const rowsView = this.gridView.getView('rowsView'); // assert assert.equal(this.option('focusedRowIndex'), undefined, 'FocusedRowIndex is undefined'); this.clock.tick(); // act - $(rowsView.getRow(1).find('td').eq(0)).trigger(pointerEvents.up).click(); + $(rowsView.getRow(1).find('td').eq(0)).trigger(CLICK_EVENT).click(); this.triggerKeyDown('rightArrow', false, false, rowsView.element().find(':focus').get(0)); // assert assert.ok(this.getController('keyboardNavigation').isCellFocusType(), 'Cell focus type'); @@ -982,8 +941,6 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle }); QUnit.testInActiveWindow('Escape should not change focus type from cell to row if not focusedRowEnabled', function(assert) { - let rowsView; - // arrange this.$element = function() { return $('#container'); @@ -998,7 +955,7 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle this.clock.tick(); - rowsView = this.gridView.getView('rowsView'); + const rowsView = this.gridView.getView('rowsView'); // assert assert.equal(this.option('focusedRowIndex'), undefined, 'FocusedRowIndex is undefined'); @@ -1015,8 +972,6 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle }); QUnit.testInActiveWindow('Not highlight cell by isHighlighted arg in the onFocusedCellChanging event by LeftArrow key', function(assert) { - let rowsView; - let keyboardController; let focusedColumnChangingCount = 0; // arrange @@ -1045,8 +1000,8 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle this.gridView.render($('#container')); this.clock.tick(); - rowsView = this.gridView.getView('rowsView'); - keyboardController = this.getController('keyboardNavigation'); + const rowsView = this.gridView.getView('rowsView'); + const keyboardController = this.getController('keyboardNavigation'); keyboardController._focusedView = rowsView; // assert @@ -1062,8 +1017,6 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle }); QUnit.testInActiveWindow('Fire onFocusedCellChanging by LeftArrow key', function(assert) { - let rowsView; - let keyboardController; let focusedColumnChangingCount = 0; // arrange @@ -1101,8 +1054,8 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle this.gridView.render($('#container')); this.clock.tick(); - rowsView = this.gridView.getView('rowsView'); - keyboardController = this.getController('keyboardNavigation'); + const rowsView = this.gridView.getView('rowsView'); + const keyboardController = this.getController('keyboardNavigation'); keyboardController._focusedView = rowsView; // assert @@ -1116,8 +1069,6 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle }); QUnit.testInActiveWindow('Fire onFocusedCellChanging by RightArrow key', function(assert) { - let rowsView; - let keyboardController; let focusedColumnChangingCount = 0; // arrange @@ -1154,8 +1105,8 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle this.gridView.render($('#container')); this.clock.tick(); - rowsView = this.gridView.getView('rowsView'); - keyboardController = this.getController('keyboardNavigation'); + const rowsView = this.gridView.getView('rowsView'); + const keyboardController = this.getController('keyboardNavigation'); keyboardController._focusedView = rowsView; // assert @@ -1169,8 +1120,6 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle }); QUnit.testInActiveWindow('Fire onFocusedCellChanging by RightArrow key and change newRowIndex, newColumnIndex', function(assert) { - let rowsView; - let keyboardController; let focusedColumnChangingCount = 0; // arrange @@ -1204,8 +1153,8 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle this.gridView.render($('#container')); this.clock.tick(); - rowsView = this.gridView.getView('rowsView'); - keyboardController = this.getController('keyboardNavigation'); + const rowsView = this.gridView.getView('rowsView'); + const keyboardController = this.getController('keyboardNavigation'); keyboardController._focusedView = rowsView; // assert @@ -1222,8 +1171,6 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle }); QUnit.testInActiveWindow('Fire onFocusedCellChanging, onFocusedRowChanging by DownArrow key and change newRowIndex, newColumnIndex', function(assert) { - let rowsView; - let keyboardController; let focusedColumnChangingCount = 0; let focusedRowChangingCount = 0; @@ -1260,8 +1207,8 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle this.gridView.render($('#container')); this.clock.tick(); - rowsView = this.gridView.getView('rowsView'); - keyboardController = this.getController('keyboardNavigation'); + const rowsView = this.gridView.getView('rowsView'); + const keyboardController = this.getController('keyboardNavigation'); keyboardController._focusedView = rowsView; // assert @@ -1280,8 +1227,6 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle }); QUnit.testInActiveWindow('Fire onFocusedCellChanging by UpArrow key', function(assert) { - let rowsView; - let keyboardController; let focusedColumnChangingCount = 0; // arrange @@ -1322,8 +1267,8 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle this.gridView.render($('#container')); this.clock.tick(); - rowsView = this.gridView.getView('rowsView'); - keyboardController = this.getController('keyboardNavigation'); + const rowsView = this.gridView.getView('rowsView'); + const keyboardController = this.getController('keyboardNavigation'); keyboardController._focusedView = rowsView; // assert @@ -1339,8 +1284,6 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle }); QUnit.testInActiveWindow('Fire onFocusedCellChanging by DownArrow key', function(assert) { - let rowsView; - let keyboardController; let focusedColumnChangingCount = 0; // arrange @@ -1381,8 +1324,8 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle this.gridView.render($('#container')); this.clock.tick(); - rowsView = this.gridView.getView('rowsView'); - keyboardController = this.getController('keyboardNavigation'); + const rowsView = this.gridView.getView('rowsView'); + const keyboardController = this.getController('keyboardNavigation'); keyboardController._focusedView = rowsView; // assert @@ -1398,7 +1341,6 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle }); QUnit.testInActiveWindow('Fire onFocusedCellChanging by UpDownArrow keys may prevent change focused row', function(assert) { - let keyboardController; let focusedColumnChangingCount = 0; let focusedRowChangingCount = 0; @@ -1438,7 +1380,7 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle this.gridView.render($('#container')); this.clock.tick(); - keyboardController = this.getController('keyboardNavigation'); + const keyboardController = this.getController('keyboardNavigation'); keyboardController._focusedView = this.gridView.getView('rowsView'); // act @@ -1451,8 +1393,6 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle }); QUnit.testInActiveWindow('Fire onFocusedCellChanging by Tab key', function(assert) { - let rowsView; - let keyboardController; let focusedCellChangingCounter = 0; let columnIndex; @@ -1489,11 +1429,11 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle this.gridView.render($('#container')); this.clock.tick(); - $(this.gridView.getView('rowsView').getRow(1).find('td').eq(0)).trigger(pointerEvents.up).click(); + $(this.getCellElement(1, 0)).trigger(CLICK_EVENT).click(); this.clock.tick(); - rowsView = this.gridView.getView('rowsView'); - keyboardController = this.getController('keyboardNavigation'); + const rowsView = this.gridView.getView('rowsView'); + const keyboardController = this.getController('keyboardNavigation'); keyboardController._focusedView = rowsView; // assert @@ -1514,8 +1454,6 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle }); QUnit.testInActiveWindow('Fire onFocusedCellChanging by Tab key in back order (shift presset)', function(assert) { - let rowsView; - let keyboardController; let focusedCellChangingCounter = 0; // arrange @@ -1551,11 +1489,11 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle this.gridView.render($('#container')); this.clock.tick(); - $(this.gridView.getView('rowsView').getRow(1).find('td').eq(2)).trigger(pointerEvents.up).click(); + $(this.getCellElement(1, 2)).trigger(CLICK_EVENT).click(); this.clock.tick(); - rowsView = this.gridView.getView('rowsView'); - keyboardController = this.getController('keyboardNavigation'); + const rowsView = this.gridView.getView('rowsView'); + const keyboardController = this.getController('keyboardNavigation'); keyboardController._focusedView = rowsView; // assert @@ -1576,8 +1514,6 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle }); QUnit.testInActiveWindow('Fire onFocusedCellChanging by Tab key if cell is being edited', function(assert) { - let rowsView; - let keyboardController; let focusedCellChangingCounter = 0; // arrange @@ -1602,11 +1538,11 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle this.gridView.render($('#container')); this.clock.tick(); - $(this.gridView.getView('rowsView').getRow(1).find('td').eq(0)).trigger(pointerEvents.up).click(); + $(this.getCellElement(1, 0)).trigger(CLICK_EVENT).click(); this.clock.tick(); - rowsView = this.gridView.getView('rowsView'); - keyboardController = this.getController('keyboardNavigation'); + const rowsView = this.gridView.getView('rowsView'); + const keyboardController = this.getController('keyboardNavigation'); keyboardController._focusedView = rowsView; // assert @@ -1634,8 +1570,6 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle }); QUnit.testInActiveWindow('Fire onFocusedCellChanging by Enter key if \'enterKeyDirection\' is \'row\', \'enterKeyAction\' is \'moveFocus\'', function(assert) { - let rowsView; - let keyboardController; let focusedCellChangingCounter = 0; let columnIndex; @@ -1676,11 +1610,11 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle this.gridView.render($('#container')); this.clock.tick(); - $(this.gridView.getView('rowsView').getRow(1).find('td').eq(0)).trigger(pointerEvents.up).click(); + $(this.getCellElement(1, 0)).trigger(CLICK_EVENT).click(); this.clock.tick(); - rowsView = this.gridView.getView('rowsView'); - keyboardController = this.getController('keyboardNavigation'); + const rowsView = this.gridView.getView('rowsView'); + const keyboardController = this.getController('keyboardNavigation'); keyboardController._focusedView = rowsView; // assert @@ -1701,8 +1635,6 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle }); QUnit.testInActiveWindow('Fire onFocusedCellChanging by Enter key if \'enterKeyDirection\' is \'row\', \'enterKeyAction\' is \'startEdit\'', function(assert) { - let rowsView; - let keyboardController; let focusedCellChangingCounter = 0; let columnIndex; @@ -1744,11 +1676,11 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle this.gridView.render($('#container')); this.clock.tick(); - $(this.gridView.getView('rowsView').getRow(1).find('td').eq(0)).trigger(pointerEvents.up).click(); + $(this.getCellElement(1, 0)).trigger(CLICK_EVENT).click(); this.clock.tick(); - rowsView = this.gridView.getView('rowsView'); - keyboardController = this.getController('keyboardNavigation'); + const rowsView = this.gridView.getView('rowsView'); + const keyboardController = this.getController('keyboardNavigation'); keyboardController._focusedView = rowsView; // assert @@ -1773,8 +1705,6 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle }); QUnit.testInActiveWindow('Fire onFocusedCellChanging by Enter key if \'enterKeyDirection\' is \'row\', \'enterKeyAction\' is \'moveFocus\'', function(assert) { - let rowsView; - let keyboardController; let focusedCellChangingCounter = 0; let columnIndex; @@ -1816,11 +1746,11 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle this.gridView.render($('#container')); this.clock.tick(); - $(this.gridView.getView('rowsView').getRow(1).find('td').eq(0)).trigger(pointerEvents.up).click(); + $(this.getCellElement(1, 0)).trigger(CLICK_EVENT).click(); this.clock.tick(); - rowsView = this.gridView.getView('rowsView'); - keyboardController = this.getController('keyboardNavigation'); + const rowsView = this.gridView.getView('rowsView'); + const keyboardController = this.getController('keyboardNavigation'); keyboardController._focusedView = rowsView; // assert @@ -1836,9 +1766,7 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle assert.notOk(this.editingController.isEditing(), 'Is editing'); }); - QUnit.testInActiveWindow('Fire onFocusedCellChanging by Enter key if \'enterKeyDirection\' is \'column\', \'enterKeyAction\' is \'startEdit\'', function(assert) { - let rowsView; - let keyboardController; + QUnit.testInActiveWindow('Fire onFocusedCellChanging by Enter key if enterKeyDirection: column, enterKeyAction: startEdit', function(assert) { let focusedCellChangingCounter = 0; let columnIndex; @@ -1880,11 +1808,11 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle this.gridView.render($('#container')); this.clock.tick(); - $(this.gridView.getView('rowsView').getRow(1).find('td').eq(0)).trigger(pointerEvents.up).click(); + $(this.getCellElement(1, 0)).trigger(CLICK_EVENT).click(); this.clock.tick(); - rowsView = this.gridView.getView('rowsView'); - keyboardController = this.getController('keyboardNavigation'); + const rowsView = this.gridView.getView('rowsView'); + const keyboardController = this.getController('keyboardNavigation'); keyboardController._focusedView = rowsView; // assert @@ -1908,9 +1836,7 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle assert.notOk(this.editingController.isEditing(), 'Is editing'); }); - QUnit.testInActiveWindow('Fire onFocusedCellChanging by Enter key if \'enterKeyDirection\' is \'column\', \'enterKeyAction\' is \'moveFocus\'', function(assert) { - let rowsView; - let keyboardController; + QUnit.testInActiveWindow('Fire onFocusedCellChanging by Enter key if enterKeyDirection: column, enterKeyAction: moveFocus', function(assert) { let focusedCellChangingCounter = 0; let columnIndex; @@ -1952,11 +1878,11 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle this.gridView.render($('#container')); this.clock.tick(); - $(this.gridView.getView('rowsView').getRow(1).find('td').eq(0)).trigger(pointerEvents.up).click(); + $(this.getCellElement(1, 0)).trigger(CLICK_EVENT).click(); this.clock.tick(); - rowsView = this.gridView.getView('rowsView'); - keyboardController = this.getController('keyboardNavigation'); + const rowsView = this.gridView.getView('rowsView'); + const keyboardController = this.getController('keyboardNavigation'); keyboardController._focusedView = rowsView; // assert @@ -1972,9 +1898,7 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle assert.notOk(this.editingController.isEditing(), 'Is editing'); }); - QUnit.testInActiveWindow('Changing row index by Enter key navigation if \'enterKeyDirection\' is \'row\', \'enterKeyAction\' is \'moveFocus\'', function(assert) { - let rowsView; - let keyboardController; + QUnit.testInActiveWindow('Changing row index by Enter key navigation if enterKeyDirection: row, enterKeyAction: moveFocus', function(assert) { let focusedCellChangingCounter = 0; // arrange @@ -2010,11 +1934,11 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle this.gridView.render($('#container')); this.clock.tick(); - $(this.gridView.getView('rowsView').getRow(1).find('td').eq(0)).trigger(pointerEvents.up).click(); + $(this.getCellElement(1, 0)).trigger(CLICK_EVENT).click(); this.clock.tick(); - rowsView = this.gridView.getView('rowsView'); - keyboardController = this.getController('keyboardNavigation'); + const rowsView = this.gridView.getView('rowsView'); + const keyboardController = this.getController('keyboardNavigation'); keyboardController._focusedView = rowsView; // assert @@ -2030,9 +1954,7 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle assert.notOk(this.editingController.isEditing(), 'Is editing'); }); - QUnit.testInActiveWindow('Changing row index by Enter key navigation if \'enterKeyDirection\' is \'row\', \'enterKeyAction\' is \'startEdit\'', function(assert) { - let rowsView; - let keyboardController; + QUnit.testInActiveWindow('Changing row index by Enter key navigation if enterKeyDirection: row, enterKeyAction: startEdit', function(assert) { let focusedCellChangingCounter = 0; // arrange @@ -2068,11 +1990,11 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle this.gridView.render($('#container')); this.clock.tick(); - $(this.gridView.getView('rowsView').getRow(1).find('td').eq(0)).trigger(pointerEvents.up).click(); + $(this.getCellElement(1, 0)).trigger(CLICK_EVENT).click(); this.clock.tick(); - rowsView = this.gridView.getView('rowsView'); - keyboardController = this.getController('keyboardNavigation'); + const rowsView = this.gridView.getView('rowsView'); + const keyboardController = this.getController('keyboardNavigation'); keyboardController._focusedView = rowsView; // assert @@ -2096,9 +2018,7 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle assert.notOk(this.editingController.isEditing(), 'Is editing'); }); - QUnit.testInActiveWindow('Enter key navigation from the last cell should navigate to the new row and first column if \'enterKeyDirection\' is \'row\', \'enterKeyAction\' is \'startEdit\'', function(assert) { - let rowsView; - let keyboardController; + QUnit.testInActiveWindow('Enter key navigation from the last cell should navigate to the new row and first column if enterKeyDirection: row, enterKeyAction: startEdit', function(assert) { let focusedCellChangingCounter = 0; // arrange @@ -2131,11 +2051,11 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle this.gridView.render($('#container')); this.clock.tick(); - $(this.getCellElement(1, 2)).trigger(pointerEvents.up).click(); + $(this.getCellElement(1, 2)).trigger(CLICK_EVENT).click(); this.clock.tick(); - rowsView = this.gridView.getView('rowsView'); - keyboardController = this.getController('keyboardNavigation'); + const rowsView = this.gridView.getView('rowsView'); + const keyboardController = this.getController('keyboardNavigation'); keyboardController._focusedView = rowsView; // assert @@ -2159,9 +2079,7 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle assert.notOk(this.editingController.isEditing(), 'Is editing'); }); - QUnit.testInActiveWindow('Enter key navigation from the last cell should navigate to the new row and first column if \'enterKeyDirection\' is \'row\', \'enterKeyAction\' is \'moveFocus\'', function(assert) { - let rowsView; - let keyboardController; + QUnit.testInActiveWindow('Enter key navigation from the last cell should navigate to the new row and first column if enterKeyDirection: row, enterKeyAction: moveFocus', function(assert) { let focusedCellChangingCounter = 0; // arrange @@ -2194,11 +2112,11 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle this.gridView.render($('#container')); this.clock.tick(); - $(this.getCellElement(1, 2)).trigger(pointerEvents.up).click(); + $(this.getCellElement(1, 2)).trigger(CLICK_EVENT).click(); this.clock.tick(); - rowsView = this.gridView.getView('rowsView'); - keyboardController = this.getController('keyboardNavigation'); + const rowsView = this.gridView.getView('rowsView'); + const keyboardController = this.getController('keyboardNavigation'); keyboardController._focusedView = rowsView; // assert @@ -2215,7 +2133,6 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle }); QUnit.testInActiveWindow('Group row should focused on focus()', function(assert) { - let keyboardController; let focusedCellChangingCount = 0; // arrange @@ -2243,7 +2160,7 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle this.gridView.render($('#container')); this.clock.tick(); - keyboardController = this.getController('keyboardNavigation'); + const keyboardController = this.getController('keyboardNavigation'); keyboardController._focusedView = this.getView('rowsView'); keyboardController.focus(null); this.clock.tick(500); @@ -2255,7 +2172,6 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle }); QUnit.testInActiveWindow('Highlight group row on focus()', function(assert) { - let keyboardController; let focusedCellChangingCount = 0; // arrange @@ -2284,7 +2200,7 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle this.gridView.render($('#container')); this.clock.tick(); - keyboardController = this.getController('keyboardNavigation'); + const keyboardController = this.getController('keyboardNavigation'); keyboardController._focusedView = this.getView('rowsView'); keyboardController.focus(null); this.clock.tick(500); @@ -2297,7 +2213,6 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle QUnit.testInActiveWindow('Highlight cell on focus()', function(assert) { let focusedCellChangingCount = 0; - let keyboardController; // arrange this.options = { focusedRowIndex: 1, @@ -2313,7 +2228,7 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle this.gridView.render($('#container')); this.clock.tick(); - keyboardController = this.getController('keyboardNavigation'); + const keyboardController = this.getController('keyboardNavigation'); keyboardController._focusedView = this.getView('rowsView'); keyboardController.focus(null); this.clock.tick(); @@ -2325,7 +2240,6 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle QUnit.testInActiveWindow('Highlight cell on focus() if focusedRowIndex, focusedColumnIndex are not set', function(assert) { let focusedCellChangingCount = 0; - let keyboardController; // arrange this.options = { onFocusedCellChanging: function(e) { @@ -2337,7 +2251,7 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle this.gridView.render($('#container')); this.clock.tick(); - keyboardController = this.getController('keyboardNavigation'); + const keyboardController = this.getController('keyboardNavigation'); keyboardController._focusedView = this.getView('rowsView'); keyboardController.focus(); this.clock.tick(); @@ -2370,7 +2284,7 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle onFocusedRowChanging: function(e) { ++focusedRowChangingCount; assert.equal(e.cancel, false); - assert.equal(e.event.type, pointerEvents.up); + assert.ok(CLICK_EVENT.indexOf(e.event.type) === 0); assert.equal(e.newRowIndex, 1); assert.equal(e.prevRowIndex, 4); assert.equal(e.rows.length, 6); @@ -2383,7 +2297,7 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle this.clock.tick(); // act - $(this.gridView.getView('rowsView').getRow(1).find('td').eq(0)).trigger(pointerEvents.up).click(); + $(this.getCellElement(1, 0)).trigger(CLICK_EVENT).click(); this.clock.tick(); // assert assert.equal(this.getController('keyboardNavigation').getVisibleRowIndex(), 1, 'Focused row index is 1'); @@ -2391,9 +2305,7 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle }); QUnit.testInActiveWindow('Fire onFocusedRowChanging by UpArrow key', function(assert) { - let rowsView; let focusedRowChangingCount = 0; - let keyboardController; // arrange this.data = [ @@ -2426,8 +2338,8 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle this.clock.tick(); - rowsView = this.gridView.getView('rowsView'); - keyboardController = this.getController('keyboardNavigation'); + const rowsView = this.gridView.getView('rowsView'); + const keyboardController = this.getController('keyboardNavigation'); keyboardController._focusedView = rowsView; // assert @@ -2440,9 +2352,7 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle }); QUnit.testInActiveWindow('DataGrid - should restore previos row index after the focus losing (T804103)', function(assert) { - let rowsView; let focusedRowChangingCount = 0; - let keyboardController; // arrange this.data = [{ name: 'Alex' }, { name: 'Dan' }]; @@ -2472,8 +2382,8 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle this.gridView.render($('#container')); this.clock.tick(); - rowsView = this.gridView.getView('rowsView'); - keyboardController = this.getController('keyboardNavigation'); + const rowsView = this.gridView.getView('rowsView'); + const keyboardController = this.getController('keyboardNavigation'); // act $(rowsView.getCellElement(0, 0)).trigger(CLICK_EVENT); @@ -2486,10 +2396,7 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle QUnit.testInActiveWindow('Fire onFocusedRowChanging by UpArrow key when virtual scrolling is enabled', function(assert) { // arrange - let rowsView; - let scrollable; - let $scrollContainer; let focusedRowChangingCount = 0; - let keyboardController; + let focusedRowChangingCount = 0; this.data = generateItems(100); @@ -2519,12 +2426,12 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle this.setupModule(); this.gridView.render($('#container')); - rowsView = this.gridView.getView('rowsView'); + const rowsView = this.gridView.getView('rowsView'); rowsView.height(400); rowsView.resize(); - scrollable = rowsView.getScrollable(); - $scrollContainer = $(scrollable._container()); - keyboardController = this.getController('keyboardNavigation'); + const scrollable = rowsView.getScrollable(); + const $scrollContainer = $(scrollable._container()); + const keyboardController = this.getController('keyboardNavigation'); keyboardController._focusedView = rowsView; // assert @@ -2541,9 +2448,7 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle }); QUnit.testInActiveWindow('Fire onFocusedRowChanging by DownArrow key', function(assert) { - let rowsView; let focusedRowChangingCount = 0; - let keyboardController; // arrange this.data = [ @@ -2576,8 +2481,8 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle this.clock.tick(); - rowsView = this.gridView.getView('rowsView'); - keyboardController = this.getController('keyboardNavigation'); + const rowsView = this.gridView.getView('rowsView'); + const keyboardController = this.getController('keyboardNavigation'); keyboardController._focusedView = rowsView; // assert @@ -2590,8 +2495,6 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle }); QUnit.testInActiveWindow('Fire onFocusedRowChanging by Tab key', function(assert) { - let rowsView; - let keyboardController; let focusedRowChangingCounter = 0; // arrange @@ -2625,11 +2528,11 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle this.gridView.render($('#container')); this.clock.tick(); - $(this.gridView.getView('rowsView').getRow(1).find('td').eq(0)).trigger(pointerEvents.up).click(); + $(this.getCellElement(1, 0)).trigger(CLICK_EVENT).click(); this.clock.tick(); - rowsView = this.gridView.getView('rowsView'); - keyboardController = this.getController('keyboardNavigation'); + const rowsView = this.gridView.getView('rowsView'); + const keyboardController = this.getController('keyboardNavigation'); keyboardController._focusedView = rowsView; // assert @@ -2656,8 +2559,6 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle }); QUnit.testInActiveWindow('Fire onFocusedRowChanging by Tab key in back order (shift presset)', function(assert) { - let rowsView; - let keyboardController; let focusedRowChangingCounter = 0; // arrange @@ -2691,11 +2592,11 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle this.gridView.render($('#container')); this.clock.tick(); - $(this.gridView.getView('rowsView').getRow(1).find('td').eq(2)).trigger(pointerEvents.up).click(); + $(this.getCellElement(1, 2)).trigger(CLICK_EVENT).click(); this.clock.tick(); - rowsView = this.gridView.getView('rowsView'); - keyboardController = this.getController('keyboardNavigation'); + const rowsView = this.gridView.getView('rowsView'); + const keyboardController = this.getController('keyboardNavigation'); keyboardController._focusedView = rowsView; // assert @@ -2756,7 +2657,7 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle this.clock.tick(); // act - $(this.gridView.getView('rowsView').getRow(1).find('td').eq(0)).trigger(pointerEvents.up).click(); + $(this.getCellElement(1, 0)).trigger(CLICK_EVENT).click(); this.clock.tick(); assert.equal(focusedRowChangingCount, 1, 'focusedRowChanging count'); @@ -2767,9 +2668,6 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle QUnit.testInActiveWindow('Focused row events should not fire if dataGrid is in loading phase', function(assert) { let focusedRowChangingCount = 0; let focusedRowChangedCount = 0; - let dataController; - let keyboardController; - const items = [ { name: 'Alex', phone: '111111', room: 6 }, { name: 'Dan', phone: '2222222', room: 5 }, @@ -2817,15 +2715,15 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle this.gridView.render($('#container')); - dataController = this.getController('data'); + const dataController = this.getController('data'); this.clock.tick(10); - keyboardController = this.getController('keyboardNavigation'); + const keyboardController = this.getController('keyboardNavigation'); keyboardController._focusedView = this.gridView.getView('rowsView'); // act - $(this.gridView.getView('rowsView').getRow(1).find('td').eq(0)).trigger(pointerEvents.up).click(); + $(this.getCellElement(1, 0)).trigger(CLICK_EVENT).click(); keyboardController._upDownKeysHandler({ key: 'ArrowDown', keyName: 'downArrow' }); keyboardController._upDownKeysHandler({ key: 'ArrowDown', keyName: 'downArrow' }); keyboardController._upDownKeysHandler({ key: 'ArrowDown', keyName: 'downArrow' }); @@ -2839,7 +2737,7 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle // T850527 QUnit.testInActiveWindow('onFocusedChanged args should be correct after data change', function(assert) { // arrange - let onFocusedRowChangedSpy = sinon.spy(); + const onFocusedRowChangedSpy = sinon.spy(); this.data = [ { id: 1 }, @@ -2861,7 +2759,7 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle this.clock.tick(); // act - $(this.gridView.getView('rowsView').getRow(0).find('td').eq(0)).trigger(pointerEvents.up).click(); + $(this.getCellElement(0, 0)).trigger(CLICK_EVENT).click(); this.clock.tick(); assert.equal(onFocusedRowChangedSpy.callCount, 1, 'focusedRowChanged count'); @@ -2925,9 +2823,6 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle QUnit.test('onFocusedCellChanged event should contains correct row object if scrolling mode is virtual', function(assert) { const that = this; let focusedCellChangedCount = 0; - let rowsView; - let scrollable; - let visibleRow; // arrange that.data = generateItems(50); @@ -2961,17 +2856,17 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle that.setupModule(); that.gridView.render($('#container')); - rowsView = that.gridView.getView('rowsView'); + const rowsView = that.gridView.getView('rowsView'); rowsView.height(100); rowsView.resize(); - scrollable = rowsView.getScrollable(); + const scrollable = rowsView.getScrollable(); that.clock.tick(); // act scrollable.scrollBy({ y: 400 }); that.clock.tick(); - visibleRow = that.getVisibleRows()[0]; + const visibleRow = that.getVisibleRows()[0]; $(that.getCellElement(0, 1)).trigger(CLICK_EVENT); // assert assert.equal(focusedCellChangedCount, 1, 'onFocusedCellChanged fires count'); @@ -2980,9 +2875,6 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle QUnit.test('onFocusedCellChanged event should contains correct row object if scrolling, rowRenderingMode are virtual', function(assert) { const that = this; let focusedCellChangedCount = 0; - let rowsView; - let scrollable; - let visibleRow; // arrange that.data = generateItems(50); @@ -3016,25 +2908,23 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle that.setupModule(); that.gridView.render($('#container')); - rowsView = that.gridView.getView('rowsView'); + + const rowsView = that.gridView.getView('rowsView'); rowsView.height(100); rowsView.resize(); - scrollable = rowsView.getScrollable(); - + const scrollable = rowsView.getScrollable(); that.clock.tick(); // act scrollable.scrollBy({ y: 400 }); that.clock.tick(); - visibleRow = that.getVisibleRows()[0]; + const visibleRow = that.getVisibleRows()[0]; $(that.getCellElement(0, 1)).trigger(CLICK_EVENT); // assert assert.equal(focusedCellChangedCount, 1, 'onFocusedCellChanged fires count'); }); QUnit.testInActiveWindow('Setting cancel in onFocusedCellChanging event should prevent focusing next cell', function(assert) { - let rowsView; - let keyboardController; let focusedColumnChangingCount = 0; // arrange @@ -3076,8 +2966,8 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle this.gridView.render($('#container')); this.clock.tick(); - rowsView = this.gridView.getView('rowsView'); - keyboardController = this.getController('keyboardNavigation'); + const rowsView = this.gridView.getView('rowsView'); + const keyboardController = this.getController('keyboardNavigation'); keyboardController._focusedView = rowsView; // assert @@ -3091,8 +2981,6 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle }); QUnit.testInActiveWindow('DataGrid should fire onFocusedCellChanging event if next focused cell is not valid', function(assert) { - let rowsView; - let keyboardController; let onFocusedCellCount = 0; // arrange @@ -3127,9 +3015,9 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle this.clock.tick(); - rowsView = this.gridView.getView('rowsView'); + const rowsView = this.gridView.getView('rowsView'); - keyboardController = this.getController('keyboardNavigation'); + const keyboardController = this.getController('keyboardNavigation'); keyboardController._focusedView = rowsView; // assert @@ -3144,8 +3032,6 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle }); QUnit.testInActiveWindow('Fire onFocusedCellChanging by click', function(assert) { - let rowsView; - let keyboardController; let focusedColumnChangingCount = 0; // arrange @@ -3176,12 +3062,12 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle this.gridView.render($('#container')); this.clock.tick(); - rowsView = this.gridView.getView('rowsView'); - keyboardController = this.getController('keyboardNavigation'); + const rowsView = this.gridView.getView('rowsView'); + const keyboardController = this.getController('keyboardNavigation'); keyboardController._focusedView = rowsView; // act - $(this.gridView.getView('rowsView').getRow(4).find('td').eq(1)).trigger(pointerEvents.up).click(); + $(this.getCellElement(4, 1)).trigger(CLICK_EVENT).click(); this.clock.tick(); // assert assert.equal(this.getController('keyboardNavigation').getVisibleColumnIndex(), 1, 'Focused column index'); @@ -3189,8 +3075,6 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle }); QUnit.testInActiveWindow('Highlight cell by isHighlighted arg in the onFocusedCellChanging event by click event', function(assert) { - let rowsView; - let keyboardController; let focusedColumnChangingCount = 0; // arrange @@ -3216,12 +3100,12 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle this.gridView.render($('#container')); this.clock.tick(); - rowsView = this.gridView.getView('rowsView'); - keyboardController = this.getController('keyboardNavigation'); + const rowsView = this.gridView.getView('rowsView'); + const keyboardController = this.getController('keyboardNavigation'); keyboardController._focusedView = rowsView; // act - $(rowsView.getRow(4).find('td').eq(1)).trigger(pointerEvents.up).click(); + $(this.getCellElement(4, 1)).trigger(CLICK_EVENT).click(); this.clock.tick(); // assert assert.equal(this.getController('keyboardNavigation').getVisibleColumnIndex(), 1, 'Focused column index'); @@ -3230,8 +3114,6 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle }); QUnit.testInActiveWindow('isHighlighted in the onFocusedCellChanged event', function(assert) { - let rowsView; - let keyboardController; let focusedColumnChangingCount = 0; let focusedColumnChangedCount = 0; @@ -3252,12 +3134,12 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle this.gridView.render($('#container')); this.clock.tick(); - rowsView = this.gridView.getView('rowsView'); - keyboardController = this.getController('keyboardNavigation'); + const rowsView = this.gridView.getView('rowsView'); + const keyboardController = this.getController('keyboardNavigation'); keyboardController._focusedView = rowsView; // act - $(rowsView.getRow(1).find('td').eq(1)).trigger(pointerEvents.up).click(); + $(this.getCellElement(1, 1)).trigger(CLICK_EVENT).click(); this.clock.tick(); // assert assert.equal(focusedColumnChangingCount, 1, 'onFocusedCellChanging fires count'); @@ -3269,8 +3151,6 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle // arrange let focusedRowChangedCount = 0; let focusedRowChangingCount = 0; - let rowsView; - this.data = [ { name: 'Alex', phone: '111111', room: 6 }, { name: 'Dan', phone: '2222222', room: 5 } @@ -3296,12 +3176,10 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle this.clock.tick(); - rowsView = this.gridView.getView('rowsView'); - // act this.option('focusedRowEnabled', true); - $(rowsView.getRow(1).find('td').eq(1)).trigger(pointerEvents.up).click(); + $(this.getCellElement(1, 1)).trigger(CLICK_EVENT).click(); // assert assert.equal(focusedRowChangedCount, 1, 'onFocusedRowChanged fires count'); @@ -3309,7 +3187,6 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle }); QUnit.testInActiveWindow('onFocusedCellChanged event', function(assert) { - let rowsView; let focusedCellChangedCount = 0; // arrange @@ -3345,16 +3222,13 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle this.clock.tick(); // act - rowsView = this.gridView.getView('rowsView'); - $(rowsView.getRow(1).find('td').eq(1)).trigger(pointerEvents.up).click(); + const rowsView = this.gridView.getView('rowsView'); + $(this.getCellElement(1, 1)).trigger(CLICK_EVENT).click(); assert.equal(focusedCellChangedCount, 1, 'onFocusedCellChanged fires count'); }); QUnit.testInActiveWindow('onFocusedCellChanged event should fire if row index changed', function(assert) { - let rowsView; let focusedCellChangedCount = 0; - let keyboardController; - // arrange this.data = [ { name: 'Alex', phone: '111111', room: 6 }, @@ -3387,8 +3261,8 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle this.clock.tick(); // act - rowsView = this.gridView.getView('rowsView'); - keyboardController = this.getController('keyboardNavigation'); + const rowsView = this.gridView.getView('rowsView'); + const keyboardController = this.getController('keyboardNavigation'); keyboardController._focusedView = rowsView; // assert @@ -3401,10 +3275,7 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle }); QUnit.testInActiveWindow('onFocusedCellChanged event should not fire if cell position not changed', function(assert) { - let rowsView; let focusedCellChangedCount = 0; - let keyboardController; - // arrange this.data = [ { name: 'Alex', phone: '111111', room: 6 }, @@ -3434,8 +3305,8 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle this.clock.tick(); // act - rowsView = this.gridView.getView('rowsView'); - keyboardController = this.getController('keyboardNavigation'); + const rowsView = this.gridView.getView('rowsView'); + const keyboardController = this.getController('keyboardNavigation'); keyboardController._focusedView = rowsView; // assert @@ -3452,8 +3323,6 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle // T755462 QUnit.testInActiveWindow('The page with focused row should load without errors after sorting the boolean column', function(assert) { // arrange - let focusedRowIndex; - this.data = [ { name: 'Alex', phone: '111111', isRoom: true }, { name: 'Dan', phone: '2222222', isRoom: true }, @@ -3502,7 +3371,7 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle this.clock.tick(); // assert - focusedRowIndex = this.option('focusedRowIndex'); + const focusedRowIndex = this.option('focusedRowIndex'); assert.strictEqual(this.pageIndex(), 1, 'pageIndex'); assert.strictEqual(this.dataController.getVisibleRows()[focusedRowIndex].data, this.data[0], 'Focused row data is on the page'); @@ -3522,7 +3391,6 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle QUnit.test('Focused row should be visible if set focusedRowKey', function(assert) { // arrange - let rowsView; let counter = 0; this.data = [ @@ -3544,7 +3412,7 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle this.setupModule(); this.gridView.render($('#container')); - rowsView = this.gridView.getView('rowsView'); + const rowsView = this.gridView.getView('rowsView'); rowsView.scrollToElementVertically = $row => { ++counter; assert.equal($row.find('td').eq(0).text(), 'Smith', 'Row'); @@ -3559,10 +3427,6 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle }); QUnit.testInActiveWindow('Keyboard navigation controller should find next cell if column index is wrong when jump from the group row', function(assert) { - let rowsView; - let keyboardController; - let $cell; - // arrange this.data = [ { name: 'Alex', phone: '111111', room: 6 }, @@ -3598,21 +3462,18 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle this.clock.tick(); - rowsView = this.gridView.getView('rowsView'); - keyboardController = this.getController('keyboardNavigation'); + const rowsView = this.gridView.getView('rowsView'); + const keyboardController = this.getController('keyboardNavigation'); keyboardController._focusedView = rowsView; // assert assert.equal(this.option('focusedRowIndex'), 0, 'FocusedRowIndex is 0'); // act - $cell = keyboardController._getNextCell('downArrow'); + const $cell = keyboardController._getNextCell('downArrow'); // assert assert.ok(keyboardController._isCellValid($cell), 'Found valid cell'); }); QUnit.testInActiveWindow('DataGrid should focus the row bellow by arrowDown key if grid focused and if selection multiple', function(assert) { - let rowsView; - let keyboardController; - // arrange this.data = [ { name: 'Alex', phone: '111111', room: 6 }, @@ -3643,8 +3504,8 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle this.clock.tick(); - rowsView = this.gridView.getView('rowsView'); - keyboardController = this.getController('keyboardNavigation'); + const rowsView = this.gridView.getView('rowsView'); + const keyboardController = this.getController('keyboardNavigation'); keyboardController._focusedView = rowsView; // assert assert.equal(this.option('focusedRowIndex'), 0, 'FocusedRowIndex is 0'); @@ -3656,9 +3517,6 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle }); QUnit.testInActiveWindow('DataGrid should not focus inserted but not saved rows (T727182)', function(assert) { - let rowsView; - let keyboardController; - this.options = { keyExpr: 'name', focusedRowEnabled: true, @@ -3673,8 +3531,9 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle addOptionChangedHandlers(this); this.gridView.render($('#container')); this.clock.tick(); - rowsView = this.gridView.getView('rowsView'); - keyboardController = this.getController('keyboardNavigation'); + + const rowsView = this.gridView.getView('rowsView'); + const keyboardController = this.getController('keyboardNavigation'); keyboardController._focusedView = rowsView; // assert @@ -3696,8 +3555,6 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle QUnit.testInActiveWindow('DataGrid should reset focused row if \'e.newRowIndex\' is set to < 0 value in the onFocusedRowChanging event (T745451)', function(assert) { // arrange let focusedRowChangingCount = 0; - let rowsView; - this.$element = function() { return $('#container'); }; @@ -3715,7 +3572,7 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle this.setupModule(); addOptionChangedHandlers(this); this.gridView.render($('#container')); - rowsView = this.gridView.getView('rowsView'); + const rowsView = this.gridView.getView('rowsView'); this.clock.tick(); try { @@ -3761,7 +3618,7 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle assert.equal($(this.getCellElement(0, 0)).attr('tabindex'), 0, 'tabindex'); }); - QUnit.testInActiveWindow('Highlight cell on click when startEditAction is \'dblClick\'', function(assert) { + QUnit.testInActiveWindow('Highlight cell on click when startEditAction: dblClick', function(assert) { // arrange let focusedCellChangingCount = 0; @@ -3782,7 +3639,7 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle this.clock.tick(); // act - $(this.getCellElement(0, 0)).trigger(pointerEvents.up).click(); + $(this.getCellElement(0, 0)).trigger(CLICK_EVENT).click(); this.clock.tick(); // assert @@ -3791,8 +3648,6 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle }); QUnit.testInActiveWindow('DataGrid - onFocusedCellChanging event should execute on cell click in batch edit mode (T743530)', function(assert) { - let rowsView; - let keyboardController; let focusedCellChangingCount = 0; // arrange @@ -3813,12 +3668,12 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle this.gridView.render($('#container')); this.clock.tick(); - rowsView = this.gridView.getView('rowsView'); - keyboardController = this.getController('keyboardNavigation'); + const rowsView = this.gridView.getView('rowsView'); + const keyboardController = this.getController('keyboardNavigation'); keyboardController._focusedView = rowsView; // act - $(rowsView.getRow(0).find('td').eq(1)).trigger(pointerEvents.up).click(); + $(this.getCellElement(0, 1)).trigger(CLICK_EVENT).click(); this.clock.tick(); // assert assert.equal(focusedCellChangingCount, 1, 'onFocusedCellChanging fires count'); @@ -3880,6 +3735,66 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle assert.equal(this.option('focusedRowKey'), 'Mark2', 'FocusedRowkey'); }); + QUnit.test('autoNavigateToFocusedRow == false and paging if scrolling mode is virtual', function(assert) { + this.options = { + focusedRowEnabled: true, + autoNavigateToFocusedRow: false, + onFocusedRowChanged: sinon.spy(), + keyExpr: 'id', + scrolling: { + mode: 'virtual' + }, + pager: { + visible: true + }, + paging: { + pageSize: 2 + } + }; + + this.data = [ + { id: 1 }, + { id: 2 }, + { id: 3 }, + { id: 4 }, + { id: 5 }, + { id: 6 }, + { id: 7 }, + { id: 8 } + ]; + + this.setupModule(); + addOptionChangedHandlers(this); + + this.gridView.render($('#container')); + this.clock.tick(); + + this.option('focusedRowIndex', 0); + + // assert + assert.equal(this.option('focusedRowIndex'), 0, 'focusedRowIndex'); + assert.equal(this.option('focusedRowKey'), 1, 'focusedRowkey'); + assert.equal(this.options.onFocusedRowChanged.callCount, 1, 'onFocusedRowChanged called once'); + + // act + this.pageIndex(3); + this.clock.tick(); + + // assert + assert.equal(this.option('focusedRowIndex'), 0, 'focusedRowIndex'); + assert.equal(this.option('focusedRowKey'), 1, 'focusedRowkey'); + assert.equal(this.options.onFocusedRowChanged.callCount, 1, 'onFocusedRowChanged called once'); + + // act + this.pageIndex(0); + this.clock.tick(); + + // assert + assert.equal(this.option('focusedRowIndex'), 0, 'focusedRowIndex'); + assert.equal(this.option('focusedRowKey'), 1, 'focusedRowkey'); + assert.equal(this.options.onFocusedRowChanged.callCount, 1, 'onFocusedRowChanged called once'); + }); + QUnit.test('Change \'pageIndex\' by API without focused row should focus it by \'focusedRowIndex\' if autoNavigateToFocusedRow == false and row or cell was focused', function(assert) { // arrange this.options = { @@ -4121,8 +4036,6 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle }); QUnit.testInActiveWindow('FocusedRow should present if set focusedRowIndex', function(assert) { - let rowsView; - // arrange this.options = { focusedRowEnabled: true, @@ -4136,7 +4049,7 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle this.clock.tick(); - rowsView = this.gridView.getView('rowsView'); + const rowsView = this.gridView.getView('rowsView'); // assert assert.notOk($(rowsView.getRow(0)).hasClass('dx-row-focused'), 'Row 0 has no focus'); @@ -4173,8 +4086,6 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle }); QUnit.testInActiveWindow('Focus row if virtual scrolling mode', function(assert) { - let rowsView; - // arrange this.options = { focusedRowIndex: 4, @@ -4205,7 +4116,7 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle this.clock.tick(); - rowsView = this.gridView.getView('rowsView'); + const rowsView = this.gridView.getView('rowsView'); // assert assert.equal(this.option('focusedRowIndex'), 4, 'FocusedRowIndex = 4'); @@ -4213,8 +4124,6 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle }); QUnit.testInActiveWindow('Focus row if virtual scrolling and index is on the not loaded page', function(assert) { - let rowsView; - // arrange this.options = { height: 40, @@ -4247,7 +4156,7 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle this.clock.tick(); - rowsView = this.gridView.getView('rowsView'); + const rowsView = this.gridView.getView('rowsView'); // assert assert.equal(this.option('focusedRowIndex'), 3, 'focusedRowIndex'); @@ -4399,8 +4308,6 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle }); QUnit.testInActiveWindow('Focus row if grouping and virtual scrolling mode', function(assert) { - let rowsView; - // arrange this.options = { keyExpr: 'name', @@ -4440,7 +4347,7 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle this.clock.tick(); - rowsView = this.gridView.getView('rowsView'); + const rowsView = this.gridView.getView('rowsView'); // assert assert.equal(this.option('focusedRowIndex'), 9, 'FocusedRowIndex'); @@ -4449,8 +4356,6 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle }); QUnit.test('Focus next row if grouping and virtual scrolling mode', function(assert) { - let rowsView; - // arrange this.options = { keyExpr: 'name', @@ -4486,7 +4391,7 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle addOptionChangedHandlers(this); - rowsView = this.gridView.getView('rowsView'); + const rowsView = this.gridView.getView('rowsView'); this.gridView.render($('#container')); rowsView.height(140); @@ -4508,10 +4413,6 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle }); QUnit.testInActiveWindow('DataGrid should focus row by focusedRowIndex if data was filtered', function(assert) { - let rowsView; - let visibleRows; - let keyboardController; - // arrange this.data = [ { team: 'internal', name: 'Alex', age: 30 }, @@ -4540,9 +4441,9 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle this.dataController.load(); this.clock.tick(); - rowsView = this.gridView.getView('rowsView'); - visibleRows = this.dataController.getVisibleRows(); - keyboardController = this.getController('keyboardNavigation'); + const rowsView = this.gridView.getView('rowsView'); + const visibleRows = this.dataController.getVisibleRows(); + const keyboardController = this.getController('keyboardNavigation'); keyboardController._focusedView = rowsView; keyboardController.focus(rowsView.getRow(0).children('td').eq(0)); @@ -4554,9 +4455,6 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle }); QUnit.testInActiveWindow('DataGrid should focus the row by focusedRowKey if row key present in data after filter', function(assert) { - let rowsView; - let visibleRows; - // arrange this.data = [ { team: 'internal', name: 'Alex', age: 30 }, @@ -4589,8 +4487,8 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle this.dataController.load(); this.clock.tick(); - rowsView = this.gridView.getView('rowsView'); - visibleRows = this.dataController.getVisibleRows(); + const rowsView = this.gridView.getView('rowsView'); + const visibleRows = this.dataController.getVisibleRows(); // assert assert.equal(this.option('focusedRowIndex'), 1, 'focusedRowIndex'); @@ -4600,10 +4498,6 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle }); QUnit.testInActiveWindow('DataGrid should focus the row below by arrowDown key if grid focused and grouping enabled', function(assert) { - let rowsView; - let keyboardController; - let $cell; - // arrange this.data = [ { name: 'Alex', phone: '111111', room: 6 }, @@ -4632,22 +4526,20 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle this.clock.tick(); - rowsView = this.gridView.getView('rowsView'); - keyboardController = this.getController('keyboardNavigation'); + const rowsView = this.gridView.getView('rowsView'); + const keyboardController = this.getController('keyboardNavigation'); keyboardController._focusedView = rowsView; // act keyboardController.setFocusedColumnIndex(0); keyboardController.focus(rowsView.getRow(1).find('td').eq(0)); - $cell = keyboardController._getNextCell('downArrow'); + const $cell = keyboardController._getNextCell('downArrow'); // assert assert.equal($cell, undefined, 'Cell is undefined'); }); QUnit.testInActiveWindow('DataGrid should focus the corresponding group row if group collapsed and inner data row was focused', function(assert) { - let rowsView; - // arrange this.data = [ { team: 'internal', name: 'Alex', age: 30 }, @@ -4675,7 +4567,7 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle this.clock.tick(); - rowsView = this.gridView.getView('rowsView'); + const rowsView = this.gridView.getView('rowsView'); // assert assert.equal(this.getVisibleRows()[3].rowType, 'group', 'group row'); @@ -4694,8 +4586,6 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle }); QUnit.testInActiveWindow('DataGrid should focus the corresponding group row if group collapsed and inner data row was focused if calculateGroupValue is used', function(assert) { - let rowsView; - // arrange this.data = [ { team: 'internal', name: 'Alex', age: 30 }, @@ -4723,7 +4613,7 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle this.clock.tick(); - rowsView = this.gridView.getView('rowsView'); + const rowsView = this.gridView.getView('rowsView'); // assert assert.equal(this.getVisibleRows()[3].rowType, 'group', 'group row'); @@ -4893,9 +4783,8 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle }); QUnit.testInActiveWindow('Highlight cell on focus() if focusedRowEnabled is true and focusedColumnIndex, focusedRowIndex are set', function(assert) { - let focusedCellChangingCount = 0; - let keyboardController; // arrange + let focusedCellChangingCount = 0; this.options = { focusedRowIndex: 1, focusedColumnIndex: 1, @@ -4911,7 +4800,7 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle this.gridView.render($('#container')); this.clock.tick(); - keyboardController = this.getController('keyboardNavigation'); + const keyboardController = this.getController('keyboardNavigation'); keyboardController._focusedView = this.getView('rowsView'); keyboardController.focus(null); this.clock.tick(); @@ -4922,9 +4811,8 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle }); QUnit.testInActiveWindow('Not highlight cell on focus() if focusedRowEnabled is true and focusedColumnIndex is not set', function(assert) { - let focusedCellChangingCount = 0; - let keyboardController; // arrange + let focusedCellChangingCount = 0; this.options = { focusedRowEnabled: true, onFocusedCellChanging: function(e) { @@ -4936,7 +4824,7 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle this.gridView.render($('#container')); this.clock.tick(); - keyboardController = this.getController('keyboardNavigation'); + const keyboardController = this.getController('keyboardNavigation'); keyboardController._focusedView = this.getView('rowsView'); keyboardController.focus(null); this.clock.tick(); @@ -5117,10 +5005,7 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle }); QUnit.testInActiveWindow('onFocusedCellChanged event should not fire if cell position updates for not cell element', function(assert) { - let rowsView; let focusedCellChangedCount = 0; - let keyboardController; - // arrange this.data = [ { name: 'Alex', phone: '111111', room: 6 }, @@ -5140,8 +5025,8 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle this.clock.tick(); // act - rowsView = this.gridView.getView('rowsView'); - keyboardController = this.getController('keyboardNavigation'); + const rowsView = this.gridView.getView('rowsView'); + const keyboardController = this.getController('keyboardNavigation'); keyboardController._updateFocusedCellPosition(rowsView.getRow(1)); // assert @@ -5180,8 +5065,6 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle }); QUnit.test('Test navigateToRow method if paging', function(assert) { - let keyboardController; - // arrange this.data = [ { name: 'Alex', phone: '111111', room: 6 }, @@ -5207,7 +5090,7 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle this.gridView.render($('#container')); this.clock.tick(); - keyboardController = this.getController('keyboardNavigation'); + const keyboardController = this.getController('keyboardNavigation'); assert.equal(this.pageIndex(), 0, 'Page index'); assert.equal(keyboardController.getVisibleRowIndex(), undefined, 'Focused row index'); @@ -5220,8 +5103,6 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle }); QUnit.test('Test navigateToRow method if virtualScrolling', function(assert) { - let keyboardController; - // arrange this.data = [ { name: 'Alex', phone: '111111', room: 6 }, @@ -5250,7 +5131,7 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle this.gridView.render($('#container')); this.clock.tick(); - keyboardController = this.getController('keyboardNavigation'); + const keyboardController = this.getController('keyboardNavigation'); assert.equal(this.pageIndex(), 0, 'Page index'); assert.equal(keyboardController.getVisibleRowIndex(), undefined, 'Focused row index'); @@ -5307,8 +5188,6 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle QUnit.test('Focused row should preserve on navigation to the other row in infinite scrolling mode if page not loaded', function(assert) { // arrange - let rowsView; - this.data = [ { name: 'Alex', phone: '111111', room: 6 }, { name: 'Dan', phone: '2222222', room: 5 }, @@ -5336,7 +5215,7 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle this.setupModule(); this.gridView.render($('#container')); - rowsView = this.gridView.getView('rowsView'); + const rowsView = this.gridView.getView('rowsView'); rowsView.height(100); rowsView.resize(); this.clock.tick(); @@ -5350,8 +5229,6 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle }); QUnit.testInActiveWindow('If editing in row edit mode and focusedRowEnabled - focusOverlay should render for the editing row', function(assert) { - let rowsView; - // arrange this.options = { keyExpr: 'name', @@ -5375,7 +5252,7 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle this.gridView.component.editRow(1); this.clock.tick(); - rowsView = this.gridView.getView('rowsView'); + const rowsView = this.gridView.getView('rowsView'); $(rowsView.getRow(1).find('td').eq(0)).trigger(pointerEvents.up).click(); @@ -5386,8 +5263,6 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle }); QUnit.testInActiveWindow('If editing in cell edit mode and focusedRowEnabled - focusOverlay should render for the editing row', function(assert) { - let rowsView; - // arrange this.options = { keyExpr: 'name', @@ -5409,7 +5284,7 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle // act this.editCell(1, 1); - rowsView = this.gridView.getView('rowsView'); + const rowsView = this.gridView.getView('rowsView'); $(rowsView.getRow(1).find('td').eq(1)).trigger(pointerEvents.up).click(); this.clock.tick(); @@ -5472,7 +5347,6 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle QUnit.testInActiveWindow('DataGrid should not focus adaptive rows', function(assert) { // arrange - let rowsView; let focusedRowChangingCount = 0; let focusedRowChangedCount = 0; @@ -5497,7 +5371,7 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle // act this.expandRow('Dan'); this.clock.tick(); - rowsView = this.gridView.getView('rowsView'); + const rowsView = this.gridView.getView('rowsView'); $(rowsView.getRow(2).find('td').first()).trigger(pointerEvents.up).click(); // assert @@ -5507,7 +5381,6 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle QUnit.testInActiveWindow('DataGrid should reset focused row if focusedRowKey is set to undefined', function(assert) { // arrange - let rowsView; let focusedRowChangedCallsCount = 0; this.options = { @@ -5525,7 +5398,7 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle this.clock.tick(); // assert - rowsView = this.gridView.getView('rowsView'); + const rowsView = this.gridView.getView('rowsView'); assert.ok($(rowsView.getRow(1)).hasClass('dx-row-focused'), 'focused row'); assert.equal(this.keyboardNavigationController._focusedCellPosition.rowIndex, this.option('focusedRowIndex'), 'Keyboard navigation focused row index'); @@ -5561,8 +5434,6 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle QUnit.testInActiveWindow('DataGrid should reset focused row if focusedRowIndex is set to < 0', function(assert) { // arrange - let rowsView; - this.options = { keyExpr: 'name', focusedRowEnabled: true, @@ -5575,7 +5446,7 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle this.clock.tick(); // assert - rowsView = this.gridView.getView('rowsView'); + const rowsView = this.gridView.getView('rowsView'); assert.ok($(rowsView.getRow(1)).hasClass('dx-row-focused'), 'focused row'); assert.ok(this.option('focusedRowKey'), 'focusedRowKey'); @@ -5689,8 +5560,6 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle QUnit.testInActiveWindow('DataGrid - click by cell should not generate exception if rowTemplate is used (T800604)', function(assert) { let d = $.Deferred(); - let rowsView; - let keyboardController; const items = generateItems(1); // arrange @@ -5722,11 +5591,11 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle this.clock.tick(); this.gridView.render($('#container')); - rowsView = this.gridView.getView('rowsView'); + const rowsView = this.gridView.getView('rowsView'); rowsView.height(100); rowsView.resize(); - keyboardController = this.getController('keyboardNavigation'); + const keyboardController = this.getController('keyboardNavigation'); keyboardController._focusedView = rowsView; // act @@ -5741,8 +5610,6 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle }); QUnit.test('autoNavigateToFocusedRow == false and focusedRowKey', function(assert) { - let rowsView; - // arrange this.options = { height: 100, @@ -5766,7 +5633,7 @@ QUnit.module('FocusedRow with real dataController, keyboard and columnsControlle addOptionChangedHandlers(this); this.gridView.render($('#container')); - rowsView = this.gridView.getView('rowsView'); + const rowsView = this.gridView.getView('rowsView'); rowsView.height(100); rowsView.resize(); diff --git a/testing/tests/DevExpress.ui.widgets.dataGrid/gridView.tests.js b/testing/tests/DevExpress.ui.widgets.dataGrid/gridView.tests.js index 88470b78c871..f3d403bed9b8 100644 --- a/testing/tests/DevExpress.ui.widgets.dataGrid/gridView.tests.js +++ b/testing/tests/DevExpress.ui.widgets.dataGrid/gridView.tests.js @@ -377,7 +377,7 @@ function createGridView(options, userOptions) { headers = testElement.find('.dx-datagrid-headers'); // assert - assert.ok(headers.length === 0, 'headers are hidden'); + assert.strictEqual(headers.length, 0, 'headers are hidden'); }); QUnit.test('Hide borders by default', function(assert) { @@ -450,7 +450,7 @@ function createGridView(options, userOptions) { headers = testElement.find('.dx-datagrid-headers'); // assert - assert.ok(headers.length === 0, 'headers are hidden'); + assert.strictEqual(headers.length, 0, 'headers are hidden'); }); // B239207 diff --git a/testing/tests/DevExpress.ui.widgets.dataGrid/headerFilter.tests.js b/testing/tests/DevExpress.ui.widgets.dataGrid/headerFilter.tests.js index f95eaf8be442..a79a0ebd0100 100644 --- a/testing/tests/DevExpress.ui.widgets.dataGrid/headerFilter.tests.js +++ b/testing/tests/DevExpress.ui.widgets.dataGrid/headerFilter.tests.js @@ -1408,7 +1408,7 @@ QUnit.test('Indicator state when there is filterValues in the grouped column', f $headerFilter = that.headerPanel.element().find('.dx-group-panel-item').first().find('.dx-header-filter'); assert.equal($headerFilter.length, 1, 'have header filter'); assert.ok(!$headerFilter.hasClass('dx-header-filter-empty'), 'has no class dx-header-filter-empty'); - assert.ok($headerFilter.css('color') === $headerFilter.parent().css('color'), 'color of the header should be as parent color'); + assert.strictEqual($headerFilter.css('color'), $headerFilter.parent().css('color'), 'color of the header should be as parent color'); }); QUnit.test('Header filter popup should be shown on header filter icon click in groupPanel', function(assert) { @@ -1509,7 +1509,7 @@ QUnit.test('Indicator state when there is no filterValues in the grouped column' $headerFilter = that.headerPanel.element().find('.dx-group-panel-item').first().find('.dx-header-filter'); assert.equal($headerFilter.length, 1, 'have header filter'); assert.ok($headerFilter.hasClass('dx-header-filter-empty'), 'has no class dx-header-filter-empty'); - assert.ok($headerFilter.css('color') !== $headerFilter.parent().css('color'), 'color of the header filter should hava alpha'); + assert.notStrictEqual($headerFilter.css('color'), $headerFilter.parent().css('color'), 'color of the header filter should hava alpha'); }); // T260241 diff --git a/testing/tests/DevExpress.ui.widgets.dataGrid/headerPanel.tests.js b/testing/tests/DevExpress.ui.widgets.dataGrid/headerPanel.tests.js index fa210e099a68..3c9e74f5bc4a 100644 --- a/testing/tests/DevExpress.ui.widgets.dataGrid/headerPanel.tests.js +++ b/testing/tests/DevExpress.ui.widgets.dataGrid/headerPanel.tests.js @@ -67,7 +67,7 @@ QUnit.test('Draw searchPanel', function(assert) { searchPanel = testElement.find('.dx-datagrid-search-panel'); assert.strictEqual(input.length, 1); - assert.ok(searchPanel.length === 1); + assert.strictEqual(searchPanel.length, 1); assert.equal(searchPanel.outerWidth(), 160, 'search panel width'); }); @@ -356,7 +356,7 @@ QUnit.test('Enter text in searchPanel', function(assert) { // assert searchPanel = testElement.find('.dx-datagrid-search-panel'); - assert.ok(searchPanel.length === 1); + assert.strictEqual(searchPanel.length, 1); searchPanel.dxTextBox('instance').option('value', '123'); assert.equal(this.option('searchPanel.text'), '123'); }); @@ -379,7 +379,7 @@ QUnit.test('Draw searchPanel custom width', function(assert) { const input = testElement.find('input'); searchPanel = testElement.find('.dx-datagrid-search-panel'); assert.strictEqual(input.length, 1); - assert.ok(searchPanel.length === 1); + assert.strictEqual(searchPanel.length, 1); assert.equal(searchPanel.outerWidth(), 213, 'default search panel width'); }); diff --git a/testing/tests/DevExpress.ui.widgets.dataGrid/keyboardNavigation.keyboardController.tests.js b/testing/tests/DevExpress.ui.widgets.dataGrid/keyboardNavigation.keyboardController.tests.js index f1ff651c1338..dc3292ffcc7f 100644 --- a/testing/tests/DevExpress.ui.widgets.dataGrid/keyboardNavigation.keyboardController.tests.js +++ b/testing/tests/DevExpress.ui.widgets.dataGrid/keyboardNavigation.keyboardController.tests.js @@ -232,43 +232,39 @@ QUnit.module('Keyboard controller', { QUnit.testInActiveWindow('Element of view is subscribed to events', function(assert) { // arrange const navigationController = new KeyboardNavigationController(this.component); - let element; // act navigationController.init(); navigationController._focusView(); - element = navigationController.getFocusedView().element(); + + const element = navigationController.getFocusedView().element(); callViewsRenderCompleted(this.component._views); // assert - assert.equal(element.eventsInfo[eventUtils.addNamespace(pointerEvents.up, 'dxDataGridKeyboardNavigation')].subscribeToEventCounter, 1, 'Subscribed'); assert.equal(element.eventsInfo[eventUtils.addNamespace(pointerEvents.down, 'dxDataGridKeyboardNavigation')].subscribeToEventCounter, 1, 'Subscribed'); }); QUnit.testInActiveWindow('Element of view is unsubscribed from events', function(assert) { // arrange const navigationController = new KeyboardNavigationController(this.component); - let element; // act navigationController.init(); navigationController._focusView(); - element = navigationController.getFocusedView().element(); + + const element = navigationController.getFocusedView().element(); callViewsRenderCompleted(this.component._views); // assert - assert.equal(element.eventsInfo[eventUtils.addNamespace(pointerEvents.up, 'dxDataGridKeyboardNavigation')].unsubscribeFromEventCounter, 1, 'Unsubscribed'); assert.equal(element.eventsInfo[eventUtils.addNamespace(pointerEvents.down, 'dxDataGridKeyboardNavigation')].unsubscribeFromEventCounter, 1, 'Unsubscribed'); }); // T579521 QUnit.testInActiveWindow('Master detail cell is not focused when clicked on self', function(assert) { // arrange - let navigationController; let isFocused = false; - let $masterDetailCell; const $rowsElement = $('
').append($('
')).appendTo('#container'); this.getView('rowsView').element = function() { @@ -276,12 +272,12 @@ QUnit.module('Keyboard controller', { }; // act - navigationController = new KeyboardNavigationController(this.component); + const navigationController = new KeyboardNavigationController(this.component); navigationController.init(); callViewsRenderCompleted(this.component._views); - $masterDetailCell = $rowsElement.find('td')[0]; + const $masterDetailCell = $rowsElement.find('td')[0]; $masterDetailCell.focus = function() { isFocused = true; @@ -296,18 +292,16 @@ QUnit.module('Keyboard controller', { // T281701 QUnit.testInActiveWindow('Cell is not focused when clicked it in another grid', function(assert) { // arrange - let navigationController; let isFocused = false; - let $cell; const $rowsElement = $('
').addClass('.dx-datagrid').append($('
') - .text(that._getDayCaption(that._getFirstDayOfWeek() + i)); + _renderHeaderCell: function(cellIndex, $headerRow) { + const { + full: fullCaption, + abbreviated: abbrCaption + } = this._getDayCaption(this._getFirstDayOfWeek() + cellIndex); + const $cell = $('') + .attr({ + scope: 'col', + abbr: fullCaption + }) + .text(abbrCaption); - appendCell($headerRow, $cell); - }); + this._appendCell($headerRow, $cell); }, getNavigatorCaption: function() { - return dateLocalization.format(this.option('date'), 'monthandyear'); + return formatMessage(this.option('date'), 'monthandyear'); }, _isTodayCell: function(cellDate) { const today = new Date(); - return dateUtils.sameDate(cellDate, today); + return sameDate(cellDate, today); }, _isDateOutOfRange: function(cellDate) { const minDate = this.option('min'); const maxDate = this.option('max'); - return !dateUtils.dateInRange(cellDate, minDate, maxDate, 'date'); + return !dateInRange(cellDate, minDate, maxDate, 'date'); }, _isOtherView: function(cellDate) { @@ -90,17 +108,21 @@ const Views = { }, _getCellText: function(cellDate) { - return dateLocalization.format(cellDate, 'd'); + return formatMessage(cellDate, 'd'); }, _getDayCaption: function(day) { const daysInWeek = this.option('colCount'); + const dayIndex = day % daysInWeek; - return dateLocalization.getDayNames('abbreviated')[day % daysInWeek]; + return { + full: getDayNames()[dayIndex], + abbreviated: getDayNames('abbreviated')[dayIndex] + }; }, _getFirstCellData: function() { - const firstDay = dateUtils.getFirstMonthDate(this.option('date')); + const firstDay = getFirstMonthDate(this.option('date')); let firstMonthDayOffset = this._getFirstDayOfWeek() - firstDay.getDay(); const daysInWeek = this.option('colCount'); @@ -119,21 +141,21 @@ const Views = { }, _getFirstDayOfWeek: function() { - return typeUtils.isDefined(this.option('firstDayOfWeek')) ? this.option('firstDayOfWeek') : dateLocalization.firstDayOfWeekIndex(); + return isDefined(this.option('firstDayOfWeek')) ? this.option('firstDayOfWeek') : firstDayOfWeekIndex(); }, _getCellByDate: function(date) { - return this._$table.find('td[data-value=\'' + dateSerialization.serializeDate(date, dateUtils.getShortDateFormat()) + '\']'); + return this._$table.find(`td[data-value='${serializeDate(date, getShortDateFormat())}']`); }, isBoundary: function(date) { - return dateUtils.sameMonthAndYear(date, this.option('min')) || dateUtils.sameMonthAndYear(date, this.option('max')); + return sameMonthAndYear(date, this.option('min')) || sameMonthAndYear(date, this.option('max')); }, _getDefaultDisabledDatesHandler: function(disabledDates) { return function(args) { const isDisabledDate = disabledDates.some(function(item) { - return dateUtils.sameDate(item, args.date); + return sameDate(item, args.date); }); if(isDisabledDate) { @@ -150,11 +172,11 @@ const Views = { }, _isTodayCell: function(cellDate) { - return dateUtils.sameMonthAndYear(cellDate, new Date()); + return sameMonthAndYear(cellDate, new Date()); }, _isDateOutOfRange: function(cellDate) { - return !dateUtils.dateInRange(cellDate, dateUtils.getFirstMonthDate(this.option('min')), dateUtils.getLastMonthDate(this.option('max'))); + return !dateInRange(cellDate, getFirstMonthDate(this.option('min')), getLastMonthDate(this.option('max'))); }, _isOtherView: function() { @@ -162,7 +184,7 @@ const Views = { }, _getCellText: function(cellDate) { - return dateLocalization.getMonthNames('abbreviated')[cellDate.getMonth()]; + return getMonthNames('abbreviated')[cellDate.getMonth()]; }, _getFirstCellData: function() { @@ -184,19 +206,19 @@ const Views = { const foundDate = new Date(date); foundDate.setDate(1); - return this._$table.find('td[data-value=\'' + dateSerialization.serializeDate(foundDate, dateUtils.getShortDateFormat()) + '\']'); + return this._$table.find(`td[data-value='${serializeDate(foundDate, getShortDateFormat())}']`); }, getCellAriaLabel: function(date) { - return dateLocalization.format(date, 'monthandyear'); + return formatMessage(date, 'monthandyear'); }, getNavigatorCaption: function() { - return dateLocalization.format(this.option('date'), 'yyyy'); + return formatMessage(this.option('date'), 'yyyy'); }, isBoundary: function(date) { - return dateUtils.sameYear(date, this.option('min')) || dateUtils.sameYear(date, this.option('max')); + return sameYear(date, this.option('min')) || sameYear(date, this.option('max')); } }), @@ -207,29 +229,29 @@ const Views = { }, _isTodayCell: function(cellDate) { - return dateUtils.sameYear(cellDate, new Date()); + return sameYear(cellDate, new Date()); }, _isDateOutOfRange: function(cellDate) { const min = this.option('min'); const max = this.option('max'); - return !dateUtils.dateInRange(cellDate.getFullYear(), min && min.getFullYear(), max && max.getFullYear()); + return !dateInRange(cellDate.getFullYear(), min && min.getFullYear(), max && max.getFullYear()); }, _isOtherView: function(cellDate) { const date = new Date(cellDate); date.setMonth(1); - return !dateUtils.sameDecade(date, this.option('date')); + return !sameDecade(date, this.option('date')); }, _getCellText: function(cellDate) { - return dateLocalization.format(cellDate, 'yyyy'); + return formatMessage(cellDate, 'yyyy'); }, _getFirstCellData: function() { - const year = dateUtils.getFirstYearInDecade(this.option('date')) - 1; + const year = getFirstYearInDecade(this.option('date')) - 1; return new Date(year, 0, 1); }, @@ -241,18 +263,18 @@ const Views = { getNavigatorCaption: function() { const currentDate = this.option('date'); - const firstYearInDecade = dateUtils.getFirstYearInDecade(currentDate); + const firstYearInDecade = getFirstYearInDecade(currentDate); const startDate = new Date(currentDate); const endDate = new Date(currentDate); startDate.setFullYear(firstYearInDecade); endDate.setFullYear(firstYearInDecade + 9); - return dateLocalization.format(startDate, 'yyyy') + '-' + dateLocalization.format(endDate, 'yyyy'); + return formatMessage(startDate, 'yyyy') + '-' + formatMessage(endDate, 'yyyy'); }, _isValueOnCurrentView: function(currentDate, value) { - return dateUtils.sameDecade(currentDate, value); + return sameDecade(currentDate, value); }, _getCellByDate: function(date) { @@ -260,11 +282,11 @@ const Views = { foundDate.setDate(1); foundDate.setMonth(0); - return this._$table.find('td[data-value=\'' + dateSerialization.serializeDate(foundDate, dateUtils.getShortDateFormat()) + '\']'); + return this._$table.find(`td[data-value='${serializeDate(foundDate, getShortDateFormat())}']`); }, isBoundary: function(date) { - return dateUtils.sameDecade(date, this.option('min')) || dateUtils.sameDecade(date, this.option('max')); + return sameDecade(date, this.option('min')) || sameDecade(date, this.option('max')); } }), @@ -275,35 +297,35 @@ const Views = { }, _isTodayCell: function(cellDate) { - return dateUtils.sameDecade(cellDate, new Date()); + return sameDecade(cellDate, new Date()); }, _isDateOutOfRange: function(cellDate) { - const decade = dateUtils.getFirstYearInDecade(cellDate); - const minDecade = dateUtils.getFirstYearInDecade(this.option('min')); - const maxDecade = dateUtils.getFirstYearInDecade(this.option('max')); + const decade = getFirstYearInDecade(cellDate); + const minDecade = getFirstYearInDecade(this.option('min')); + const maxDecade = getFirstYearInDecade(this.option('max')); - return !dateUtils.dateInRange(decade, minDecade, maxDecade); + return !dateInRange(decade, minDecade, maxDecade); }, _isOtherView: function(cellDate) { const date = new Date(cellDate); date.setMonth(1); - return !dateUtils.sameCentury(date, this.option('date')); + return !sameCentury(date, this.option('date')); }, _getCellText: function(cellDate) { - const startDate = dateLocalization.format(cellDate, 'yyyy'); + const startDate = formatMessage(cellDate, 'yyyy'); const endDate = new Date(cellDate); endDate.setFullYear(endDate.getFullYear() + 9); - return startDate + ' - ' + dateLocalization.format(endDate, 'yyyy'); + return startDate + ' - ' + formatMessage(endDate, 'yyyy'); }, _getFirstCellData: function() { - const decade = dateUtils.getFirstDecadeInCentury(this.option('date')) - 10; + const decade = getFirstDecadeInCentury(this.option('date')) - 10; return new Date(decade, 0, 1); }, @@ -317,25 +339,25 @@ const Views = { const foundDate = new Date(date); foundDate.setDate(1); foundDate.setMonth(0); - foundDate.setFullYear(dateUtils.getFirstYearInDecade(foundDate)); + foundDate.setFullYear(getFirstYearInDecade(foundDate)); - return this._$table.find('td[data-value=\'' + dateSerialization.serializeDate(foundDate, dateUtils.getShortDateFormat()) + '\']'); + return this._$table.find(`td[data-value='${serializeDate(foundDate, getShortDateFormat())}']`); }, getNavigatorCaption: function() { const currentDate = this.option('date'); - const firstDecadeInCentury = dateUtils.getFirstDecadeInCentury(currentDate); + const firstDecadeInCentury = getFirstDecadeInCentury(currentDate); const startDate = new Date(currentDate); const endDate = new Date(currentDate); startDate.setFullYear(firstDecadeInCentury); endDate.setFullYear(firstDecadeInCentury + 99); - return dateLocalization.format(startDate, 'yyyy') + '-' + dateLocalization.format(endDate, 'yyyy'); + return formatMessage(startDate, 'yyyy') + '-' + formatMessage(endDate, 'yyyy'); }, isBoundary: function(date) { - return dateUtils.sameCentury(date, this.option('min')) || dateUtils.sameCentury(date, this.option('max')); + return sameCentury(date, this.option('min')) || sameCentury(date, this.option('max')); } }) }; diff --git a/js/ui/collection/ui.collection_widget.edit.js b/js/ui/collection/ui.collection_widget.edit.js index ef21df6115cf..42a4bb83a37e 100644 --- a/js/ui/collection/ui.collection_widget.edit.js +++ b/js/ui/collection/ui.collection_widget.edit.js @@ -8,7 +8,8 @@ import { noop } from '../../core/utils/common'; import { isDefined } from '../../core/utils/type'; import PlainEditStrategy from './ui.collection_widget.edit.strategy.plain'; import { compileGetter } from '../../core/utils/data'; -import { DataSource, normalizeLoadResult } from '../../data/data_source/data_source'; +import { DataSource } from '../../data/data_source/data_source'; +import { normalizeLoadResult } from '../../data/data_source/utils'; import Selection from '../selection/selection'; import { when, Deferred, fromPromise } from '../../core/utils/deferred'; diff --git a/js/ui/data_grid.d.ts b/js/ui/data_grid.d.ts index 332a0ea0c32c..ebb3cc0558a8 100644 --- a/js/ui/data_grid.d.ts +++ b/js/ui/data_grid.d.ts @@ -19,7 +19,10 @@ import { } from '../events/index'; import { - ExcelDataGridCell, + ExcelDataGridCell +} from '../excel_exporter'; + +import { ExcelFont } from '../exporter/excel/excel.doc_comments'; diff --git a/js/ui/date_box/ui.date_box.base.js b/js/ui/date_box/ui.date_box.base.js index 5d1068af2aac..b440be7c09fb 100644 --- a/js/ui/date_box/ui.date_box.base.js +++ b/js/ui/date_box/ui.date_box.base.js @@ -676,17 +676,6 @@ const DateBox = DropDownEditor.inherit({ this.option('text', this._getDisplayedText(this.dateOption('value'))); this._renderInputValue(); break; - case 'formatWidthCalculator': - break; - case 'closeOnValueChange': { - const applyValueMode = args.value ? 'instantly' : 'useButtons'; - this.option('applyValueMode', applyValueMode); - break; - } - case 'applyValueMode': - this.option('closeOnValueChange', args.value === 'instantly'); - this.callBase.apply(this, arguments); - break; case 'text': this._strategy.textChangedHandler(args.value); this.callBase.apply(this, arguments); @@ -697,6 +686,7 @@ const DateBox = DropDownEditor.inherit({ break; case 'showDropDownButton': this._formatValidationIcon(); + this.callBase.apply(this, arguments); break; case 'readOnly': this.callBase.apply(this, arguments); diff --git a/js/ui/date_box/ui.date_box.mask.js b/js/ui/date_box/ui.date_box.mask.js index 921682e08faa..ddbcb23a18e3 100644 --- a/js/ui/date_box/ui.date_box.mask.js +++ b/js/ui/date_box/ui.date_box.mask.js @@ -12,6 +12,7 @@ import { getFormat } from '../../localization/ldml/date.format'; import { isString } from '../../core/utils/type'; import { sign } from '../../core/utils/math'; import DateBoxBase from './ui.date_box.base'; +import numberLocalization from '../../localization/number'; const MASK_EVENT_NAMESPACE = 'dateBoxMask'; const FORWARD = 1; @@ -118,8 +119,7 @@ const DateBoxMask = DateBoxBase.inherit({ useMaskBehavior: false, - emptyDateValue: new Date(2000, 0, 1, 0, 0, 0), - advanceCaret: true + emptyDateValue: new Date(2000, 0, 1, 0, 0, 0) }); }, @@ -184,10 +184,20 @@ const DateBoxMask = DateBoxBase.inherit({ } }, + _partLimitsReached(max) { + const maxLimitLength = String(max).length; + const formatLength = this._getActivePartProp('pattern').length; + const isShortFormat = formatLength === 1; + const maxSearchLength = isShortFormat ? maxLimitLength : Math.min(formatLength, maxLimitLength); + const isLengthExceeded = this._searchValue.length === maxSearchLength; + const isValueOverflowed = parseInt(this._searchValue + '0') > max; + + return isLengthExceeded || isValueOverflowed; + }, + _searchNumber(char) { const { max } = this._getActivePartLimits(); const maxLimitLength = String(max).length; - const formatLength = this._getActivePartProp('pattern').length; this._searchValue = (this._searchValue + char).substr(-maxLimitLength); if(isNaN(this._searchValue)) { @@ -196,15 +206,8 @@ const DateBoxMask = DateBoxBase.inherit({ this._setActivePartValue(this._searchValue); - if(this.option('advanceCaret')) { - const isShortFormat = formatLength === 1; - const maxSearchLength = isShortFormat ? maxLimitLength : Math.min(formatLength, maxLimitLength); - const isLengthExceeded = this._searchValue.length === maxSearchLength; - const isValueOverflowed = parseInt(this._searchValue + '0') > max; - - if(isLengthExceeded || isValueOverflowed) { - this._selectNextPart(FORWARD); - } + if(this._partLimitsReached(max)) { + this._selectNextPart(FORWARD); } }, @@ -252,10 +255,18 @@ const DateBoxMask = DateBoxBase.inherit({ return this.option('useMaskBehavior') && this.option('mode') === 'text'; }, + _prepareRegExpInfo() { + this._regExpInfo = getRegExpInfo(this._getFormatPattern(), dateLocalization); + const regExp = this._regExpInfo.regexp; + const flags = regExp.flags; + const convertedRegExp = numberLocalization.convertDigits(this._regExpInfo.regexp.source, false); + this._regExpInfo.regexp = RegExp(convertedRegExp, flags); + }, + _initMaskState() { this._activePartIndex = 0; this._formatPattern = null; - this._regExpInfo = getRegExpInfo(this._getFormatPattern(), dateLocalization); + this._prepareRegExpInfo(); this._loadMaskValue(); }, @@ -519,7 +530,6 @@ const DateBoxMask = DateBoxBase.inherit({ this.callBase(args); this._renderDateParts(); break; - case 'advanceCaret': case 'emptyDateValue': break; default: diff --git a/js/ui/date_box/ui.date_box.strategy.js b/js/ui/date_box/ui.date_box.strategy.js index d2fcc1816ebe..75f850b36d57 100644 --- a/js/ui/date_box/ui.date_box.strategy.js +++ b/js/ui/date_box/ui.date_box.strategy.js @@ -90,12 +90,6 @@ const DateBoxStrategy = Class.inherit({ this._widget && this._widget.option('value', this.dateBoxValue()); }, - _valueChangedHandler: function(args) { - if(this.dateBox.option('opened') && this.dateBox.option('applyValueMode') === 'instantly') { - this.dateBoxValue(args.value); - } - }, - useCurrentDateByDefault: noop, getDefaultDate: function() { diff --git a/js/ui/date_box/ui.date_box.strategy.list.js b/js/ui/date_box/ui.date_box.strategy.list.js index 6becb911d027..c991c8b0058f 100644 --- a/js/ui/date_box/ui.date_box.strategy.list.js +++ b/js/ui/date_box/ui.date_box.strategy.list.js @@ -8,6 +8,7 @@ const isDate = require('../../core/utils/type').isDate; const extend = require('../../core/utils/extend').extend; const dateUtils = require('./ui.date_utils'); const dateLocalization = require('../../localization/date'); +const dateSerialization = require('../../core/utils/date_serialization'); const DATE_FORMAT = 'date'; @@ -231,7 +232,11 @@ const ListStrategy = DateBoxStrategy.inherit({ const day = itemData.getDate(); if(date) { - date = new Date(date); + if(this.dateBox.option('dateSerializationFormat')) { + date = dateSerialization.deserializeDate(date); + } else { + date = new Date(date); + } date.setHours(hours); date.setMinutes(minutes); @@ -243,7 +248,7 @@ const ListStrategy = DateBoxStrategy.inherit({ date = new Date(year, month, day, hours, minutes, 0, 0); } - this.dateBoxValue(date); + this.dateBoxValue(date, e.event); }, getKeyboardListener() { diff --git a/js/ui/diagram.d.ts b/js/ui/diagram.d.ts index b666cd4ce13b..765badb6b571 100644 --- a/js/ui/diagram.d.ts +++ b/js/ui/diagram.d.ts @@ -206,7 +206,23 @@ export interface dxDiagramOptions extends WidgetOptions { * @prevFileNamespace DevExpress.ui * @public */ - toolbar?: { commands?: Array<'separator' | 'export' | 'undo' | 'redo' | 'cut' | 'copy' | 'paste' | 'selectAll' | 'delete' | 'fontName' | 'fontSize' | 'bold' | 'italic' | 'underline' | 'fontColor' | 'lineColor' | 'fillColor' | 'textAlignLeft' | 'textAlignCenter' | 'textAlignRight' | 'lock' | 'unlock' | 'sendToBack' | 'bringToFront' | 'insertShapeImage' | 'editShapeImage' | 'deleteShapeImage' | 'connectorLineType' | 'connectorLineStart' | 'connectorLineEnd' | 'autoLayout' | 'fullScreen'>, visible?: boolean }; + toolbar?: { commands?: Array<'separator' | 'export' | 'undo' | 'redo' | 'cut' | 'copy' | 'paste' | 'selectAll' | 'delete' | 'fontName' | 'fontSize' | 'bold' | 'italic' | 'underline' | 'fontColor' | 'lineColor' | 'fillColor' | 'textAlignLeft' | 'textAlignCenter' | 'textAlignRight' | 'lock' | 'unlock' | 'sendToBack' | 'bringToFront' | 'insertShapeImage' | 'editShapeImage' | 'deleteShapeImage' | 'connectorLineType' | 'connectorLineStart' | 'connectorLineEnd' | 'autoLayout' | 'fullScreen' | 'zoomLevel' | 'autoZoom' | 'showGrid' | 'snapToGrid' | 'gridSize' | 'units'>, visible?: boolean }; + /** + * @docid dxDiagramOptions.historyToolbar + * @type Object + * @default {} + * @prevFileNamespace DevExpress.ui + * @public + */ + historyToolbar?: { commands?: Array<'separator' | 'export' | 'undo' | 'redo' | 'cut' | 'copy' | 'paste' | 'selectAll' | 'delete' | 'fontName' | 'fontSize' | 'bold' | 'italic' | 'underline' | 'fontColor' | 'lineColor' | 'fillColor' | 'textAlignLeft' | 'textAlignCenter' | 'textAlignRight' | 'lock' | 'unlock' | 'sendToBack' | 'bringToFront' | 'insertShapeImage' | 'editShapeImage' | 'deleteShapeImage' | 'connectorLineType' | 'connectorLineStart' | 'connectorLineEnd' | 'autoLayout' | 'fullScreen' | 'zoomLevel' | 'autoZoom' | 'showGrid' | 'snapToGrid' | 'gridSize' | 'units'>, visible?: boolean }; + /** + * @docid dxDiagramOptions.viewToolbar + * @type Object + * @default {} + * @prevFileNamespace DevExpress.ui + * @public + */ + viewToolbar?: { commands?: Array<'separator' | 'export' | 'undo' | 'redo' | 'cut' | 'copy' | 'paste' | 'selectAll' | 'delete' | 'fontName' | 'fontSize' | 'bold' | 'italic' | 'underline' | 'fontColor' | 'lineColor' | 'fillColor' | 'textAlignLeft' | 'textAlignCenter' | 'textAlignRight' | 'lock' | 'unlock' | 'sendToBack' | 'bringToFront' | 'insertShapeImage' | 'editShapeImage' | 'deleteShapeImage' | 'connectorLineType' | 'connectorLineStart' | 'connectorLineEnd' | 'autoLayout' | 'fullScreen' | 'zoomLevel' | 'autoZoom' | 'showGrid' | 'snapToGrid' | 'gridSize' | 'units'>, visible?: boolean }; /** * @docid dxDiagramOptions.toolbox * @type Object @@ -356,4 +372,4 @@ interface JQuery { export type Options = dxDiagramOptions; /** @deprecated use Options instead */ -export type IOptions = dxDiagramOptions; \ No newline at end of file +export type IOptions = dxDiagramOptions; diff --git a/js/ui/diagram/diagram_bar.js b/js/ui/diagram/diagram.bar.js similarity index 71% rename from js/ui/diagram/diagram_bar.js rename to js/ui/diagram/diagram.bar.js index c391a612cace..c29a72d79b01 100644 --- a/js/ui/diagram/diagram_bar.js +++ b/js/ui/diagram/diagram.bar.js @@ -1,4 +1,4 @@ -import { getDiagram } from './diagram_importer'; +import { getDiagram } from './diagram.importer'; class DiagramBar { constructor(owner) { @@ -26,6 +26,19 @@ class DiagramBar { isVisible() { // IBar.isVisible(): boolean return true; } + + _getKeys(items) { + const keys = items.reduce((commands, item) => { + if(item.command !== undefined) { + commands.push(item.command); + } + if(item.items) { + commands = commands.concat(this._getKeys(item.items)); + } + return commands; + }, []); + return keys; + } } module.exports = DiagramBar; diff --git a/js/ui/diagram/ui.diagram.commands.js b/js/ui/diagram/diagram.commands_manager.js similarity index 66% rename from js/ui/diagram/ui.diagram.commands.js rename to js/ui/diagram/diagram.commands_manager.js index 6bd09e13ed2d..6db203ac5b66 100644 --- a/js/ui/diagram/ui.diagram.commands.js +++ b/js/ui/diagram/diagram.commands_manager.js @@ -1,4 +1,4 @@ -import { getDiagram } from './diagram_importer'; +import { getDiagram } from './diagram.importer'; import { extend } from '../../core/utils/extend'; import { fileSaver } from '../../exporter/file_saver'; import { isFunction } from '../../core/utils/type'; @@ -12,41 +12,33 @@ const CSS_CLASSES = { BUTTON_COLOR: 'dx-diagram-color-b', }; -const DiagramCommands = { - getAllToolbarCommands: function() { +const DiagramCommandsManager = { + getAllCommands: function() { const { DiagramCommand } = getDiagram(); - return this.toolbarCommands || - (this.toolbarCommands = { + return this.allCommands || + (this.allCommands = { separator: SEPARATOR, - export: { - widget: 'dxButton', - icon: 'export', - text: messageLocalization.format('dxDiagram-commandExport'), - hint: messageLocalization.format('dxDiagram-commandExport'), - items: [ - { - command: DiagramCommand.ExportSvg, // eslint-disable-line spellcheck/spell-checker - text: messageLocalization.format('dxDiagram-commandExportToSvg'), - getParameter: (widget) => { - return (dataURI) => this._exportTo(widget, dataURI, 'SVG', 'image/svg+xml'); - } - }, - { - command: DiagramCommand.ExportPng, // eslint-disable-line spellcheck/spell-checker - text: messageLocalization.format('dxDiagram-commandExportToPng'), - getParameter: (widget) => { - return (dataURI) => this._exportTo(widget, dataURI, 'PNG', 'image/png'); - } - }, - { - command: DiagramCommand.ExportJpg, // eslint-disable-line spellcheck/spell-checker - text: messageLocalization.format('dxDiagram-commandExportToJpg'), - getParameter: (widget) => { - return (dataURI) => this._exportTo(widget, dataURI, 'JPEG', 'image/jpeg'); - } - } - ] + exportSvg: { + command: DiagramCommand.ExportSvg, // eslint-disable-line spellcheck/spell-checker + text: messageLocalization.format('dxDiagram-commandExportToSvg'), + getParameter: (widget) => { + return (dataURI) => this._exportTo(widget, dataURI, 'SVG', 'image/svg+xml'); + } + }, + exportPng: { + command: DiagramCommand.ExportPng, // eslint-disable-line spellcheck/spell-checker + text: messageLocalization.format('dxDiagram-commandExportToPng'), + getParameter: (widget) => { + return (dataURI) => this._exportTo(widget, dataURI, 'PNG', 'image/png'); + } + }, + exportJpg: { + command: DiagramCommand.ExportJpg, // eslint-disable-line spellcheck/spell-checker + text: messageLocalization.format('dxDiagram-commandExportToJpg'), + getParameter: (widget) => { + return (dataURI) => this._exportTo(widget, dataURI, 'JPEG', 'image/jpeg'); + } }, undo: { command: DiagramCommand.Undo, @@ -85,7 +77,8 @@ const DiagramCommands = { command: DiagramCommand.SelectAll, hint: messageLocalization.format('dxDiagram-commandSelectAll'), text: messageLocalization.format('dxDiagram-commandSelectAll'), - icon: 'dx-diagram-i-button-select-all dx-diagram-i' + icon: 'dx-diagram-i-button-select-all dx-diagram-i', + menuIcon: 'dx-diagram-i-menu-select-all dx-diagram-i' }, delete: { command: DiagramCommand.Delete, @@ -170,40 +163,47 @@ const DiagramCommands = { command: DiagramCommand.Lock, hint: messageLocalization.format('dxDiagram-commandLock'), text: messageLocalization.format('dxDiagram-commandLock'), - icon: 'dx-diagram-i-button-lock dx-diagram-i' + icon: 'dx-diagram-i-button-lock dx-diagram-i', + menuIcon: 'dx-diagram-i-menu-lock dx-diagram-i' }, unlock: { command: DiagramCommand.Unlock, hint: messageLocalization.format('dxDiagram-commandUnlock'), text: messageLocalization.format('dxDiagram-commandUnlock'), - icon: 'dx-diagram-i-button-unlock dx-diagram-i' + icon: 'dx-diagram-i-button-unlock dx-diagram-i', + menuIcon: 'dx-diagram-i-menu-unlock dx-diagram-i' }, bringToFront: { command: DiagramCommand.BringToFront, hint: messageLocalization.format('dxDiagram-commandBringToFront'), text: messageLocalization.format('dxDiagram-commandBringToFront'), - icon: 'dx-diagram-i-button-bring-to-front dx-diagram-i' + icon: 'dx-diagram-i-button-bring-to-front dx-diagram-i', + menuIcon: 'dx-diagram-i-menu-bring-to-front dx-diagram-i' }, sendToBack: { command: DiagramCommand.SendToBack, hint: messageLocalization.format('dxDiagram-commandSendToBack'), text: messageLocalization.format('dxDiagram-commandSendToBack'), - icon: 'dx-diagram-i-button-send-to-back dx-diagram-i' + icon: 'dx-diagram-i-button-send-to-back dx-diagram-i', + menuIcon: 'dx-diagram-i-menu-send-to-back dx-diagram-i' }, insertShapeImage: { command: DiagramCommand.InsertShapeImage, text: messageLocalization.format('dxDiagram-commandInsertShapeImage'), - icon: 'dx-diagram-i-button-image-insert dx-diagram-i' + icon: 'dx-diagram-i-button-image-insert dx-diagram-i', + menuIcon: 'dx-diagram-i-menu-image-insert dx-diagram-i' }, editShapeImage: { command: DiagramCommand.EditShapeImage, text: messageLocalization.format('dxDiagram-commandEditShapeImage'), - icon: 'dx-diagram-i-button-image-edit dx-diagram-i' + icon: 'dx-diagram-i-button-image-edit dx-diagram-i', + menuIcon: 'dx-diagram-i-menu-image-edit dx-diagram-i' }, deleteShapeImage: { command: DiagramCommand.DeleteShapeImage, text: messageLocalization.format('dxDiagram-commandDeleteShapeImage'), - icon: 'dx-diagram-i-button-image-delete dx-diagram-i' + icon: 'dx-diagram-i-button-image-delete dx-diagram-i', + menuIcon: 'dx-diagram-i-menu-image-delete dx-diagram-i' }, connectorLineType: { command: DiagramCommand.ConnectorLineOption, @@ -304,56 +304,42 @@ const DiagramCommands = { text: messageLocalization.format('dxDiagram-commandFullscreen'), icon: 'dx-diagram-i dx-diagram-i-button-fullscreen', cssClass: CSS_CLASSES.BUTTON_COLOR - } - }); - }, - getToolbarCommands: function(commandNames) { - const commands = this.getAllToolbarCommands(); - if(commandNames) { - return commandNames.map(function(cn) { return commands[cn]; }).filter(function(c) { return c; }); - } - return [ - commands['export'], - commands['separator'], - commands['undo'], - commands['redo'], - commands['separator'], - commands['fontName'], - commands['fontSize'], - commands['separator'], - commands['bold'], - commands['italic'], - commands['underline'], - commands['separator'], - commands['fontColor'], - commands['lineColor'], - commands['fillColor'], - commands['separator'], - commands['textAlignLeft'], - commands['textAlignCenter'], - commands['textAlignRight'], - commands['separator'], - commands['connectorLineType'], - commands['connectorLineStart'], - commands['connectorLineEnd'], - commands['separator'], - commands['autoLayout'], - commands['separator'], - commands['fullScreen'] - ]; - }, + }, - getAllPropertyPanelCommands: function() { - const { DiagramCommand } = getDiagram(); - return this.propertyPanelCommands || - (this.propertyPanelCommands = { units: { command: DiagramCommand.ViewUnits, + hint: messageLocalization.format('dxDiagram-commandUnits'), text: messageLocalization.format('dxDiagram-commandUnits'), widget: 'dxSelectBox' }, + simpleView: { + command: DiagramCommand.ToggleSimpleView, + hint: messageLocalization.format('dxDiagram-commandSimpleView'), + text: messageLocalization.format('dxDiagram-commandSimpleView'), + widget: 'dxCheckBox' + }, + showGrid: { + command: DiagramCommand.ShowGrid, + hint: messageLocalization.format('dxDiagram-commandShowGrid'), + text: messageLocalization.format('dxDiagram-commandShowGrid'), + widget: 'dxCheckBox' + }, + snapToGrid: { + command: DiagramCommand.SnapToGrid, + hint: messageLocalization.format('dxDiagram-commandSnapToGrid'), + text: messageLocalization.format('dxDiagram-commandSnapToGrid'), + widget: 'dxCheckBox' + }, + gridSize: { + command: DiagramCommand.GridSize, + hint: messageLocalization.format('dxDiagram-commandGridSize'), + text: messageLocalization.format('dxDiagram-commandGridSize'), + widget: 'dxSelectBox' + }, + pageSize: { command: DiagramCommand.PageSize, + hint: messageLocalization.format('dxDiagram-commandPageSize'), text: messageLocalization.format('dxDiagram-commandPageSize'), widget: 'dxSelectBox', getValue: (v) => JSON.parse(v), @@ -361,6 +347,7 @@ const DiagramCommands = { }, pageOrientation: { command: DiagramCommand.PageLandscape, + hint: messageLocalization.format('dxDiagram-commandPageOrientation'), text: messageLocalization.format('dxDiagram-commandPageOrientation'), widget: 'dxSelectBox', items: [ @@ -370,162 +357,210 @@ const DiagramCommands = { }, pageColor: { command: DiagramCommand.PageColor, + hint: messageLocalization.format('dxDiagram-commandPageColor'), text: messageLocalization.format('dxDiagram-commandPageColor'), widget: 'dxColorBox', }, - showGrid: { - command: DiagramCommand.ShowGrid, - text: messageLocalization.format('dxDiagram-commandShowGrid'), - widget: 'dxCheckBox', - }, - snapToGrid: { - command: DiagramCommand.SnapToGrid, - text: messageLocalization.format('dxDiagram-commandSnapToGrid'), - widget: 'dxCheckBox' - }, - gridSize: { - command: DiagramCommand.GridSize, - text: messageLocalization.format('dxDiagram-commandGridSize'), - widget: 'dxSelectBox' - }, zoomLevel: { command: DiagramCommand.ZoomLevel, + hint: messageLocalization.format('dxDiagram-commandZoomLevel'), text: messageLocalization.format('dxDiagram-commandZoomLevel'), widget: 'dxSelectBox' }, autoZoom: { command: DiagramCommand.ToggleAutoZoom, + hint: messageLocalization.format('dxDiagram-commandAutoZoom'), text: messageLocalization.format('dxDiagram-commandAutoZoom'), widget: 'dxCheckBox' - }, - simpleView: { - command: DiagramCommand.ToggleSimpleView, - text: messageLocalization.format('dxDiagram-commandSimpleView'), - widget: 'dxCheckBox' - }, + } }); }, + getMainToolbarCommands: function(commands) { + const allCommands = this.getAllCommands(); + const mainToolbarCommands = commands ? this._getCustomCommands(allCommands, commands) : + this._getDefaultMainToolbarCommands(allCommands); + return this._prepareToolbarCommands(mainToolbarCommands); + }, + _getDefaultMainToolbarCommands: function(allCommands) { + return [ + allCommands['undo'], + allCommands['redo'], + allCommands['separator'], + allCommands['fontName'], + allCommands['fontSize'], + allCommands['separator'], + allCommands['bold'], + allCommands['italic'], + allCommands['underline'], + allCommands['separator'], + allCommands['fontColor'], + allCommands['lineColor'], + allCommands['fillColor'], + allCommands['separator'], + allCommands['textAlignLeft'], + allCommands['textAlignCenter'], + allCommands['textAlignRight'], + allCommands['separator'], + allCommands['connectorLineType'], + allCommands['connectorLineStart'], + allCommands['connectorLineEnd'], + allCommands['separator'], + allCommands['autoLayout'], + ]; + }, + getHistoryToolbarCommands: function(commands) { + const allCommands = this.getAllCommands(); + const historyToolbarCommands = commands ? this._getCustomCommands(allCommands, commands) : + this._getDefaultHistoryToolbarCommands(allCommands); + return this._prepareToolbarCommands(historyToolbarCommands); + }, + _getDefaultHistoryToolbarCommands: function(allCommands) { + return [ + allCommands['undo'], + allCommands['separator'], + allCommands['redo'] + ]; + }, + getViewToolbarCommands: function(commands) { + const allCommands = this.getAllCommands(); + const viewToolbarCommands = commands ? this._getCustomCommands(allCommands, commands) : + this._getDefaultViewToolbarCommands(allCommands); + return this._prepareToolbarCommands(viewToolbarCommands); + }, + _getDefaultViewToolbarCommands: function(allCommands) { + return [ + allCommands['zoomLevel'], + allCommands['separator'], + allCommands['fullScreen'], + allCommands['separator'], + { + widget: 'dxButton', + icon: 'export', + text: messageLocalization.format('dxDiagram-commandExport'), + hint: messageLocalization.format('dxDiagram-commandExport'), + items: [ + allCommands['exportSvg'], + allCommands['exportPng'], + allCommands['exportJpg'] + ] + }, + { + icon: 'preferences', + hint: messageLocalization.format('dxDiagram-commandProperties'), + text: messageLocalization.format('dxDiagram-commandProperties'), + items: [ + allCommands['units'], + allCommands['separator'], + allCommands['showGrid'], + allCommands['snapToGrid'], + allCommands['gridSize'], + allCommands['separator'], + allCommands['simpleView'] + ] + } + ]; + }, + getDefaultPropertyPanelCommandGroups: function() { return [ - { commands: ['units'] }, - { commands: ['pageSize', 'pageOrientation', 'pageColor'] }, - { commands: ['showGrid', 'snapToGrid', 'gridSize'] }, - { commands: ['zoomLevel', 'autoZoom', 'simpleView'] }, + { commands: ['pageSize', 'pageOrientation', 'pageColor'] } ]; }, - getPropertyPanelCommandsByGroups: function(groups) { - const commands = DiagramCommands.getAllPropertyPanelCommands(); + _getPropertyPanelCommandsByGroups: function(groups) { + const allCommands = this.getAllCommands(); const result = []; groups.forEach(function(g, gi) { g.commands.forEach(function(cn, ci) { - result.push(extend(commands[cn], { + result.push(extend({ beginGroup: gi > 0 && ci === 0 - })); + }, allCommands[cn])); }); }); return result; }, getPropertyPanelCommands: function(commandGroups) { - commandGroups = commandGroups || DiagramCommands.getDefaultPropertyPanelCommandGroups(); - return DiagramCommands.getPropertyPanelCommandsByGroups(commandGroups); + commandGroups = commandGroups || this.getDefaultPropertyPanelCommandGroups(); + return this._getPropertyPanelCommandsByGroups(commandGroups); }, - getAllContextMenuCommands: function() { - const { DiagramCommand } = getDiagram(); - return this.contextMenuCommands || - (this.contextMenuCommands = { - separator: SEPARATOR, - - cut: { - command: DiagramCommand.Cut, - text: messageLocalization.format('dxDiagram-commandCut'), - icon: 'cut' - }, - copy: { - command: DiagramCommand.Copy, - text: messageLocalization.format('dxDiagram-commandCopy'), - icon: 'copy' - }, - paste: { - command: DiagramCommand.PasteInPosition, - text: messageLocalization.format('dxDiagram-commandPaste'), - getParameter: (diagramContextMenu) => { - return diagramContextMenu.clickPosition; - }, - icon: 'paste' - }, - selectAll: { - command: DiagramCommand.SelectAll, - text: messageLocalization.format('dxDiagram-commandSelectAll'), - icon: 'dx-diagram-i-menu-select-all dx-diagram-i' - }, - delete: { - command: DiagramCommand.Delete, - text: messageLocalization.format('dxDiagram-commandDelete'), - icon: 'remove' - }, - bringToFront: { - command: DiagramCommand.BringToFront, - text: messageLocalization.format('dxDiagram-commandBringToFront'), - icon: 'dx-diagram-i-menu-bring-to-front dx-diagram-i' - }, - sendToBack: { - command: DiagramCommand.SendToBack, - text: messageLocalization.format('dxDiagram-commandSendToBack'), - icon: 'dx-diagram-i-menu-send-to-back dx-diagram-i' - }, - lock: { - command: DiagramCommand.Lock, - text: messageLocalization.format('dxDiagram-commandLock'), - icon: 'dx-diagram-i-menu-lock dx-diagram-i' - }, - unlock: { - command: DiagramCommand.Unlock, - text: messageLocalization.format('dxDiagram-commandUnlock'), - icon: 'dx-diagram-i-menu-unlock dx-diagram-i' - }, - insertShapeImage: { - command: DiagramCommand.InsertShapeImage, - text: messageLocalization.format('dxDiagram-commandInsertShapeImage'), - icon: 'dx-diagram-i-menu-image-insert dx-diagram-i' - }, - editShapeImage: { - command: DiagramCommand.EditShapeImage, - text: messageLocalization.format('dxDiagram-commandEditShapeImage'), - icon: 'dx-diagram-i-menu-image-edit dx-diagram-i' - }, - deleteShapeImage: { - command: DiagramCommand.DeleteShapeImage, - text: messageLocalization.format('dxDiagram-commandDeleteShapeImage'), - icon: 'dx-diagram-i-menu-image-delete dx-diagram-i' - } - }); + getContextMenuCommands: function(commands) { + const allCommands = this.getAllCommands(); + const contextMenuCommands = commands ? this._getCustomCommands(allCommands, commands) : + this._getDefaultContextMenuCommands(allCommands); + return this._prepareContextMenuCommands(contextMenuCommands); }, - getContextMenuCommands: function(commandNames) { - const commands = this.getAllContextMenuCommands(); - if(commandNames) { - return commandNames.map(function(cn) { return commands[cn]; }).filter(function(c) { return c; }); - } + _getDefaultContextMenuCommands: function(allCommands) { return [ - commands['cut'], - commands['copy'], - commands['paste'], - commands['delete'], - commands['separator'], - commands['selectAll'], - commands['separator'], - commands['bringToFront'], - commands['sendToBack'], - commands['separator'], - commands['lock'], - commands['unlock'], - commands['separator'], - commands['insertShapeImage'], - commands['editShapeImage'], - commands['deleteShapeImage'] + allCommands['cut'], + allCommands['copy'], + allCommands['paste'], + allCommands['delete'], + allCommands['separator'], + allCommands['selectAll'], + allCommands['separator'], + allCommands['bringToFront'], + allCommands['sendToBack'], + allCommands['separator'], + allCommands['lock'], + allCommands['unlock'], + allCommands['separator'], + allCommands['insertShapeImage'], + allCommands['editShapeImage'], + allCommands['deleteShapeImage'] ]; }, + _getCustomCommands(allCommands, customCommands) { + return customCommands.map(c => { + if(allCommands[c]) { + return allCommands[c]; + } else if(c.text || c.icon) { + const command = { + text: c.text, + icon: c.icon, + onExecuted: c.onClick + }; + if(Array.isArray(c.items)) { + command.items = this._getCustomCommands(allCommands, c.items); + } + return command; + } + }).filter(c => c); + }, + + _prepareContextMenuCommands(commands) { + const result = []; + let beginGroup = false; + commands.forEach(command => { + if(command === SEPARATOR) { + beginGroup = true; + } else { + if(typeof command === 'object') { + if(Array.isArray(command.items)) { + command.items = this._prepareContextMenuCommands(command.items); + } + result.push(extend(command, { + beginGroup: beginGroup + })); + } else { + result.push(command); + } + beginGroup = false; + } + }); + return result; + }, + _prepareToolbarCommands(commands) { + const result = []; + commands.forEach(command => { + if(Array.isArray(command.items)) { + command.items = this._prepareContextMenuCommands(command.items); + } + result.push(command); + }); + return result; + }, + _exportTo(widget, dataURI, format, mimeString) { const window = getWindow(); if(window && window.atob && isFunction(window.Blob)) { @@ -544,4 +579,4 @@ const DiagramCommands = { } }; -module.exports = DiagramCommands; +module.exports = DiagramCommandsManager; diff --git a/js/ui/diagram/diagram.edges_option.js b/js/ui/diagram/diagram.edges_option.js new file mode 100644 index 000000000000..3034bdabd4d9 --- /dev/null +++ b/js/ui/diagram/diagram.edges_option.js @@ -0,0 +1,9 @@ +import ItemsOption from './diagram.items_option'; + +class EdgesOption extends ItemsOption { + _getKeyExpr() { + return this._diagramWidget._createOptionGetter('edges.keyExpr'); + } +} + +module.exports = EdgesOption; diff --git a/js/ui/diagram/diagram_importer.js b/js/ui/diagram/diagram.importer.js similarity index 100% rename from js/ui/diagram/diagram_importer.js rename to js/ui/diagram/diagram.importer.js diff --git a/js/ui/diagram/diagram_item.js b/js/ui/diagram/diagram.items.js similarity index 100% rename from js/ui/diagram/diagram_item.js rename to js/ui/diagram/diagram.items.js diff --git a/js/ui/diagram/ui.diagram.items.js b/js/ui/diagram/diagram.items_option.js similarity index 100% rename from js/ui/diagram/ui.diagram.items.js rename to js/ui/diagram/diagram.items_option.js diff --git a/js/ui/diagram/ui.diagram.nodes.js b/js/ui/diagram/diagram.nodes_option.js similarity index 77% rename from js/ui/diagram/ui.diagram.nodes.js rename to js/ui/diagram/diagram.nodes_option.js index 3f2fc3de7ab6..740792f73729 100644 --- a/js/ui/diagram/ui.diagram.nodes.js +++ b/js/ui/diagram/diagram.nodes_option.js @@ -1,4 +1,4 @@ -import ItemsOption from './ui.diagram.items'; +import ItemsOption from './diagram.items_option'; class NodesOption extends ItemsOption { _getKeyExpr() { diff --git a/js/ui/diagram/ui.diagram.optionsupdate.js b/js/ui/diagram/diagram.options_update.js similarity index 97% rename from js/ui/diagram/ui.diagram.optionsupdate.js rename to js/ui/diagram/diagram.options_update.js index f50ac825e4e3..b5e06a574446 100644 --- a/js/ui/diagram/ui.diagram.optionsupdate.js +++ b/js/ui/diagram/diagram.options_update.js @@ -1,5 +1,5 @@ -import DiagramBar from './diagram_bar'; -import { getDiagram } from './diagram_importer'; +import DiagramBar from './diagram.bar'; +import { getDiagram } from './diagram.importer'; class DiagramOptionsUpdateBar extends DiagramBar { constructor(owner) { diff --git a/js/ui/diagram/diagram.toolbox_manager.js b/js/ui/diagram/diagram.toolbox_manager.js new file mode 100644 index 000000000000..b9542db53e43 --- /dev/null +++ b/js/ui/diagram/diagram.toolbox_manager.js @@ -0,0 +1,52 @@ +import messageLocalization from '../../localization/message'; + +const DiagramToolboxManager = { + getDefaultGroups() { + return this._groups || + (this._groups = { + general: { + category: 'general', + title: messageLocalization.format('dxDiagram-categoryGeneral') + }, + flowchart: { + category: 'flowchart', + title: messageLocalization.format('dxDiagram-categoryFlowchart') + }, + orgChart: { + category: 'orgChart', + title: messageLocalization.format('dxDiagram-categoryOrgChart') + }, + containers: { + category: 'containers', + title: messageLocalization.format('dxDiagram-categoryContainers') + }, + custom: { + category: 'custom', + title: messageLocalization.format('dxDiagram-categoryCustom') + } + }); + }, + + getGroups: function(groups) { + const defaultGroups = this.getDefaultGroups(); + if(groups) { + return groups.map(function(g) { + if(typeof g === 'string') { + return { + category: g, + title: (defaultGroups[g] && defaultGroups[g].title) || g + }; + } + return g; + }).filter(function(g) { return g; }); + } + return [ + defaultGroups['general'], + defaultGroups['flowchart'], + defaultGroups['orgChart'], + defaultGroups['containers'] + ]; + } +}; + +module.exports = DiagramToolboxManager; diff --git a/js/ui/diagram/ui.diagram.contextmenu.js b/js/ui/diagram/ui.diagram.context_menu.js similarity index 55% rename from js/ui/diagram/ui.diagram.contextmenu.js rename to js/ui/diagram/ui.diagram.context_menu.js index 37af48f2db8e..ff35cd59e4b1 100644 --- a/js/ui/diagram/ui.diagram.contextmenu.js +++ b/js/ui/diagram/ui.diagram.context_menu.js @@ -2,9 +2,11 @@ import $ from '../../core/renderer'; import Widget from '../widget/ui.widget'; import ContextMenu from '../context_menu'; -import DiagramCommands from './ui.diagram.commands'; -import DiagramBar from './diagram_bar'; -import { getDiagram } from './diagram_importer'; +import DiagramCommandsManager from './diagram.commands_manager'; +import DiagramMenuHelper from './ui.diagram.menu_helper'; + +import DiagramBar from './diagram.bar'; +import { getDiagram } from './diagram.importer'; const DIAGRAM_TOUCHBAR_CLASS = 'dx-diagram-touchbar'; const DIAGRAM_TOUCHBAR_TARGET_CLASS = 'dx-diagram-touchbar-target'; @@ -16,18 +18,18 @@ class DiagramContextMenu extends Widget { super._init(); this._createOnVisibleChangedAction(); this._createOnItemClickAction(); - this.bar = new ContextMenuBar(this); this._tempState = undefined; this._commands = []; this._commandToIndexMap = {}; + this.bar = new ContextMenuBar(this); } _initMarkup() { super._initMarkup(); - this._commands = DiagramCommands.getContextMenuCommands(this.option('commands')); + this._commands = this._getCommands(); this._commandToIndexMap = {}; - this._commands.forEach((item, index) => this._commandToIndexMap[item.command] = index); + this._fillCommandToIndexMap(this._commands, []); this._$contextMenuTargetElement = $('
') .addClass(DIAGRAM_TOUCHBAR_TARGET_CLASS) @@ -40,7 +42,7 @@ class DiagramContextMenu extends Widget { this._contextMenuInstance = this._createComponent($contextMenu, ContextMenu, { closeOnOutsideClick: false, showEvent: '', - cssClass: Browser.TouchUI ? DIAGRAM_TOUCHBAR_CLASS : '', + cssClass: Browser.TouchUI ? DIAGRAM_TOUCHBAR_CLASS : DiagramMenuHelper.getContextMenuCssClass(), items: this._getItems(this._commands), focusStateEnabled: false, position: (Browser.TouchUI ? { @@ -48,36 +50,20 @@ class DiagramContextMenu extends Widget { at: { x: 'center', y: 'top' }, of: this._$contextMenuTargetElement } : {}), + itemTemplate: function(itemData, itemIndex, itemElement) { + DiagramMenuHelper.getContextMenuItemTemplate(itemData, itemIndex, itemElement, this._menuHasCheckedItems); + }, onItemClick: ({ itemData }) => this._onItemClick(itemData), onShowing: (e) => { if(this._inOnShowing === true) return; this._inOnShowing = true; this._onVisibleChangedAction({ visible: true, component: this }); - this._contextMenuInstance.option('items', this._getItems(this._commands, true)); + e.component.option('items', this._getItems(this._commands, true)); delete this._inOnShowing; } }); } - _getItems(commands, onlyVisible) { - const items = []; - let beginGroup = false; - commands.forEach(function(command) { - if(command.widget === 'separator') { - beginGroup = true; - } else if(command.visible || !onlyVisible) { - items.push({ - command: command.command, - text: command.text, - icon: command.icon, - getParameter: command.getParameter, - beginGroup: beginGroup - }); - beginGroup = false; - } - }); - return items; - } _show(x, y, selection) { this.clickPosition = { x, y }; const { Browser } = getDiagram(); @@ -112,23 +98,92 @@ class DiagramContextMenu extends Widget { } if(!processed) { - const parameter = this._getExecCommandParameter(itemData); - this.bar.raiseBarCommandExecuted(itemData.command, parameter); + DiagramMenuHelper.onContextMenuItemClick(itemData, this._execDiagramCommand.bind(this)); this._contextMenuInstance.hide(); } } - _getExecCommandParameter(itemData) { - if(itemData.getParameter) { - return itemData.getParameter(this); + _execDiagramCommand(command, value, onExecuted) { + if(command !== undefined) { + this.bar.raiseBarCommandExecuted(command, value); } + + if(typeof onExecuted === 'function') { + onExecuted.call(this); + } + } + + _getCommands() { + return DiagramCommandsManager.getContextMenuCommands(this.option('commands')); + } + _fillCommandToIndexMap(commands, indexPath) { + commands.forEach((command, index) => { + const commandIndexPath = indexPath.concat([index]); + if(command.command !== undefined) { + this._commandToIndexMap[command.command] = commandIndexPath; + } + if(Array.isArray(command.items)) { + this._fillCommandToIndexMap(command.items, commandIndexPath); + } + }); + } + _getCommandByKey(key) { + const indexPath = this._commandToIndexMap[key]; + if(indexPath) { + let command; + let commands = this._commands; + indexPath.forEach(index => { + command = commands[index]; + commands = command.items; + }); + return command; + } + } + _getItems(commands, onlyVisible) { + const result = []; + commands.forEach(command => { + if(command.visible !== false || !onlyVisible) { + result.push(command); + } + }); + return result; } _setItemEnabled(key, enabled) { this._setItemVisible(key, enabled); } _setItemVisible(key, visible) { - if(key in this._commandToIndexMap) { - const command = this._commands[this._commandToIndexMap[key]]; - if(command) command.visible = visible; + const command = this._getCommandByKey(key); + if(command) command.visible = visible; + } + _setItemValue(key, value) { + const command = this._getCommandByKey(key); + if(command) { + if(value === true || value === false) { + this._setHasCheckedItems(-1); + command.checked = value; + } else if(value !== undefined) { + this._setHasCheckedItems(key); + command.items = command.items.map(item => { + return { + 'value': item.value, + 'text': item.text, + 'checked': item.value === value, + 'rootCommand': key + }; + }); + } + } + } + _setItemSubItems(key, items) { + const command = this._getCommandByKey(key); + if(command) { + command.items = items.map(item => { + return { + 'value': DiagramMenuHelper.getItemValue(item), + 'text': item.text, + 'checked': item.checked, + 'rootCommand': key + }; + }); } } _setEnabled(enabled) { @@ -137,6 +192,12 @@ class DiagramContextMenu extends Widget { isVisible() { return this._inOnShowing; } + _setHasCheckedItems(key) { + if(!this._contextMenuInstance._menuHasCheckedItems) { + this._contextMenuInstance._menuHasCheckedItems = {}; + } + this._contextMenuInstance._menuHasCheckedItems[key] = true; + } _createOnVisibleChangedAction() { this._onVisibleChangedAction = this._createActionByOption('onVisibleChanged'); } @@ -161,8 +222,15 @@ class DiagramContextMenu extends Widget { } class ContextMenuBar extends DiagramBar { + constructor(owner) { + super(owner); + } + getCommandKeys() { - return DiagramCommands.getContextMenuCommands().map(c => c.command); + return this._getKeys(this._owner._commands); + } + setItemValue(key, value) { + this._owner._setItemValue(key, value); } setItemEnabled(key, enabled) { this._owner._setItemEnabled(key, enabled); @@ -170,6 +238,9 @@ class ContextMenuBar extends DiagramBar { setItemVisible(key, visible) { this._owner._setItemVisible(key, visible); } + setItemSubItems(key, items) { + this._owner._setItemSubItems(key, items); + } setEnabled(enabled) { this._owner._setEnabled(enabled); } diff --git a/js/ui/diagram/ui.diagram.contexttoolbox.js b/js/ui/diagram/ui.diagram.context_toolbox.js similarity index 100% rename from js/ui/diagram/ui.diagram.contexttoolbox.js rename to js/ui/diagram/ui.diagram.context_toolbox.js diff --git a/js/ui/diagram/ui.diagram.dialogmanager.js b/js/ui/diagram/ui.diagram.dialog_manager.js similarity index 97% rename from js/ui/diagram/ui.diagram.dialogmanager.js rename to js/ui/diagram/ui.diagram.dialog_manager.js index 92f0a5782e9e..3a674e198161 100644 --- a/js/ui/diagram/ui.diagram.dialogmanager.js +++ b/js/ui/diagram/ui.diagram.dialog_manager.js @@ -1,5 +1,5 @@ import $ from '../../core/renderer'; -import { getDiagram } from './diagram_importer'; +import { getDiagram } from './diagram.importer'; import messageLocalization from '../../localization/message'; const FileUploader = require('../file_uploader'); diff --git a/js/ui/diagram/ui.diagram.dialogs.js b/js/ui/diagram/ui.diagram.dialogs.js index e9f6ad7a5d29..19f2c66a1a7c 100644 --- a/js/ui/diagram/ui.diagram.dialogs.js +++ b/js/ui/diagram/ui.diagram.dialogs.js @@ -20,7 +20,7 @@ class DiagramDialog extends Widget { this._$popupElement = $('
') .appendTo(this.$element()); - this._popupInstance = this._createComponent(this._$popupElement, Popup, { + this._popup = this._createComponent(this._$popupElement, Popup, { title: this.option('title'), maxWidth: this.option('maxWidth'), height: this.option('height'), @@ -29,7 +29,7 @@ class DiagramDialog extends Widget { }); } _clean() { - delete this._popupInstance; + delete this._popup; this._$popupElement && this._$popupElement.remove(); } _getDefaultOptions() { @@ -74,7 +74,7 @@ class DiagramDialog extends Widget { case 'maxWidth': case 'height': case 'toolbarItems': - this._popupInstance.option(args.name, args.value); + this._popup.option(args.name, args.value); break; case 'command': this._command = args.value; @@ -96,15 +96,15 @@ class DiagramDialog extends Widget { this._onHiddenAction = this._createActionByOption('onHidden'); } _hide() { - this._popupInstance.hide(); + this._popup.hide(); this._isShown = false; } _show() { - this._popupInstance + this._popup .content() .empty() .append(this._onGetContentAction()); - this._popupInstance.show(); + this._popup.show(); this._isShown = true; } isVisible() { diff --git a/js/ui/diagram/ui.diagram.edges.js b/js/ui/diagram/ui.diagram.edges.js deleted file mode 100644 index 10e46cbbbb6c..000000000000 --- a/js/ui/diagram/ui.diagram.edges.js +++ /dev/null @@ -1,9 +0,0 @@ -import ItemsOption from './ui.diagram.items'; - -class EdgesOptions extends ItemsOption { - _getKeyExpr() { - return this._diagramWidget._createOptionGetter('edges.keyExpr'); - } -} - -module.exports = EdgesOptions; diff --git a/js/ui/diagram/ui.diagram.floating_panel.js b/js/ui/diagram/ui.diagram.floating_panel.js new file mode 100644 index 000000000000..4d2a2358729e --- /dev/null +++ b/js/ui/diagram/ui.diagram.floating_panel.js @@ -0,0 +1,36 @@ +import $ from '../../core/renderer'; +import Widget from '../widget/ui.widget'; +import Popup from '../popup'; + +class DiagramFloatingPanel extends Widget { + _initMarkup() { + super._initMarkup(); + + const $parent = this.$element(); + + const $popupElement = $('
') + .addClass(this._getPopupClass()) + .appendTo($parent); + + this._popup = this._createComponent($popupElement, Popup, this._getPopupOptions()); + } + _getPopupClass() { + return ''; + } + _getPopupOptions() { + const that = this; + return { + animation: null, + shading: false, + focusStateEnabled: false, + height: this.option('height') || 'auto', + position: this.option('position'), + onContentReady: function() { + that._renderPopupContent(that._popup.content()); + } + }; + } + _renderPopupContent($parent) { + } +} +module.exports = DiagramFloatingPanel; diff --git a/js/ui/diagram/ui.diagram.history_toolbar.js b/js/ui/diagram/ui.diagram.history_toolbar.js new file mode 100644 index 000000000000..105bef23da22 --- /dev/null +++ b/js/ui/diagram/ui.diagram.history_toolbar.js @@ -0,0 +1,10 @@ +import DiagramToolbar from './ui.diagram.toolbar'; +import DiagramCommandsManager from './diagram.commands_manager'; + +class DiagramHistoryToolbar extends DiagramToolbar { + _getCommands() { + return DiagramCommandsManager.getHistoryToolbarCommands(this.option('commands')); + } +} + +module.exports = DiagramHistoryToolbar; diff --git a/js/ui/diagram/ui.diagram.js b/js/ui/diagram/ui.diagram.js index 1464543327cf..42db9937b899 100644 --- a/js/ui/diagram/ui.diagram.js +++ b/js/ui/diagram/ui.diagram.js @@ -6,25 +6,28 @@ import registerComponent from '../../core/component_registrator'; import { extend } from '../../core/utils/extend'; import typeUtils from '../../core/utils/type'; import dataCoreUtils from '../../core/utils/data'; -import DiagramToolbar from './ui.diagram.toolbar'; -import DiagramLeftPanel from './ui.diagram.leftpanel'; -import DiagramRightPanel from './ui.diagram.rightpanel'; -import DiagramContextMenu from './ui.diagram.contextmenu'; -import DiagramContextToolbox from './ui.diagram.contexttoolbox'; -import DiagramDialog from './ui.diagram.dialogs'; -import DiagramToolbox from './ui.diagram.toolbox'; -import DiagramOptionsUpdateBar from './ui.diagram.optionsupdate'; -import NodesOption from './ui.diagram.nodes'; -import EdgesOptions from './ui.diagram.edges'; -import Tooltip from '../tooltip'; -import { getDiagram } from './diagram_importer'; +import positionUtils from '../../animation/position'; +import { getDiagram } from './diagram.importer'; import { hasWindow, getWindow } from '../../core/utils/window'; import domUtils from '../../core/utils/dom'; import eventsEngine from '../../events/core/events_engine'; import * as eventUtils from '../../events/utils'; import messageLocalization from '../../localization/message'; import numberLocalization from '../../localization/number'; -import DiagramDialogManager from './ui.diagram.dialogmanager'; + +import DiagramMainToolbar from './ui.diagram.main_toolbar'; +import DiagramHistoryToolbar from './ui.diagram.history_toolbar'; +import DiagramViewToolbar from './ui.diagram.view_toolbar'; +import DiagramRightPanel from './ui.diagram.rightpanel'; +import DiagramContextMenu from './ui.diagram.context_menu'; +import DiagramContextToolbox from './ui.diagram.context_toolbox'; +import DiagramDialog from './ui.diagram.dialogs'; +import DiagramToolboxManager from './diagram.toolbox_manager'; +import DiagramToolbox from './ui.diagram.toolbox'; +import DiagramOptionsUpdateBar from './diagram.options_update'; +import DiagramDialogManager from './ui.diagram.dialog_manager'; +import NodesOption from './diagram.nodes_option'; +import EdgesOption from './diagram.edges_option'; const DIAGRAM_CLASS = 'dx-diagram'; const DIAGRAM_FULLSCREEN_CLASS = 'dx-diagram-fullscreen'; @@ -32,7 +35,9 @@ const DIAGRAM_TOOLBAR_WRAPPER_CLASS = DIAGRAM_CLASS + '-toolbar-wrapper'; const DIAGRAM_CONTENT_WRAPPER_CLASS = DIAGRAM_CLASS + '-content-wrapper'; const DIAGRAM_DRAWER_WRAPPER_CLASS = DIAGRAM_CLASS + '-drawer-wrapper'; const DIAGRAM_CONTENT_CLASS = DIAGRAM_CLASS + '-content'; +const DIAGRAM_FLOATING_TOOLBAR_CONTAINER_CLASS = DIAGRAM_CLASS + '-floating-toolbar-container'; const DIAGRAM_LOADING_INDICATOR_CLASS = DIAGRAM_CLASS + '-loading-indicator'; +const DIAGRAM_FLOATING_PANEL_OFFSET = 22; const DIAGRAM_DEFAULT_UNIT = 'in'; const DIAGRAM_DEFAULT_ZOOMLEVEL = 1; @@ -40,6 +45,11 @@ const DIAGRAM_DEFAULT_AUTOZOOM = 'disabled'; const DIAGRAM_DEFAULT_PAGE_ORIENTATION = 'portrait'; const DIAGRAM_DEFAULT_PAGE_COLOR = 'white'; +const DIAGRAM_TOOLBOX_ITEM_SIZE = 30; +const DIAGRAM_TOOLBOX_ITEM_SPACING = 10; +const DIAGRAM_CONTEXT_TOOLBOX_ICON_SIZE = 24; +const DIAGRAM_CONTEXT_TOOLBOX_ICON_SPACING = 8; + const DIAGRAM_NAMESPACE = 'dxDiagramEvent'; const FULLSCREEN_CHANGE_EVENT_NAME = eventUtils.addNamespace('fullscreenchange', DIAGRAM_NAMESPACE); const IE_FULLSCREEN_CHANGE_EVENT_NAME = eventUtils.addNamespace('msfullscreenchange', DIAGRAM_NAMESPACE); @@ -60,18 +70,28 @@ class Diagram extends Widget { const isServerSide = !hasWindow(); this.$element().addClass(DIAGRAM_CLASS); - this._toolbarInstance = undefined; + this._mainToolbar = undefined; if(this.option('toolbar.visible')) { - this._renderToolbar(); + this._renderMainToolbar(); } const $contentWrapper = $('
') .addClass(DIAGRAM_CONTENT_WRAPPER_CLASS) .appendTo(this.$element()); - this._leftPanel = undefined; + this._historyToolbar = undefined; + if(this.option('historyToolbar.visible')) { + this._renderHistoryToolbar($contentWrapper); + } + + this._viewToolbar = undefined; + if(this.option('viewToolbar.visible')) { + this._renderViewToolbar($contentWrapper); + } + + this._toolbox = undefined; if(this.option('toolbox.visible')) { - this._renderLeftPanel($contentWrapper); + this._renderToolbox($contentWrapper); } const $drawerWrapper = $('
') @@ -130,7 +150,7 @@ class Diagram extends Widget { component.bar.onChanged.add(this); this._diagramInstance.barManager.registerBar(component.bar); } - _renderToolbar() { + _renderMainToolbar() { const $toolbarWrapper = $('
') .addClass(DIAGRAM_TOOLBAR_WRAPPER_CLASS) .appendTo(this.$element()); @@ -138,91 +158,95 @@ class Diagram extends Widget { if(this.option('propertiesPanel.enabled') && this.option('propertiesPanel.collapsible')) { toolbarWidgetCommandNames.push('options'); } - this._toolbarInstance = this._createComponent($toolbarWrapper, DiagramToolbar, { + this._mainToolbar = this._createComponent($toolbarWrapper, DiagramMainToolbar, { commands: this.option('toolbar.commands'), - onContentReady: (e) => this._registerBar(e.component), + onContentReady: ({ component }) => this._registerBar(component), + onSubMenuVisibleChanged: ({ component }) => this._diagramInstance.barManager.updateBarItemsState(component.bar), onPointerUp: this._onPanelPointerUp.bind(this), export: this.option('export'), widgetCommandNames: toolbarWidgetCommandNames }); } - _renderLeftPanel($parent) { - const isServerSide = !hasWindow(); + _adjustFloatingToolbarContainer($container, toolbar, position) { + if(!hasWindow()) return; - const $leftPanel = $('
') + const $toolbarContent = toolbar.$element().find('.dx-toolbar-before'); + $container.width($toolbarContent.width()); + positionUtils.setup($container, position); + } + _renderHistoryToolbar($parent) { + const $container = $('
') + .addClass(DIAGRAM_FLOATING_TOOLBAR_CONTAINER_CLASS) .appendTo($parent); - - this._leftPanel = this._createComponent($leftPanel, DiagramLeftPanel, { + this._historyToolbar = this._createComponent($container, DiagramHistoryToolbar, { + commands: this.option('historyToolbar.commands'), + onContentReady: ({ component }) => this._registerBar(component), + onSubMenuVisibleChanged: ({ component }) => this._diagramInstance.barManager.updateBarItemsState(component.bar), + onPointerUp: this._onPanelPointerUp.bind(this) + }); + this._adjustFloatingToolbarContainer($container, this._historyToolbar, { + my: 'left top', + at: 'left top', + of: $parent, + offset: DIAGRAM_FLOATING_PANEL_OFFSET + ' ' + DIAGRAM_FLOATING_PANEL_OFFSET + }); + } + _renderToolbox($parent) { + const isServerSide = !hasWindow(); + const $toolBox = $('
') + .appendTo($parent); + let yOffset = DIAGRAM_FLOATING_PANEL_OFFSET; + let height = !isServerSide ? $parent.height() - 2 * DIAGRAM_FLOATING_PANEL_OFFSET : 200; + if(this._historyToolbar && !isServerSide) { + yOffset += this._historyToolbar.$element().height() + DIAGRAM_FLOATING_PANEL_OFFSET; + height -= this._historyToolbar.$element().height() + DIAGRAM_FLOATING_PANEL_OFFSET; + } + if(this._viewToolbar && !isServerSide) { + height -= this._viewToolbar.$element().height() + DIAGRAM_FLOATING_PANEL_OFFSET; + } + this._toolbox = this._createComponent($toolBox, DiagramToolbox, { + visible: !this.option('readOnly') && !this.option('disabled'), + height: height, + position: { + my: 'left top', + at: 'left top', + of: $parent, + offset: DIAGRAM_FLOATING_PANEL_OFFSET + ' ' + yOffset + }, toolboxGroups: this._getToolboxGroups(), - disabled: this.option('readOnly'), onShapeCategoryRendered: (e) => { if(isServerSide) return; - const $toolboxContainer = $(e.$element); - this._diagramInstance.createToolbox($toolboxContainer[0], 32, 8, - { 'data-toggle': 'shape-toolbox-tooltip' }, - e.shapes || e.category, e.displayMode === 'texts'); - this._createTooltips($parent, $toolboxContainer.find('[data-toggle="shape-toolbox-tooltip"]')); + this._diagramInstance.createToolbox(e.$element[0], + DIAGRAM_TOOLBOX_ITEM_SIZE, DIAGRAM_TOOLBOX_ITEM_SPACING, + { 'data-toggle': e.dataToggle }, + e.shapes || e.category, e.displayMode === 'texts', e.width + ); + }, + onFilterChanged: (e) => { + if(isServerSide) return; + + this._diagramInstance.applyToolboxFilter(e.text, e.filteringToolboxes); }, onPointerUp: this._onPanelPointerUp.bind(this) }); } - _createTooltips($container, targets) { - targets.each((index, element) => { - const $target = $(element); - const title = $target.attr('title'); - if(title) { - const $tooltip = $('
') - .html(title) - .appendTo($container); - this._createComponent($tooltip, Tooltip, { - target: $target.get(0), - showEvent: 'mouseenter', - hideEvent: 'mouseleave', - position: 'top', - animation: { - show: { type: 'fade', from: 0, to: 1, delay: 500 }, - hide: { type: 'fade', from: 1, to: 0, delay: 100 } - } - }); - } + _renderViewToolbar($parent) { + const $container = $('
') + .addClass(DIAGRAM_FLOATING_TOOLBAR_CONTAINER_CLASS) + .appendTo($parent); + this._viewToolbar = this._createComponent($container, DiagramViewToolbar, { + commands: this.option('viewToolbar.commands'), + onContentReady: ({ component }) => this._registerBar(component), + onSubMenuVisibleChanged: ({ component }) => this._diagramInstance.barManager.updateBarItemsState(component.bar), + onPointerUp: this._onPanelPointerUp.bind(this) + }); + this._adjustFloatingToolbarContainer($container, this._viewToolbar, { + my: 'left bottom', + at: 'left bottom', + of: $parent, + offset: DIAGRAM_FLOATING_PANEL_OFFSET + ' -' + DIAGRAM_FLOATING_PANEL_OFFSET }); - - } - _invalidateContextMenuCommands() { - if(this._contextMenu) { - this._contextMenu.option({ - commands: this.option('contextMenu.commands') - }); - } - } - _invalidatePropertiesPanelGroups() { - if(this._rightPanel) { - this._rightPanel.option({ - propertyGroups: this.option('propertiesPanel.groups') - }); - } - } - _invalidateToolbarCommands() { - if(this._toolbarInstance) { - this._toolbarInstance.option({ - commands: this.option('toolbar.commands') - }); - } - } - _invalidateToolboxGroups() { - if(this._leftPanel) { - this._leftPanel.option({ - toolboxGroups: this._getToolboxGroups() - }); - } - } - _setLeftPanelEnabled(enabled) { - if(this._leftPanel) { - this._leftPanel.option({ - disabled: !enabled - }); - } } _renderRightPanel($parent) { @@ -240,8 +264,8 @@ class Diagram extends Widget { }); } }); - if(this._toolbarInstance) { - this._toolbarInstance.option('onWidgetCommand', (e) => { + if(this._mainToolbar) { + this._mainToolbar.option('onWidgetCommand', (e) => { if(e.name === 'options') { drawer.toggle(); } @@ -287,7 +311,7 @@ class Diagram extends Widget { isTextGroup = group.displayMode === 'texts'; } } - this._diagramInstance.createContextToolbox($toolboxContainer[0], 24, 8, {}, + this._diagramInstance.createContextToolbox($toolboxContainer[0], DIAGRAM_CONTEXT_TOOLBOX_ICON_SIZE, DIAGRAM_CONTEXT_TOOLBOX_ICON_SPACING, {}, shapes || category || e.category, isTextGroup, function(shapeType) { e.callback(shapeType); @@ -433,7 +457,7 @@ class Diagram extends Widget { delete this._edgesOption; } if(this.option('edges.dataSource')) { - this._edgesOption = new EdgesOptions(this); + this._edgesOption = new EdgesOption(this); this._edgesOption.option('dataSource', this.option('edges.dataSource')); this._edgesOption._refreshDataSource(); } @@ -670,7 +694,7 @@ class Diagram extends Widget { return this.option('customShapes') || []; } _getToolboxGroups() { - return DiagramToolbox.getGroups(this.option('toolbox.groups')); + return DiagramToolboxManager.getGroups(this.option('toolbox.groups')); } _updateCustomShapes(customShapes, prevCustomShapes) { if(Array.isArray(prevCustomShapes)) { @@ -840,7 +864,7 @@ class Diagram extends Widget { const { DiagramCommand } = getDiagram(); const readOnly = this.option('readOnly') || this.option('disabled'); this._executeDiagramCommand(DiagramCommand.ToggleReadOnly, readOnly); - this._setLeftPanelEnabled(!readOnly); + this._setToolboxVisible(!readOnly); } _updateZoomLevelState() { let zoomLevel = this.option('zoomLevel.value'); @@ -1528,6 +1552,32 @@ class Diagram extends Widget { * @default undefined */ }, + historyToolbar: { + /** + * @name dxDiagramOptions.historyToolbar.visible + * @type boolean + * @default true + */ + visible: true, + /** + * @name dxDiagramOptions.historyToolbar.commands + * @type Array + * @default undefined + */ + }, + viewToolbar: { + /** + * @name dxDiagramOptions.viewToolbar.visible + * @type boolean + * @default true + */ + visible: true, + /** + * @name dxDiagramOptions.viewToolbar.commands + * @type Array + * @default undefined + */ + }, contextMenu: { /** * @name dxDiagramOptions.contextMenu.enabled @@ -1643,13 +1693,13 @@ class Diagram extends Widget { } } _raiseToolboxDragStart() { - if(this._leftPanel) { - this._leftPanel.$element().addClass('dx-skip-gesture-event'); + if(this._toolbox) { + this._toolbox._raiseToolboxDragStart(); } } _raiseToolboxDragEnd() { - if(this._leftPanel) { - this._leftPanel.$element().removeClass('dx-skip-gesture-event'); + if(this._toolbox) { + this._toolbox._raiseToolboxDragEnd(); } } @@ -1706,6 +1756,57 @@ class Diagram extends Widget { toKey: nativeConnector.toKey }; } + + _invalidateContextMenuCommands() { + if(this._contextMenu) { + this._contextMenu.option({ + commands: this.option('contextMenu.commands') + }); + } + } + _invalidatePropertiesPanelGroups() { + if(this._rightPanel) { + this._rightPanel.option({ + propertyGroups: this.option('propertiesPanel.groups') + }); + } + } + _invalidateMainToolbarCommands() { + if(this._mainToolbar) { + this._mainToolbar.option({ + commands: this.option('toolbar.commands') + }); + } + } + _invalidateHistoryToolbarCommands() { + if(this._historyToolbar) { + this._historyToolbar.option({ + commands: this.option('historyToolbar.commands') + }); + } + } + _invalidateViewToolbarCommands() { + if(this._viewToolbar) { + this._viewToolbar.option({ + commands: this.option('viewToolbar.commands') + }); + } + } + _invalidateToolboxGroups() { + if(this._toolbox) { + this._toolbox.option({ + toolboxGroups: this._getToolboxGroups() + }); + } + } + _setToolboxVisible(visible) { + if(this._toolbox) { + this._toolbox.option({ + visible: visible + }); + } + } + _optionChanged(args) { if(this.optionsUpdateBar.isUpdateLocked()) return; @@ -1815,7 +1916,21 @@ class Diagram extends Widget { break; case 'toolbar': if(args.fullName === 'toolbar.commands') { - this._invalidateToolbarCommands(); + this._invalidateMainToolbarCommands(); + } else { + this._invalidate(); + } + break; + case 'historyToolbar': + if(args.fullName === 'historyToolbar.commands') { + this._invalidateHistoryToolbarCommands(); + } else { + this._invalidate(); + } + break; + case 'viewToolbar': + if(args.fullName === 'viewToolbar.commands') { + this._invalidateViewToolbarCommands(); } else { this._invalidate(); } @@ -1830,8 +1945,8 @@ class Diagram extends Widget { this._createSelectionChangedAction(); break; case 'export': - if(this._toolbarInstance) { - this._toolbarInstance.option('export', args.value); + if(this._mainToolbar) { + this._mainToolbar.option('export', args.value); } break; case 'hasChanges': diff --git a/js/ui/diagram/ui.diagram.leftpanel.js b/js/ui/diagram/ui.diagram.leftpanel.js deleted file mode 100644 index 9de2c77d115a..000000000000 --- a/js/ui/diagram/ui.diagram.leftpanel.js +++ /dev/null @@ -1,101 +0,0 @@ -import $ from '../../core/renderer'; - -import DiagramPanel from './diagram.panel'; -import Accordion from '../accordion'; -import ScrollView from '../scroll_view'; -import { Deferred } from '../../core/utils/deferred'; - -const DIAGRAM_LEFT_PANEL_CLASS = 'dx-diagram-left-panel'; - -class DiagramLeftPanel extends DiagramPanel { - _init() { - super._init(); - - this._onShapeCategoryRenderedAction = this._createActionByOption('onShapeCategoryRendered', { - excludeValidators: ['disabled'] - }); - } - _initMarkup() { - super._initMarkup(); - this.$element().addClass(DIAGRAM_LEFT_PANEL_CLASS); - const $scrollViewWrapper = $('
') - .appendTo(this.$element()); - - this._scrollView = this._createComponent($scrollViewWrapper, ScrollView); - - const $accordion = $('
') - .appendTo(this._scrollView.content()); - - this._renderAccordion($accordion); - } - _getAccordionDataSource() { - const result = []; - const toolboxGroups = this.option('toolboxGroups'); - for(let i = 0; i < toolboxGroups.length; i++) { - const category = toolboxGroups[i].category; - const title = toolboxGroups[i].title; - const groupObj = { - category, - title: title || category, - expanded: toolboxGroups[i].expanded, - displayMode: toolboxGroups[i].displayMode, - shapes: toolboxGroups[i].shapes, - onTemplate: (widget, $element, data) => { - this._onShapeCategoryRenderedAction({ - category: data.category, - displayMode: data.displayMode, - shapes: data.shapes, - $element - }); - } - }; - result.push(groupObj); - } - return result; - } - _renderAccordion($container) { - const data = this._getAccordionDataSource(); - this._accordionInstance = this._createComponent($container, Accordion, { - multiple: true, - collapsible: true, - displayExpr: 'title', - dataSource: data, - disabled: this.option('disabled'), - itemTemplate: (data, index, $element) => data.onTemplate(this, $element, data), - onContentReady: (e) => { - this._updateScrollAnimateSubscription(e.component); - } - }); - - for(let i = 0; i < data.length; i++) { - if(data[i].expanded === false) { - this._accordionInstance.collapseItem(i); - } else if(data[i].expanded === true) { - this._accordionInstance.expandItem(i); - } - } - } - - _updateScrollAnimateSubscription(component) { - component._deferredAnimate = new Deferred(); - component._deferredAnimate.done(() => { - this._scrollView.update(); - this._updateScrollAnimateSubscription(component); - }); - } - - _optionChanged(args) { - switch(args.name) { - case 'disabled': - this._accordionInstance.option('disabled', args.value); - break; - case 'toolboxGroups': - this._invalidate(); - break; - default: - super._optionChanged(args); - } - } -} - -module.exports = DiagramLeftPanel; diff --git a/js/ui/diagram/ui.diagram.main_toolbar.js b/js/ui/diagram/ui.diagram.main_toolbar.js new file mode 100644 index 000000000000..8d9de9251e5c --- /dev/null +++ b/js/ui/diagram/ui.diagram.main_toolbar.js @@ -0,0 +1,26 @@ +import messageLocalization from '../../localization/message'; +import DiagramToolbar from './ui.diagram.toolbar'; +import DiagramCommandsManager from './diagram.commands_manager'; + +class DiagramMainToolbar extends DiagramToolbar { + _getCommands() { + return DiagramCommandsManager.getMainToolbarCommands(this.option('commands')); + } + _getAllWidgetCommands() { + return this._widgetCommands || + (this._widgetCommands = [ + { + command: 'options', + icon: 'preferences', + hint: messageLocalization.format('dxDiagram-commandProperties'), + text: messageLocalization.format('dxDiagram-commandProperties'), + } + ]); + } + _getRightAlignedCommands() { + const widgetCommands = this._getWidgetCommands(); + return this._getAllWidgetCommands().filter(function(c) { return widgetCommands.indexOf(c.command) > -1; }); + } +} + +module.exports = DiagramMainToolbar; diff --git a/js/ui/diagram/ui.diagram.menu_helper.js b/js/ui/diagram/ui.diagram.menu_helper.js new file mode 100644 index 000000000000..5c2df5d6a1fe --- /dev/null +++ b/js/ui/diagram/ui.diagram.menu_helper.js @@ -0,0 +1,53 @@ +import $ from '../../core/renderer'; +import { getImageContainer } from '../../core/utils/icon'; + +const DIAGRAM_CONTEXT_MENU_CLASS = 'dx-diagram-contextmenu'; + +const DiagramMenuHelper = { + getContextMenuItemTemplate(itemData, itemIndex, itemElement, menuHasCheckedItems) { + const itemKey = itemData.rootCommand !== undefined ? itemData.rootCommand : -1; + if(itemData.icon && !itemData.checked) { + const $iconElement = getImageContainer(itemData.icon); + itemElement.append($iconElement); + } else if(menuHasCheckedItems && menuHasCheckedItems[itemKey] === true) { + const $checkElement = getImageContainer('check'); + $checkElement.css('visibility', !itemData.checked ? 'hidden' : ''); + itemElement.append($checkElement); + } + itemElement.append('' + itemData.text + ''); + if(Array.isArray(itemData.items) && itemData.items.length > 0) { + const $popoutElement = $('
'); + itemElement.append($popoutElement); + } + }, + getContextMenuCssClass() { + return DIAGRAM_CONTEXT_MENU_CLASS; + }, + onContextMenuItemClick(itemData, actionHandler) { + if(itemData.command !== undefined && (!Array.isArray(itemData.items) || !itemData.items.length)) { + const parameter = DiagramMenuHelper.getItemCommandParameter(itemData); + actionHandler.call(this, itemData.command, parameter, itemData.onExecuted); + } else if(itemData.rootCommand !== undefined && itemData.value !== undefined) { + const parameter = DiagramMenuHelper.getItemCommandParameter(itemData, itemData.value); + actionHandler.call(this, itemData.rootCommand, parameter, itemData.onExecuted); + } else if(itemData.onExecuted) { + actionHandler.call(this, itemData.command, undefined, itemData.onExecuted); + } + }, + getItemValue(item) { + return (typeof item.value === 'object') ? JSON.stringify(item.value) : item.value; + }, + getItemOptionText(indexPath) { + return indexPath.reduce((r, i) => { + return r + `items[${i}].`; + }, ''); + }, + getItemCommandParameter(item, value) { + if(item.getParameter) { + return item.getParameter(this); + } + return value; + } +}; + +module.exports = DiagramMenuHelper; diff --git a/js/ui/diagram/diagram.panel.js b/js/ui/diagram/ui.diagram.panel.js similarity index 100% rename from js/ui/diagram/diagram.panel.js rename to js/ui/diagram/ui.diagram.panel.js diff --git a/js/ui/diagram/ui.diagram.rightpanel.js b/js/ui/diagram/ui.diagram.rightpanel.js index 5a0a0e216b60..3c6ed2fba978 100644 --- a/js/ui/diagram/ui.diagram.rightpanel.js +++ b/js/ui/diagram/ui.diagram.rightpanel.js @@ -1,11 +1,11 @@ import $ from '../../core/renderer'; -import DiagramPanel from './diagram.panel'; +import DiagramPanel from './ui.diagram.panel'; import Accordion from '../accordion'; import Form from '../form'; -import DiagramCommands from './ui.diagram.commands'; +import DiagramCommandsManager from './diagram.commands_manager'; import { extend } from '../../core/utils/extend'; import messageLocalization from '../../localization/message'; -import DiagramBar from './diagram_bar'; +import DiagramBar from './diagram.bar'; import ScrollView from '../scroll_view'; import { Deferred } from '../../core/utils/deferred'; @@ -55,7 +55,7 @@ class DiagramRightPanel extends DiagramPanel { }); } _renderOptions($container) { - const commands = DiagramCommands.getPropertyPanelCommands(this.option('propertyGroups')); + const commands = DiagramCommandsManager.getPropertyPanelCommands(this.option('propertyGroups')); this._formInstance = this._createComponent($container, Form, { items: commands.map(item => { return extend(true, { @@ -147,7 +147,7 @@ class DiagramRightPanel extends DiagramPanel { class OptionsDiagramBar extends DiagramBar { getCommandKeys() { - return DiagramCommands.getPropertyPanelCommands().map(c => c.command); + return DiagramCommandsManager.getPropertyPanelCommands().map(c => c.command); } setItemValue(key, value) { this._owner._setItemValue(key, value); diff --git a/js/ui/diagram/ui.diagram.toolbar.js b/js/ui/diagram/ui.diagram.toolbar.js index 2b23a91ad6ba..34a73b42f5a0 100644 --- a/js/ui/diagram/ui.diagram.toolbar.js +++ b/js/ui/diagram/ui.diagram.toolbar.js @@ -1,61 +1,66 @@ import $ from '../../core/renderer'; -import DiagramPanel from './diagram.panel'; import Toolbar from '../toolbar'; import ContextMenu from '../context_menu'; -import DiagramCommands from './ui.diagram.commands'; -import DiagramBar from './diagram_bar'; +import DiagramBar from './diagram.bar'; import { extend } from '../../core/utils/extend'; -import messageLocalization from '../../localization/message'; + +import DiagramPanel from './ui.diagram.panel'; +import DiagramMenuHelper from './ui.diagram.menu_helper'; import '../select_box'; import '../color_box'; import '../check_box'; const ACTIVE_FORMAT_CLASS = 'dx-format-active'; -const TOOLBAR_CLASS = 'dx-diagram-toolbar'; -const TOOLBAR_SEPARATOR_CLASS = 'dx-diagram-toolbar-separator'; -const TOOLBAR_MENU_SEPARATOR_CLASS = 'dx-diagram-toolbar-menu-separator'; +const DIAGRAM_TOOLBAR_CLASS = 'dx-diagram-toolbar'; +const DIAGRAM_TOOLBAR_SEPARATOR_CLASS = 'dx-diagram-toolbar-separator'; +const DIAGRAM_TOOLBAR_MENU_SEPARATOR_CLASS = 'dx-diagram-toolbar-menu-separator'; class DiagramToolbar extends DiagramPanel { _init() { - this.bar = new ToolbarDiagramBar(this); + this._commands = []; this._itemHelpers = {}; this._contextMenus = []; + this.bar = new ToolbarDiagramBar(this); + this._createOnWidgetCommand(); + this._createOnSubMenuVisibleChangedAction(); + super._init(); } - _initMarkup() { super._initMarkup(); - const $toolbar = $('
') - .addClass(TOOLBAR_CLASS) - .appendTo(this._$element); + + this._commands = this._getCommands(); + this._itemHelpers = {}; + this._contextMenus = []; + this._rightAlignedCommands = this._getRightAlignedCommands(); + + const $toolbar = this._createMainElement(); this._renderToolbar($toolbar); } + _createMainElement() { + return $('
') + .addClass(DIAGRAM_TOOLBAR_CLASS) + .appendTo(this._$element); + } + _getCommands() { + return []; + } + _getRightAlignedCommands() { + return []; + } _getWidgetCommands() { - return this._widgetCommands || - (this._widgetCommands = [ - { - command: 'options', - icon: 'preferences', - hint: messageLocalization.format('dxDiagram-commandProperties'), - text: messageLocalization.format('dxDiagram-commandProperties'), - } - ]); + return this.option('widgetCommandNames') || []; } _renderToolbar($toolbar) { - const commands = DiagramCommands.getToolbarCommands(this.option('commands')); - const widgetCommandNames = this.option('widgetCommandNames') || []; - const widgetCommands = this._getWidgetCommands().filter(function(c) { return widgetCommandNames.indexOf(c.command) > -1; }); - let dataSource = this._prepareToolbarItems(commands, 'before', this._execDiagramCommand); - dataSource = dataSource.concat(this._prepareToolbarItems(widgetCommands, 'after', this._execWidgetCommand)); - this._toolbarInstance = this._createComponent($toolbar, Toolbar, { - dataSource - }); + let dataSource = []; + dataSource = dataSource.concat(this._prepareToolbarItems(this._commands, 'before', this._execDiagramCommand)); + dataSource = dataSource.concat(this._prepareToolbarItems(this._rightAlignedCommands, 'after', this._execDiagramCommand)); + this._toolbarInstance = this._createComponent($toolbar, Toolbar, { dataSource }); } - _prepareToolbarItems(items, location, actionHandler) { return items.map(item => extend(true, { location: location, locateInMenu: 'auto' }, @@ -69,10 +74,10 @@ class DiagramToolbar extends DiagramPanel { if(item.widget === 'separator') { return { template: (data, index, element) => { - $(element).addClass(TOOLBAR_SEPARATOR_CLASS); + $(element).addClass(DIAGRAM_TOOLBAR_SEPARATOR_CLASS); }, menuItemTemplate: (data, index, element) => { - $(element).addClass(TOOLBAR_MENU_SEPARATOR_CLASS); + $(element).addClass(DIAGRAM_TOOLBAR_MENU_SEPARATOR_CLASS); } }; } @@ -178,8 +183,8 @@ class DiagramToolbar extends DiagramPanel { return { options: { onValueChanged: (e) => { - const parameter = this._getExecCommandParameter(item, e.component.option('value')); - handler.call(this, item.command, parameter); + const parameter = DiagramMenuHelper.getItemCommandParameter(item, e.component.option('value')); + handler.call(this, item.command, parameter, item.onExecuted); } } }; @@ -188,41 +193,38 @@ class DiagramToolbar extends DiagramPanel { return { options: { onClick: (e) => { - const parameter = this._getExecCommandParameter(item); - handler.call(this, item.command, parameter); + const parameter = DiagramMenuHelper.getItemCommandParameter(item); + handler.call(this, item.command, parameter, item.onExecuted); } } }; } } } - _getExecCommandParameter(item, widgetValue) { - if(item.getParameter) { - return item.getParameter(this, widgetValue); - } - return widgetValue; - } _onItemInitialized(widget, item) { - if(item.command !== undefined) { - this._itemHelpers[item.command] = new ToolbarItemHelper(widget); - } + this._addItemHelper(item.command, new ToolbarItemHelper(widget)); } _onItemContentReady(widget, item, actionHandler) { if(widget.NAME === 'dxButton' && item.items) { const $menuContainer = $('
') .appendTo(this.$element()); this._createComponent($menuContainer, ContextMenu, { - dataSource: item.items, - displayExpr: 'text', - valueExpr: 'command', + items: item.items, target: widget.$element(), + cssClass: DiagramMenuHelper.getContextMenuCssClass(), showEvent: 'dxclick', position: { at: 'left bottom' }, - onItemClick: ({ itemData }) => { - if(itemData.command !== undefined) { - const parameter = this._getExecCommandParameter(itemData); - actionHandler.call(this, itemData.command, parameter); - } + itemTemplate: function(itemData, itemIndex, itemElement) { + DiagramMenuHelper.getContextMenuItemTemplate(itemData, itemIndex, itemElement, this._menuHasCheckedItems); + }, + onItemClick: ({ itemData }) => DiagramMenuHelper.onContextMenuItemClick(itemData, actionHandler.bind(this)), + onShowing: (e) => { + if(this._showingSubMenu) return; + + this._showingSubMenu = e.component; + this._onSubMenuVisibleChangedAction({ visible: true, component: this }); + e.component.option('items', item.items); + delete this._showingSubMenu; }, onInitialized: ({ component }) => this._onContextMenuInitialized(component, item, widget), onDisposing: ({ component }) => this._onContextMenuDisposing(component, item) @@ -231,38 +233,51 @@ class DiagramToolbar extends DiagramPanel { } _onContextMenuInitialized(widget, item, rootButton) { this._contextMenus.push(widget); - this._addContextMenuHelper(item.items, widget, [], rootButton); + this._addContextMenuHelper(item, widget, [], rootButton); } - _addContextMenuHelper(items, widget, indexPath, rootButton) { - if(items) { - items.forEach((item, index) => { + _addItemHelper(command, helper) { + if(command !== undefined) { + if(this._itemHelpers[command]) { + throw new Error('Toolbar cannot contain duplicated commands.'); + } + this._itemHelpers[command] = helper; + } + } + _addContextMenuHelper(item, widget, indexPath, rootButton) { + if(item.items) { + item.items.forEach((subItem, index) => { const itemIndexPath = indexPath.concat(index); - this._itemHelpers[item.command] = new ContextMenuItemHelper(widget, itemIndexPath, rootButton); - this._addContextMenuHelper(item.items, widget, itemIndexPath, rootButton); + this._addItemHelper(subItem.command, new ToolbarSubItemHelper(widget, itemIndexPath, subItem.command, rootButton)); + this._addContextMenuHelper(subItem, widget, itemIndexPath, rootButton); }); } } _onContextMenuDisposing(widget, item) { this._contextMenus = this._contextMenus.filter(cm => cm !== widget); } - _execDiagramCommand(command, value) { - if(!this._updateLocked) { - this.bar.raiseBarCommandExecuted(command, value); + _execDiagramCommand(command, value, onExecuted) { + if(!this._updateLocked && command !== undefined) { + const widgetCommands = this._getWidgetCommands(); + if(widgetCommands.indexOf(command) > -1) { + this._onWidgetCommandAction({ name: command }); + } else { + this.bar.raiseBarCommandExecuted(command, value); + } } - } - _execWidgetCommand(command) { - if(!this._updateLocked) { - this._onWidgetCommandAction({ name: command }); + if(typeof onExecuted === 'function') { + onExecuted.call(this); } } - _createOnWidgetCommand() { this._onWidgetCommandAction = this._createActionByOption('onWidgetCommand'); } _setItemEnabled(command, enabled) { if(command in this._itemHelpers) { - this._itemHelpers[command].setEnabled(enabled); + const helper = this._itemHelpers[command]; + if(helper.canUpdate(this._showingSubMenu)) { + helper.setEnabled(enabled); + } } } _setEnabled(enabled) { @@ -273,7 +288,10 @@ class DiagramToolbar extends DiagramPanel { try { this._updateLocked = true; if(command in this._itemHelpers) { - this._itemHelpers[command].setValue(value); + const helper = this._itemHelpers[command]; + if(helper.canUpdate(this._showingSubMenu)) { + helper.setValue(value); + } } } finally { this._updateLocked = false; @@ -282,12 +300,23 @@ class DiagramToolbar extends DiagramPanel { _setItemSubItems(command, items) { this._updateLocked = true; if(command in this._itemHelpers) { - this._itemHelpers[command].setItems(items); + const helper = this._itemHelpers[command]; + if(helper.canUpdate(this._showingSubMenu)) { + helper.setItems(items); + } } this._updateLocked = false; } + _createOnSubMenuVisibleChangedAction() { + this._hasCheckedItems = false; + this._onSubMenuVisibleChangedAction = this._createActionByOption('onSubMenuVisibleChanged'); + } + _optionChanged(args) { switch(args.name) { + case 'onSubMenuVisibleChanged': + this._createOnSubMenuVisibleChangedAction(); + break; case 'onWidgetCommand': this._createOnWidgetCommand(); break; @@ -312,18 +341,7 @@ class DiagramToolbar extends DiagramPanel { class ToolbarDiagramBar extends DiagramBar { getCommandKeys() { - return this.getKeys(DiagramCommands.getToolbarCommands()); - } - getKeys(items) { - return items.reduce((commands, item) => { - if(item.command !== undefined) { - commands.push(item.command); - } - if(item.items) { - commands = commands.concat(this.getKeys(item.items)); - } - return commands; - }, []); + return this._getKeys(this._owner._commands); } setItemValue(key, value) { this._owner._setItemValue(key, value); @@ -343,6 +361,9 @@ class ToolbarItemHelper { constructor(widget) { this._widget = widget; } + canUpdate(showingSubMenu) { + return showingSubMenu === undefined; + } setEnabled(enabled) { this._widget.option('disabled', !enabled); } @@ -356,9 +377,8 @@ class ToolbarItemHelper { setItems(items) { if('items' in this._widget.option()) { this._widget.option('items', items.map(item => { - const value = (typeof item.value === 'object') ? JSON.stringify(item.value) : item.value; return { - 'value': value, + 'value': DiagramMenuHelper.getItemValue(item), 'title': item.text }; })); @@ -366,17 +386,18 @@ class ToolbarItemHelper { } } -class ContextMenuItemHelper extends ToolbarItemHelper { - constructor(widget, indexPath, rootButton) { +class ToolbarSubItemHelper extends ToolbarItemHelper { + constructor(widget, indexPath, rootCommandKey, rootButton) { super(widget); this._indexPath = indexPath; + this._rootCommandKey = rootCommandKey; this._rootButton = rootButton; } + canUpdate(showingSubMenu) { + return super.canUpdate(showingSubMenu) || showingSubMenu === this._widget; + } setEnabled(enabled) { - const optionText = this._indexPath.reduce((r, i) => { - return r + `items[${i}].`; - }, '') + 'disabled'; - this._widget.option(optionText, !enabled); + this._widget.option(this._getItemOptionText() + 'disabled', !enabled); const rootEnabled = this._hasEnabledCommandItems(this._widget.option('items')); this._rootButton.option('disabled', !rootEnabled); } @@ -388,7 +409,43 @@ class ContextMenuItemHelper extends ToolbarItemHelper { } return false; } - setValue(value) { } + setValue(value) { + const optionText = this._getItemOptionText(); + if(value === true || value === false) { + this._setHasCheckedItems(-1); + this._widget.option(optionText + 'checked', value); + } else if(value !== undefined) { + this._setHasCheckedItems(this._rootCommandKey); + this._subItems.forEach((item, index) => { + item.checked = item.value === value; + }); + this._updateItems(); + } + } + setItems(items) { + this._subItems = items.slice(); + this._updateItems(); + } + _setHasCheckedItems(key) { + if(!this._widget._menuHasCheckedItems) { + this._widget._menuHasCheckedItems = {}; + } + this._widget._menuHasCheckedItems[key] = true; + } + _updateItems(items) { + this._widget.option(this._getItemOptionText() + 'items', this._subItems.map(item => { + return { + 'value': DiagramMenuHelper.getItemValue(item), + 'text': item.text, + 'checked': item.checked, + 'widget': this._widget, + 'rootCommand': this._rootCommandKey + }; + })); + } + _getItemOptionText() { + return DiagramMenuHelper.getItemOptionText(this._indexPath); + } } module.exports = DiagramToolbar; diff --git a/js/ui/diagram/ui.diagram.toolbox.js b/js/ui/diagram/ui.diagram.toolbox.js index cb88e5a33507..ab367317e011 100644 --- a/js/ui/diagram/ui.diagram.toolbox.js +++ b/js/ui/diagram/ui.diagram.toolbox.js @@ -1,52 +1,228 @@ -import messageLocalization from '../../localization/message'; - -const DiagramToolbox = { - getDefaultGroups() { - return this._groups || - (this._groups = { - general: { - category: 'general', - title: messageLocalization.format('dxDiagram-categoryGeneral') - }, - flowchart: { - category: 'flowchart', - title: messageLocalization.format('dxDiagram-categoryFlowchart') - }, - orgChart: { - category: 'orgChart', - title: messageLocalization.format('dxDiagram-categoryOrgChart') - }, - containers: { - category: 'containers', - title: messageLocalization.format('dxDiagram-categoryContainers') - }, - custom: { - category: 'custom', - title: messageLocalization.format('dxDiagram-categoryCustom') +import $ from '../../core/renderer'; +import { extend } from '../../core/utils/extend'; +import { hasWindow } from '../../core/utils/window'; +import { Deferred } from '../../core/utils/deferred'; +import TextBox from '../text_box'; +import Accordion from '../accordion'; +import ScrollView from '../scroll_view'; +import Tooltip from '../tooltip'; +import DiagramFloatingPanel from './ui.diagram.floating_panel'; + +const DIAGRAM_TOOLBOX_POPUP_WIDTH = 136; +const DIAGRAM_TOOLBOX_POPUP_CLASS = 'dx-diagram-toolbox-popup'; +const DIAGRAM_TOOLBOX_PANEL_CLASS = 'dx-diagram-toolbox-panel'; +const DIAGRAM_TOOLBOX_INPUT_CLASS = 'dx-diagram-toolbox-input'; +const DIAGRAM_TOOLTIP_DATATOGGLE = 'shape-toolbox-tooltip'; +const DIAGRAM_SKIP_GESTURE_CLASS = 'dx-skip-gesture-event'; + +class DiagramToolbox extends DiagramFloatingPanel { + _init() { + super._init(); + + this._toolboxes = []; + this.filterText = ''; + this._onShapeCategoryRenderedAction = this._createActionByOption('onShapeCategoryRendered'); + this._onFilterChangedAction = this._createActionByOption('onFilterChanged'); + } + _initMarkup() { + super._initMarkup(); + + if(this.option('visible')) { + this._popup.show(); + } + } + _getPopupClass() { + return DIAGRAM_TOOLBOX_POPUP_CLASS; + } + _getPopupOptions() { + return extend(super._getPopupOptions(), { + width: DIAGRAM_TOOLBOX_POPUP_WIDTH, + toolbarItems: [{ + widget: 'dxButton', + location: 'center', + options: { + activeStateEnabled: false, + focusStateEnabled: false, + hoverStateEnabled: false, + icon: 'diagram-toolbox-drag', + stylingMode: 'outlined', + type: 'normal', + } + }], + }); + } + _renderPopupContent($parent) { + const that = this; + const $input = $('
') + .addClass(DIAGRAM_TOOLBOX_INPUT_CLASS) + .appendTo($parent); + this._searchInput = this._createComponent($input, TextBox, { + placeholder: 'Search', + onValueChanged: function(data) { + that._onInputChanged(data.value); + }, + valueChangeEvent: 'keyup', + buttons: [{ + name: 'search', + location: 'after', + options: { + activeStateEnabled: false, + focusStateEnabled: false, + hoverStateEnabled: false, + icon: 'search', + stylingMode: 'outlined', + type: 'normal', + onClick: function() { + that._searchInput.focus(); + } } - }); - }, - - getGroups: function(groups) { - const defaultGroups = this.getDefaultGroups(); - if(groups) { - return groups.map(function(g) { - if(typeof g === 'string') { - return { - category: g, - title: (defaultGroups[g] && defaultGroups[g].title) || g - }; + }] + }); + const searchInputHeight = !hasWindow() ? '100%' : 'calc(100% - ' + this._searchInput.$element().height() + 'px)'; + const $panel = $('
') + .addClass(DIAGRAM_TOOLBOX_PANEL_CLASS) + .appendTo($parent) + .height(searchInputHeight); + this._renderScrollView($panel); + } + _renderScrollView($parent) { + super._initMarkup(); + + const $scrollViewWrapper = $('
') + .appendTo($parent); + + this._scrollView = this._createComponent($scrollViewWrapper, ScrollView); + + const $accordion = $('
') + .appendTo(this._scrollView.content()); + + this._renderAccordion($accordion); + } + + _getAccordionDataSource() { + const result = []; + const toolboxGroups = this.option('toolboxGroups'); + for(let i = 0; i < toolboxGroups.length; i++) { + const category = toolboxGroups[i].category; + const title = toolboxGroups[i].title; + const groupObj = { + category, + title: title || category, + expanded: toolboxGroups[i].expanded, + displayMode: toolboxGroups[i].displayMode, + shapes: toolboxGroups[i].shapes, + onTemplate: (widget, $element, data) => { + const $toolboxElement = $($element); + let toolboxWidth = DIAGRAM_TOOLBOX_POPUP_WIDTH; + if(hasWindow()) { + toolboxWidth -= ($toolboxElement.parent().width() - $toolboxElement.width() + 2); + } + this._onShapeCategoryRenderedAction({ + category: data.category, + displayMode: data.displayMode, + dataToggle: DIAGRAM_TOOLTIP_DATATOGGLE, + shapes: data.shapes, + $element: $toolboxElement, + width: toolboxWidth + }); + this._toolboxes.push($toolboxElement); + + if(this.filterText !== '') { + this._onFilterChangedAction({ + text: this.filterText, + filteringToolboxes: this._toolboxes.length - 1 + }); + } + this._createTooltips($toolboxElement.find('[data-toggle="' + DIAGRAM_TOOLTIP_DATATOGGLE + '"]')); } - return g; - }).filter(function(g) { return g; }); + }; + result.push(groupObj); + } + return result; + } + _createTooltips(targets) { + const $container = this.$element(); + targets.each((index, element) => { + const $target = $(element); + const title = $target.attr('title'); + if(title) { + const $tooltip = $('
') + .html(title) + .appendTo($container); + this._createComponent($tooltip, Tooltip, { + target: $target.get(0), + showEvent: 'mouseenter', + hideEvent: 'mouseleave', + position: 'top', + animation: { + show: { type: 'fade', from: 0, to: 1, delay: 500 }, + hide: { type: 'fade', from: 1, to: 0, delay: 100 } + } + }); + } + }); + } + _renderAccordion($container) { + const data = this._getAccordionDataSource(); + this._accordion = this._createComponent($container, Accordion, { + multiple: true, + activeStateEnabled: false, + focusStateEnabled: false, + hoverStateEnabled: false, + collapsible: true, + displayExpr: 'title', + dataSource: data, + disabled: this.option('disabled'), + itemTemplate: (data, index, $element) => data.onTemplate(this, $element, data), + onContentReady: (e) => { + this._updateScrollAnimateSubscription(e.component); + } + }); + + for(let i = 0; i < data.length; i++) { + if(data[i].expanded === false) { + this._accordion.collapseItem(i); + } else if(data[i].expanded === true) { + this._accordion.expandItem(i); + } } - return [ - defaultGroups['general'], - defaultGroups['flowchart'], - defaultGroups['orgChart'], - defaultGroups['containers'] - ]; } -}; + _updateScrollAnimateSubscription(component) { + component._deferredAnimate = new Deferred(); + component._deferredAnimate.done(() => { + this._scrollView.update(); + this._updateScrollAnimateSubscription(component); + }); + } + _raiseToolboxDragStart() { + this._scrollView.$element().addClass(DIAGRAM_SKIP_GESTURE_CLASS); + } + _raiseToolboxDragEnd() { + this._scrollView.$element().removeClass(DIAGRAM_SKIP_GESTURE_CLASS); + } + _onInputChanged(text) { + this.filterText = text; + this._onFilterChangedAction({ + text: this.filterText, + filteringToolboxes: this._toolboxes.map(($element, index) => index) + }); + this._toolboxes.forEach($element => { + const $tooltipContainer = $($element); + this._createTooltips($tooltipContainer.find('[data-toggle="' + DIAGRAM_TOOLTIP_DATATOGGLE + '"]')); + }); + } + _optionChanged(args) { + switch(args.name) { + case 'visible': + this._popup.option('visible', args.value); + break; + case 'toolboxGroups': + this._accordion.option('dataSource', this._getAccordionDataSource()); + break; + default: + super._optionChanged(args); + } + } +} module.exports = DiagramToolbox; diff --git a/js/ui/diagram/ui.diagram.view_toolbar.js b/js/ui/diagram/ui.diagram.view_toolbar.js new file mode 100644 index 000000000000..10ec13b8cdc8 --- /dev/null +++ b/js/ui/diagram/ui.diagram.view_toolbar.js @@ -0,0 +1,10 @@ +import DiagramToolbar from './ui.diagram.toolbar'; +import DiagramCommandsManager from './diagram.commands_manager'; + +class DiagramViewToolbar extends DiagramToolbar { + _getCommands() { + return DiagramCommandsManager.getViewToolbarCommands(this.option('commands')); + } +} + +module.exports = DiagramViewToolbar; diff --git a/js/ui/draggable.js b/js/ui/draggable.js index 6074f453d182..c6be2ec4875f 100644 --- a/js/ui/draggable.js +++ b/js/ui/draggable.js @@ -475,7 +475,9 @@ const Draggable = DOMComponent.inherit({ }).appendTo(result); } - return result.toggleClass(this._addWidgetPrefix(CLONE_CLASS), result.get(0) !== $element.get(0)); + return result + .toggleClass(this._addWidgetPrefix(CLONE_CLASS), result.get(0) !== $element.get(0)) + .toggleClass('dx-rtl', this.option('rtlEnabled')); }, _resetDragElement: function() { diff --git a/js/ui/drop_down_button.js b/js/ui/drop_down_button.js index 632733a84e65..38974191d787 100644 --- a/js/ui/drop_down_button.js +++ b/js/ui/drop_down_button.js @@ -13,7 +13,7 @@ import { DataSource } from '../data/data_source/data_source'; import ArrayStore from '../data/array_store'; import { Deferred } from '../core/utils/deferred'; import { extend } from '../core/utils/extend'; -import { isPlainObject } from '../core/utils/type'; +import { isPlainObject, isDefined } from '../core/utils/type'; import { ensureDefined } from '../core/utils/common'; import Guid from '../core/guid'; import { format as formatMessage } from '../localization/message'; @@ -158,9 +158,22 @@ const DropDownButton = Widget.inherit({ this.$element().addClass(DROP_DOWN_BUTTON_CLASS); this._renderButtonGroup(); this._loadSelectedItem().done(this._updateActionButton.bind(this)); + }, + + _render() { if(!this.option('deferRendering') || this.option('opened')) { this._renderPopup(); } + + this.callBase(); + }, + + _renderContentImpl() { + if(this._popup) { + this._renderPopupContent(); + } + + return this.callBase(); }, _loadSelectedItem() { @@ -330,8 +343,10 @@ const DropDownButton = Widget.inherit({ focusStateEnabled: this.option('focusStateEnabled'), hoverStateEnabled: this.option('hoverStateEnabled'), showItemDataTitle: true, + onContentReady: () => this._fireContentReadyAction(), selectedItemKeys: selectedItemKey && useSelectMode ? [selectedItemKey] : [], grouped: this.option('grouped'), + groupTemplate: this.option('groupTemplate'), keyExpr: this.option('keyExpr'), noDataText: this.option('noDataText'), displayExpr: this.option('displayExpr'), @@ -373,7 +388,6 @@ const DropDownButton = Widget.inherit({ this._popup._wrapper().addClass(DROP_DOWN_BUTTON_POPUP_WRAPPER_CLASS); this._popup.on('hiding', this._popupHidingHandler.bind(this)); this._popup.on('showing', this._popupShowingHandler.bind(this)); - this._renderPopupContent(); this._bindInnerWidgetOptions(this._popup, 'dropDownOptions'); }, @@ -410,7 +424,10 @@ const DropDownButton = Widget.inherit({ }, toggle(visible) { - this._popup || this._renderPopup(); + if(!this._popup) { + this._renderPopup(); + this._renderContent(); + } return this._popup.toggle(visible); }, @@ -450,7 +467,7 @@ const DropDownButton = Widget.inherit({ }, _selectedItemKeyChanged(value) { - this._setListOption('selectedItemKeys', this.option('useSelectMode') && value ? [value] : []); + this._setListOption('selectedItemKeys', this.option('useSelectMode') && isDefined(value) ? [value] : []); const previousItem = this.option('selectedItem'); this._loadSelectedItem().done((selectedItem) => { this._updateActionButton(selectedItem); @@ -493,9 +510,9 @@ const DropDownButton = Widget.inherit({ _optionChanged(args) { const { name, value } = args; - switch(args.name) { + switch(name) { case 'useSelectMode': - this._selectModeChanged(args.value); + this._selectModeChanged(value); break; case 'splitButton': this._renderButtonGroup(); @@ -519,6 +536,7 @@ const DropDownButton = Widget.inherit({ case 'hoverStateEnabled': this._setListOption(name, value); this._buttonGroup.option(name, value); + this.callBase(args); break; case 'items': this._dataSource = null; @@ -553,7 +571,7 @@ const DropDownButton = Widget.inherit({ this._setListOption(name, value); break; case 'dropDownContentTemplate': - this._popup && this._renderPopupContent(); + this._renderContent(); break; case 'selectedItemKey': this._selectedItemKeyChanged(value); @@ -572,6 +590,7 @@ const DropDownButton = Widget.inherit({ case 'deferRendering': if(!value && !this._popup) { this._renderPopup(); + this._renderContent(); } break; default: diff --git a/js/ui/drop_down_editor/ui.drop_down_editor.js b/js/ui/drop_down_editor/ui.drop_down_editor.js index fb5f27311df6..41ea66cef3c7 100644 --- a/js/ui/drop_down_editor/ui.drop_down_editor.js +++ b/js/ui/drop_down_editor/ui.drop_down_editor.js @@ -1,27 +1,26 @@ -const $ = require('../../core/renderer'); -const AsyncTemplateMixin = require('../shared/async_template_mixin'); -const eventsEngine = require('../../events/core/events_engine'); -const Guid = require('../../core/guid'); -const registerComponent = require('../../core/component_registrator'); -const commonUtils = require('../../core/utils/common'); -const domUtils = require('../../core/utils/dom'); -const focused = require('../widget/selectors').focused; -const each = require('../../core/utils/iterator').each; -const isDefined = require('../../core/utils/type').isDefined; -const extend = require('../../core/utils/extend').extend; -const getPublicElement = require('../../core/utils/dom').getPublicElement; -const errors = require('../widget/ui.errors'); -const positionUtils = require('../../animation/position'); -const getDefaultAlignment = require('../../core/utils/position').getDefaultAlignment; -const DropDownButton = require('./ui.drop_down_button').default; -const Widget = require('../widget/ui.widget'); -const messageLocalization = require('../../localization/message'); -const eventUtils = require('../../events/utils'); -const TextBox = require('../text_box'); -const clickEvent = require('../../events/click'); -const devices = require('../../core/devices'); -const FunctionTemplate = require('../../core/templates/function_template').FunctionTemplate; -const Popup = require('../popup'); +import $ from '../../core/renderer'; +import AsyncTemplateMixin from '../shared/async_template_mixin'; +import eventsEngine from '../../events/core/events_engine'; +import Guid from '../../core/guid'; +import registerComponent from '../../core/component_registrator'; +import { noop, splitPair } from '../../core/utils/common'; +import { focused } from '../widget/selectors'; +import { each } from '../../core/utils/iterator'; +import { isDefined } from '../../core/utils/type'; +import { extend } from '../../core/utils/extend'; +import { getPublicElement } from '../../core/utils/dom'; +import errors from '../widget/ui.errors'; +import { setup as setupPosition } from '../../animation/position'; +import { getDefaultAlignment } from '../../core/utils/position'; +import DropDownButton from './ui.drop_down_button'; +import Widget from '../widget/ui.widget'; +import { format as formatMessage } from '../../localization/message'; +import { addNamespace } from '../../events/utils'; +import TextBox from '../text_box'; +import clickEvent from '../../events/click'; +import devices from '../../core/devices'; +import { FunctionTemplate } from '../../core/templates/function_template'; +import Popup from '../popup'; const DROP_DOWN_EDITOR_CLASS = 'dx-dropdowneditor'; const DROP_DOWN_EDITOR_INPUT_WRAPPER = 'dx-dropdowneditor-input-wrapper'; @@ -137,8 +136,8 @@ const DropDownEditor = TextBox.inherit({ dropDownOptions: {}, popupPosition: this._getDefaultPopupPosition(), onPopupInitialized: null, - applyButtonText: messageLocalization.format('OK'), - cancelButtonText: messageLocalization.format('Cancel'), + applyButtonText: formatMessage('OK'), + cancelButtonText: formatMessage('Cancel'), buttonsLocation: 'default', showPopupTitle: false, useHiddenSubmitElement: false @@ -180,8 +179,8 @@ const DropDownEditor = TextBox.inherit({ }); }, - _getDefaultPopupPosition: function() { - const position = getDefaultAlignment(); + _getDefaultPopupPosition: function(isRtlEnabled) { + const position = getDefaultAlignment(isRtlEnabled); return { offset: { h: 0, v: -1 }, @@ -213,9 +212,17 @@ const DropDownEditor = TextBox.inherit({ this.callBase(); this._initVisibilityActions(); this._initPopupInitializedAction(); + this._updatePopupPosition(this.option('rtlEnabled')); this._options.cache('dropDownOptions', this.option('dropDownOptions')); }, + _updatePopupPosition: function(isRtlEnabled) { + const { my, at } = this._getDefaultPopupPosition(isRtlEnabled); + const currentPosition = this.option('popupPosition'); + + this.option('popupPosition', extend({}, currentPosition, { my, at })); + }, + _initVisibilityActions: function() { this._openAction = this._createActionByOption('onOpened', { excludeValidators: ['disabled', 'readOnly'] @@ -340,7 +347,7 @@ const DropDownEditor = TextBox.inherit({ fieldTemplate.render({ model: data, - container: domUtils.getPublicElement($templateWrapper), + container: getPublicElement($templateWrapper), onRendered: () => { const $input = this._input(); @@ -374,24 +381,23 @@ const DropDownEditor = TextBox.inherit({ }, _renderOpenHandler: function() { - const that = this; - const $inputWrapper = that._inputWrapper(); - const eventName = eventUtils.addNamespace(clickEvent.name, that.NAME); - const openOnFieldClick = that.option('openOnFieldClick'); + const $inputWrapper = this._inputWrapper(); + const eventName = addNamespace(clickEvent.name, this.NAME); + const openOnFieldClick = this.option('openOnFieldClick'); eventsEngine.off($inputWrapper, eventName); - eventsEngine.on($inputWrapper, eventName, that._getInputClickHandler(openOnFieldClick)); - that.$element().toggleClass(DROP_DOWN_EDITOR_FIELD_CLICKABLE, openOnFieldClick); + eventsEngine.on($inputWrapper, eventName, this._getInputClickHandler(openOnFieldClick)); + this.$element().toggleClass(DROP_DOWN_EDITOR_FIELD_CLICKABLE, openOnFieldClick); if(openOnFieldClick) { - that._openOnFieldClickAction = that._createAction(that._openHandler.bind(that)); + this._openOnFieldClickAction = this._createAction(this._openHandler.bind(this)); } }, _attachFocusOutHandler: function() { if(isIOs) { this._detachFocusOutEvents(); - eventsEngine.on(this._inputWrapper(), eventUtils.addNamespace('focusout', this.NAME), function(event) { + eventsEngine.on(this._inputWrapper(), addNamespace('focusout', this.NAME), (event) => { const newTarget = event.relatedTarget; const popupWrapper = this.content ? $(this.content()).closest('.' + DROP_DOWN_EDITOR_OVERLAY) : this._$popup; if(newTarget && this.option('opened')) { @@ -400,20 +406,18 @@ const DropDownEditor = TextBox.inherit({ this.close(); } } - }.bind(this)); + }); } }, _detachFocusOutEvents: function() { - isIOs && eventsEngine.off(this._inputWrapper(), eventUtils.addNamespace('focusout', this.NAME)); + isIOs && eventsEngine.off(this._inputWrapper(), addNamespace('focusout', this.NAME)); }, _getInputClickHandler: function(openOnFieldClick) { - const that = this; - return openOnFieldClick ? - function(e) { that._executeOpenAction(e); } : - function(e) { that._focusInput(); }; + (e) => { this._executeOpenAction(e); } : + (e) => { this._focusInput(); }; }, _openHandler: function() { @@ -503,7 +507,7 @@ const DropDownEditor = TextBox.inherit({ this.setAria('id', this._popupContentId, $popupContent); }, - _contentReadyHandler: commonUtils.noop, + _contentReadyHandler: noop, _popupConfig: function() { @@ -536,16 +540,16 @@ const DropDownEditor = TextBox.inherit({ return; } - return (function(e) { + return (e) => { this._popupInitializedAction({ popup: e.component }); - }).bind(this); + }; }, _popupPositionedHandler: function(e) { e.position && this._popup.overlayContent().toggleClass(DROP_DOWN_EDITOR_OVERLAY_FLIPPED, e.position.v.flip); }, - _popupShowingHandler: commonUtils.noop, + _popupShowingHandler: noop, _popupHidingHandler: function() { this.option('opened', false); @@ -570,8 +574,8 @@ const DropDownEditor = TextBox.inherit({ let positionRequest = 'below'; if(this._popup && this._popup.option('visible')) { - const myTop = positionUtils.setup(this.$element()).top; - const popupTop = positionUtils.setup(this._popup.$content()).top; + const { top: myTop } = setupPosition(this.$element()); + const { top: popupTop } = setupPosition(this._popup.$content()); positionRequest = (myTop + this.option('popupPosition').offset.v) > popupTop ? 'below' : 'above'; } @@ -595,7 +599,7 @@ const DropDownEditor = TextBox.inherit({ $popupContent.empty(); contentTemplate.render({ - container: domUtils.getPublicElement($popupContent), + container: getPublicElement($popupContent), model: templateData }); }, @@ -695,7 +699,7 @@ const DropDownEditor = TextBox.inherit({ const resultConfig = buttonsConfig; if(buttonsLocation !== 'default') { - const position = commonUtils.splitPair(buttonsLocation); + const position = splitPair(buttonsLocation); each(resultConfig, function(_, element) { extend(element, { @@ -718,7 +722,7 @@ const DropDownEditor = TextBox.inherit({ this.option('focusStateEnabled') && this.focus(); }, - _updatePopupWidth: commonUtils.noop, + _updatePopupWidth: noop, _popupOptionChanged: function(args) { const options = Widget.getOptionsFromContainer(args); @@ -807,6 +811,10 @@ const DropDownEditor = TextBox.inherit({ this._renderSubmitElement(); break; + case 'rtlEnabled': + this._updatePopupPosition(args.value); + this.callBase(args); + break; default: this.callBase(args); } diff --git a/js/ui/drop_down_editor/ui.drop_down_list.js b/js/ui/drop_down_editor/ui.drop_down_list.js index a6e563e216fc..432748ad03b7 100644 --- a/js/ui/drop_down_editor/ui.drop_down_list.js +++ b/js/ui/drop_down_editor/ui.drop_down_list.js @@ -768,7 +768,8 @@ const DropDownList = DropDownEditor.inherit({ const $element = this.$element(); const $customBoundaryContainer = this._$customBoundaryContainer; const offsetTop = $element.offset().top - ($customBoundaryContainer ? $customBoundaryContainer.offset().top : 0); - const containerHeight = ($customBoundaryContainer || $(window)).outerHeight(); + const windowHeight = $(window).outerHeight(); + const containerHeight = $customBoundaryContainer ? Math.min($customBoundaryContainer.outerHeight(), windowHeight) : windowHeight; const maxHeight = Math.max(offsetTop, containerHeight - offsetTop - $element.outerHeight()); return Math.min(containerHeight * 0.5, maxHeight); diff --git a/js/ui/file_manager.d.ts b/js/ui/file_manager.d.ts index a0f25da1cc07..270cef4bde8c 100644 --- a/js/ui/file_manager.d.ts +++ b/js/ui/file_manager.d.ts @@ -4,6 +4,8 @@ import { dxElement } from '../core/element'; +import FileSystemItem from '../file_management/file_system_item'; + import { dxContextMenuItem } from './context_menu'; @@ -56,20 +58,20 @@ export interface dxFileManagerOptions extends WidgetOptions { /** * @docid dxFileManagerOptions.customizeThumbnail * @type function - * @type_function_param1 fileItem:object + * @type_function_param1 fileSystemItem:FileSystemItem * @type_function_return string * @prevFileNamespace DevExpress.ui * @public */ - customizeThumbnail?: ((fileItem: any) => string); + customizeThumbnail?: ((fileSystemItem: FileSystemItem) => string); /** - * @docid dxFileManagerOptions.fileProvider + * @docid dxFileManagerOptions.fileSystemProvider * @type object * @default null * @prevFileNamespace DevExpress.ui * @public */ - fileProvider?: any; + fileSystemProvider?: any; /** * @docid dxFileManagerOptions.itemView * @type object @@ -83,24 +85,25 @@ export interface dxFileManagerOptions extends WidgetOptions { * @extends Action * @type function(e) * @type_function_param1 e:object + * @type_function_param1_field4 directory:FileSystemItem * @default null * @action * @prevFileNamespace DevExpress.ui * @public */ - onCurrentDirectoryChanged?: ((e: { component?: dxFileManager, element?: dxElement, model?: any }) => any); + onCurrentDirectoryChanged?: ((e: { component?: dxFileManager, element?: dxElement, model?: any, directory?: FileSystemItem }) => any); /** * @docid dxFileManagerOptions.onSelectedFileOpened * @extends Action * @type function(e) * @type_function_param1 e:object - * @type_function_param1_field4 fileItem:object + * @type_function_param1_field4 file:FileSystemItem * @default null * @action * @prevFileNamespace DevExpress.ui * @public */ - onSelectedFileOpened?: ((e: { component?: dxFileManager, element?: dxElement, model?: any, fileItem?: any }) => any); + onSelectedFileOpened?: ((e: { component?: dxFileManager, element?: dxElement, model?: any, file?: FileSystemItem }) => any); /** * @docid dxFileManagerOptions.permissions * @type object @@ -137,7 +140,7 @@ export interface dxFileManagerOptions extends WidgetOptions { * @prevFileNamespace DevExpress.ui * @public */ - upload?: { maxFileSize?: number }; + upload?: { maxFileSize?: number, chunkSize?: number }; } /** * @docid dxFileManager @@ -219,15 +222,15 @@ export interface dxFileManagerToolbar { * @prevFileNamespace DevExpress.ui * @public */ - fileSelectionItems?: Array; + fileSelectionItems?: Array; /** * @docid dxFileManagerToolbar.items * @type Array - * @default [ "showNavPane", "create", "upload", "viewSwitcher", { name: "separator", location: "after" }, "refresh" ] + * @default [ "showNavPane", "create", "upload", "switchView", { name: "separator", location: "after" }, "refresh" ] * @prevFileNamespace DevExpress.ui * @public */ - items?: Array; + items?: Array; } export interface dxFileManagerToolbarItem extends dxToolbarItem { @@ -244,7 +247,7 @@ export interface dxFileManagerToolbarItem extends dxToolbarItem { * @prevFileNamespace DevExpress.ui * @public */ - name?: 'showNavPane' | 'create' | 'upload' | 'refresh' | 'viewSwitcher' | 'download' | 'move' | 'copy' | 'rename' | 'delete' | 'clear' | 'separator' | string; + name?: 'showNavPane' | 'create' | 'upload' | 'refresh' | 'switchView' | 'download' | 'move' | 'copy' | 'rename' | 'delete' | 'clear' | 'separator' | string; /** * @docid dxFileManagerToolbarItem.visible * @default undefined diff --git a/js/ui/file_manager/file_items_controller.js b/js/ui/file_manager/file_items_controller.js index 6ae55159c1f8..cca0313c540c 100644 --- a/js/ui/file_manager/file_items_controller.js +++ b/js/ui/file_manager/file_items_controller.js @@ -1,31 +1,32 @@ -import { FileProvider, FileManagerItem, FileManagerRootItem } from './file_provider/file_provider'; -import ArrayFileProvider from './file_provider/array'; -import AjaxFileProvider from './file_provider/ajax'; -import RemoteFileProvider from './file_provider/remote'; -import CustomFileProvider from './file_provider/custom'; -import { pathCombine, getEscapedFileName, getPathParts, getFileExtension } from './ui.file_manager.utils'; -import whenSome, { ErrorCode } from './ui.file_manager.common'; +import FileSystemProviderBase from '../../file_management/provider_base'; +import FileSystemItem from '../../file_management/file_system_item'; +import ObjectFileSystemProvider from '../../file_management/object_provider'; +import RemoteFileSystemProvider from '../../file_management/remote_provider'; +import CustomFileSystemProvider from '../../file_management/custom_provider'; +import ErrorCode from '../../file_management/errors'; +import { pathCombine, getEscapedFileName, getPathParts, getFileExtension } from '../../file_management/utils'; +import whenSome from './ui.file_manager.common'; import { Deferred, when } from '../../core/utils/deferred'; import { find } from '../../core/utils/array'; import { extend } from '../../core/utils/extend'; +const DEFAULT_ROOT_FILE_SYSTEM_ITEM_NAME = 'Files'; + export default class FileItemsController { constructor(options) { options = options || {}; this._options = extend({ }, options); - const rootDirectory = this._createRootDirectory(options.rootText); - this._rootDirectoryInfo = this._createDirectoryInfo(rootDirectory, null); - + this._rootDirectoryInfo = this._createRootDirectoryInfo(options.rootText); this._currentDirectoryInfo = this._rootDirectoryInfo; this._defaultIconMap = this._createDefaultIconMap(); this._securityController = new FileSecurityController({ allowedFileExtensions: this._options.allowedFileExtensions, - maxFileSize: this._options.maxUploadFileSize + maxFileSize: this._options.uploadMaxFileSize }); this.setProvider(options.fileProvider); @@ -47,25 +48,21 @@ export default class FileItemsController { } if(Array.isArray(fileProvider)) { - return new ArrayFileProvider({ data: fileProvider }); + return new ObjectFileSystemProvider({ data: fileProvider }); } - if(typeof fileProvider === 'string') { - return new AjaxFileProvider({ url: fileProvider }); - } - - if(fileProvider instanceof FileProvider) { + if(fileProvider instanceof FileSystemProviderBase) { return fileProvider; } switch(fileProvider.type) { case 'remote': - return new RemoteFileProvider(fileProvider); + return new RemoteFileSystemProvider(fileProvider); case 'custom': - return new CustomFileProvider(fileProvider); + return new CustomFileSystemProvider(fileProvider); } - return new ArrayFileProvider(fileProvider); + return new ObjectFileSystemProvider(fileProvider); } setCurrentPath(path) { @@ -87,7 +84,7 @@ export default class FileItemsController { getCurrentPath() { let currentPath = ''; let directory = this.getCurrentDirectory(); - while(directory && !directory.fileItem.isRoot) { + while(directory && !directory.fileItem.isRoot()) { const escapedName = getEscapedFileName(directory.fileItem.name); currentPath = pathCombine(escapedName, currentPath); directory = directory.parentDirectory; @@ -136,14 +133,13 @@ export default class FileItemsController { .promise(); } - const dirKey = parentDirectoryInfo.fileItem.key; + const dirKey = parentDirectoryInfo.getInternalKey(); let loadItemsDeferred = this._loadedItems[dirKey]; if(loadItemsDeferred) { return loadItemsDeferred; } - const pathInfo = this._getPathInfo(parentDirectoryInfo); - loadItemsDeferred = this._getFileItems(pathInfo) + loadItemsDeferred = this._getFileItems(parentDirectoryInfo) .then(fileItems => { parentDirectoryInfo.items = fileItems.map(fileItem => fileItem.isDirectory && this._createDirectoryInfo(fileItem, parentDirectoryInfo) || this._createFileInfo(fileItem, parentDirectoryInfo) @@ -160,15 +156,15 @@ export default class FileItemsController { return loadItemsDeferred; } - _getFileItems(pathInfo) { - return when(this._fileProvider.getItems(pathInfo)) + _getFileItems(parentDirectoryInfo) { + return when(this._fileProvider.getItems(parentDirectoryInfo.fileItem)) .then(fileItems => this._securityController.getAllowedItems(fileItems)); } createDirectory(parentDirectoryInfo, name) { const actionInfo = this._createEditActionInfo('create', parentDirectoryInfo, parentDirectoryInfo); return this._processEditAction(actionInfo, - () => this._fileProvider.createFolder(parentDirectoryInfo.fileItem, name), + () => this._fileProvider.createDirectory(parentDirectoryInfo.fileItem, name), () => this._resetDirectoryState(parentDirectoryInfo)); } @@ -245,6 +241,10 @@ export default class FileItemsController { } getFileUploadChunkSize() { + const chunkSize = this._options.uploadChunkSize; + if(chunkSize && chunkSize > 0) { + return chunkSize; + } return this._fileProvider.getFileUploadChunkSize(); } @@ -255,7 +255,7 @@ export default class FileItemsController { getItemContent(itemInfos) { const items = itemInfos.map(i => i.fileItem); - return when(this._fileProvider.getItemContent(items)); + return when(this._fileProvider.getItemsContent(items)); } _processEditAction(actionInfo, action, completeAction) { @@ -301,7 +301,7 @@ export default class FileItemsController { const result = []; for(let i = 0; i < files.length; i++) { const file = files[i]; - const item = new FileManagerItem(pathInfo, file.name, false); + const item = new FileSystemItem(pathInfo, file.name, false); const itemInfo = this._createFileInfo(item, parentDirectoryInfo); result.push(itemInfo); } @@ -398,7 +398,7 @@ export default class FileItemsController { _createDirectoryInfo(fileItem, parentDirectoryInfo) { return extend(this._createFileInfo(fileItem, parentDirectoryInfo), { icon: 'folder', - expanded: fileItem.isRoot, + expanded: fileItem.isRoot(), items: [ ] }); } @@ -407,7 +407,13 @@ export default class FileItemsController { return { fileItem, parentDirectory: parentDirectoryInfo, - icon: this._getFileItemDefaultIcon(fileItem) + icon: this._getFileItemDefaultIcon(fileItem), + getInternalKey() { + return `FIK_${this.fileItem.key}`; + }, + getDisplayName() { + return this.displayName || this.fileItem.name; + } }; } @@ -446,10 +452,12 @@ export default class FileItemsController { return result; } - _createRootDirectory(text) { - const root = new FileManagerRootItem(); - root.name = text || ''; - return root; + _createRootDirectoryInfo(text) { + const rootDirectory = new FileSystemItem(null, '', true); + + const result = this._createDirectoryInfo(rootDirectory, null); + result.displayName = text || DEFAULT_ROOT_FILE_SYSTEM_ITEM_NAME; + return result; } _raiseSelectedDirectoryChanged(directoryInfo) { @@ -501,7 +509,7 @@ export default class FileItemsController { _getPathInfo(directoryInfo) { const pathInfo = [ ]; - for(let dirInfo = directoryInfo; dirInfo && !dirInfo.fileItem.isRoot; dirInfo = dirInfo.parentDirectory) { + for(let dirInfo = directoryInfo; dirInfo && !dirInfo.fileItem.isRoot(); dirInfo = dirInfo.parentDirectory) { pathInfo.unshift({ key: dirInfo.fileItem.key, name: dirInfo.fileItem.name diff --git a/js/ui/file_manager/file_provider/ajax.d.ts b/js/ui/file_manager/file_provider/ajax.d.ts deleted file mode 100644 index 898c3a10b5cf..000000000000 --- a/js/ui/file_manager/file_provider/ajax.d.ts +++ /dev/null @@ -1,33 +0,0 @@ -import FileProvider, { - FileProviderOptions -} from './file_provider'; - -export interface AjaxFileProviderOptions extends FileProviderOptions { - /** - * @docid AjaxFileProviderOptions.itemsExpr - * @type string|function(fileItem) - * @prevFileNamespace DevExpress.ui - * @public - */ - itemsExpr?: string | Function; - /** - * @docid AjaxFileProviderOptions.url - * @type string - * @prevFileNamespace DevExpress.ui - * @public - */ - url?: string; -} -/** - * @docid AjaxFileProvider - * @inherits FileProvider - * @type object - * @module ui/file_manager/file_provider/ajax - * @namespace DevExpress.fileProvider - * @export default - * @prevFileNamespace DevExpress.ui - * @public - */ -export default class AjaxFileProvider extends FileProvider { - constructor(options?: AjaxFileProviderOptions) -} diff --git a/js/ui/file_manager/file_provider/ajax.js b/js/ui/file_manager/file_provider/ajax.js deleted file mode 100644 index 58d8426f98d8..000000000000 --- a/js/ui/file_manager/file_provider/ajax.js +++ /dev/null @@ -1,76 +0,0 @@ -import ajax from '../../../core/utils/ajax'; -import { ensureDefined } from '../../../core/utils/common'; -import { Deferred } from '../../../core/utils/deferred'; -import { extend } from '../../../core/utils/extend'; -import { FileProvider } from './file_provider'; -import ArrayFileProvider from './array'; - -class AjaxFileProvider extends FileProvider { - - constructor(options) { - options = ensureDefined(options, { }); - super(options); - - this._options = options; - this._provider = null; - } - - getItems(pathInfo) { - return this._doActionAfterDataAcquired(() => this._provider.getItems(pathInfo)); - } - - renameItem(item, name) { - return this._doActionAfterDataAcquired(() => this._provider.renameItem(item, name)); - } - - createFolder(parentDir, name) { - return this._doActionAfterDataAcquired(() => this._provider.createFolder(parentDir, name)); - } - - deleteItems(items) { - return this._doActionAfterDataAcquired(() => this._provider.deleteItems(items)); - } - - moveItems(items, destinationFolder) { - return this._doActionAfterDataAcquired(() => this._provider.moveItems(items, destinationFolder)); - } - - copyItems(items, destinationFolder) { - return this._doActionAfterDataAcquired(() => this._provider.copyItems(items, destinationFolder)); - } - - uploadFileChunk(fileData, chunksInfo, destinationDirectory) { - return this._doActionAfterDataAcquired(() => this._provider.uploadFileChunk(fileData, chunksInfo, destinationDirectory)); - } - - abortFileUpload(fileData, chunksInfo, destinationDirectory) { - return this._doActionAfterDataAcquired(() => this._provider.abortFileUpload(fileData, chunksInfo, destinationDirectory)); - } - - _doActionAfterDataAcquired(action) { - return this._ensureDataAcquired().then(action.bind(this)); - } - - _ensureDataAcquired() { - if(this._provider) { - return new Deferred().resolve().promise(); - } - - return this._getData() - .done(data => { - const arrayOptions = extend(this._options, { data }); - this._provider = new ArrayFileProvider(arrayOptions); - }); - } - - _getData() { - return ajax.sendRequest({ - url: this._options.url, - dataType: 'json', - cache: false - }); - } - -} - -module.exports = AjaxFileProvider; diff --git a/js/ui/file_manager/file_provider/array.d.ts b/js/ui/file_manager/file_provider/array.d.ts deleted file mode 100644 index c8a5fb6dc596..000000000000 --- a/js/ui/file_manager/file_provider/array.d.ts +++ /dev/null @@ -1,40 +0,0 @@ -import FileProvider, { - FileProviderOptions -} from './file_provider'; - -export interface ArrayFileProviderOptions extends FileProviderOptions { - /** - * @docid ArrayFileProviderOptions.contentExpr - * @type string|function(fileItem) - * @prevFileNamespace DevExpress.ui - * @public - */ - contentExpr?: string | Function; - /** - * @docid ArrayFileProviderOptions.data - * @type Array - * @prevFileNamespace DevExpress.ui - * @public - */ - data?: Array; - /** - * @docid ArrayFileProviderOptions.itemsExpr - * @type string|function(fileItem) - * @prevFileNamespace DevExpress.ui - * @public - */ - itemsExpr?: string | Function; -} -/** - * @docid ArrayFileProvider - * @inherits FileProvider - * @type object - * @module ui/file_manager/file_provider/array - * @namespace DevExpress.fileProvider - * @export default - * @prevFileNamespace DevExpress.ui - * @public - */ -export default class ArrayFileProvider extends FileProvider { - constructor(options?: ArrayFileProviderOptions) -} diff --git a/js/ui/file_manager/file_provider/custom.d.ts b/js/ui/file_manager/file_provider/custom.d.ts deleted file mode 100644 index dfaddc4344be..000000000000 --- a/js/ui/file_manager/file_provider/custom.d.ts +++ /dev/null @@ -1,103 +0,0 @@ -import FileProvider, { - FileProviderOptions -} from './file_provider'; - -export interface CustomFileProviderOptions extends FileProviderOptions { - /** - * @docid CustomFileProviderOptions.abortFileUpload - * @type function - * @prevFileNamespace DevExpress.ui - * @public - */ - abortFileUpload?: Function; - /** - * @docid CustomFileProviderOptions.copyItem - * @type function - * @prevFileNamespace DevExpress.ui - * @public - */ - copyItem?: Function; - /** - * @docid CustomFileProviderOptions.createDirectory - * @type function - * @prevFileNamespace DevExpress.ui - * @public - */ - createDirectory?: Function; - /** - * @docid CustomFileProviderOptions.deleteItem - * @type function - * @prevFileNamespace DevExpress.ui - * @public - */ - deleteItem?: Function; - /** - * @docid CustomFileProviderOptions.downloadItems - * @type function - * @prevFileNamespace DevExpress.ui - * @public - */ - downloadItems?: Function; - /** - * @docid CustomFileProviderOptions.getItems - * @type function - * @prevFileNamespace DevExpress.ui - * @public - */ - getItems?: Function; - /** - * @docid CustomFileProviderOptions.getItemsContent - * @type function - * @prevFileNamespace DevExpress.ui - * @public - */ - getItemsContent?: Function; - /** - * @docid CustomFileProviderOptions.hasSubDirectoriesExpr - * @type string|function(fileItem) - * @prevFileNamespace DevExpress.ui - * @public - */ - hasSubDirectoriesExpr?: string | Function; - /** - * @docid CustomFileProviderOptions.moveItem - * @type function - * @prevFileNamespace DevExpress.ui - * @public - */ - moveItem?: Function; - /** - * @docid CustomFileProviderOptions.renameItem - * @type function - * @prevFileNamespace DevExpress.ui - * @public - */ - renameItem?: Function; - /** - * @docid CustomFileProviderOptions.uploadChunkSize - * @type number - * @prevFileNamespace DevExpress.ui - * @public - */ - uploadChunkSize?: number; - /** - * @docid CustomFileProviderOptions.uploadFileChunk - * @type function - * @prevFileNamespace DevExpress.ui - * @public - */ - uploadFileChunk?: Function; -} -/** - * @docid CustomFileProvider - * @inherits FileProvider - * @type object - * @module ui/file_manager/file_provider/custom - * @namespace DevExpress.fileProvider - * @export default - * @prevFileNamespace DevExpress.ui - * @public - */ -export default class CustomFileProvider extends FileProvider { - constructor(options?: CustomFileProviderOptions) -} diff --git a/js/ui/file_manager/file_provider/file_provider.d.ts b/js/ui/file_manager/file_provider/file_provider.d.ts deleted file mode 100644 index fe193b80d5a4..000000000000 --- a/js/ui/file_manager/file_provider/file_provider.d.ts +++ /dev/null @@ -1,67 +0,0 @@ -import '../../../jquery_augmentation'; - -export interface FileProviderOptions { - /** - * @docid FileProviderOptions.dateModifiedExpr - * @type string|function(fileItem) - * @prevFileNamespace DevExpress.ui - * @public - */ - dateModifiedExpr?: string | Function; - /** - * @docid FileProviderOptions.isDirectoryExpr - * @type string|function(fileItem) - * @prevFileNamespace DevExpress.ui - * @public - */ - isDirectoryExpr?: string | Function; - /** - * @docid FileProviderOptions.keyExpr - * @type string|function(fileItem) - * @prevFileNamespace DevExpress.ui - * @public - */ - keyExpr?: string | Function; - /** - * @docid FileProviderOptions.nameExpr - * @type string|function(fileItem) - * @prevFileNamespace DevExpress.ui - * @public - */ - nameExpr?: string | Function; - /** - * @docid FileProviderOptions.sizeExpr - * @type string|function(fileItem) - * @prevFileNamespace DevExpress.ui - * @public - */ - sizeExpr?: string | Function; - /** - * @docid FileProviderOptions.thumbnailExpr - * @type string|function(fileItem) - * @prevFileNamespace DevExpress.ui - * @public - */ - thumbnailExpr?: string | Function; -} -/** - * @docid FileProvider - * @type object - * @module ui/file_manager/file_provider/file_provider - * @namespace DevExpress.fileProvider - * @export default - * @hidden - * @prevFileNamespace DevExpress.ui - */ -export default class FileProvider { - constructor(options?: FileProviderOptions) - /** - * @docid FileProviderMethods.getItemContent - * @publicName getItemContent() - * @param1 items:Array - * @return Promise - * @prevFileNamespace DevExpress.ui - * @public - */ - getItemContent(items: Array): Promise & JQueryPromise; -} diff --git a/js/ui/file_manager/file_provider/remote.d.ts b/js/ui/file_manager/file_provider/remote.d.ts deleted file mode 100644 index fa84c0c1ffd3..000000000000 --- a/js/ui/file_manager/file_provider/remote.d.ts +++ /dev/null @@ -1,33 +0,0 @@ -import FileProvider, { - FileProviderOptions -} from './file_provider'; - -export interface RemoteFileProviderOptions extends FileProviderOptions { - /** - * @docid RemoteFileProviderOptions.endpointUrl - * @type string - * @prevFileNamespace DevExpress.ui - * @public - */ - endpointUrl?: string; - /** - * @docid RemoteFileProviderOptions.hasSubDirectoriesExpr - * @type string|function(fileItem) - * @prevFileNamespace DevExpress.ui - * @public - */ - hasSubDirectoriesExpr?: string | Function; -} -/** - * @docid RemoteFileProvider - * @inherits FileProvider - * @type object - * @module ui/file_manager/file_provider/remote - * @namespace DevExpress.fileProvider - * @export default - * @prevFileNamespace DevExpress.ui - * @public - */ -export default class RemoteFileProvider extends FileProvider { - constructor(options?: RemoteFileProviderOptions) -} diff --git a/js/ui/file_manager/ui.file_manager.breadcrumbs.js b/js/ui/file_manager/ui.file_manager.breadcrumbs.js index c22cdcdb72f6..314b0fd4beec 100644 --- a/js/ui/file_manager/ui.file_manager.breadcrumbs.js +++ b/js/ui/file_manager/ui.file_manager.breadcrumbs.js @@ -70,7 +70,7 @@ class FileManagerBreadcrumbs extends Widget { dirLine.forEach((dir, index) => { result.push({ - text: dir.fileItem.name, + text: dir.getDisplayName(), directory: dir, isPathItem: true }); diff --git a/js/ui/file_manager/ui.file_manager.command_manager.js b/js/ui/file_manager/ui.file_manager.command_manager.js index 54136b13c4ca..95780a3baf45 100644 --- a/js/ui/file_manager/ui.file_manager.command_manager.js +++ b/js/ui/file_manager/ui.file_manager.command_manager.js @@ -43,7 +43,7 @@ export class FileManagerCommandManager { name: 'delete', text: messageLocalization.format('dxFileManager-commandDelete'), icon: 'trash', - enabled: this._permissions.remove, + enabled: this._permissions.delete, }, { name: 'download', @@ -131,7 +131,7 @@ export class FileManagerCommandManager { } const itemsLength = itemInfos && itemInfos.length || 0; - if(itemsLength === 0 || itemInfos.some(item => item.fileItem.isRoot || item.fileItem.isParentFolder)) { + if(itemsLength === 0 || itemInfos.some(item => item.fileItem.isRoot() || item.fileItem.isParentFolder)) { return false; } diff --git a/js/ui/file_manager/ui.file_manager.common.js b/js/ui/file_manager/ui.file_manager.common.js index 7fd6046050ef..c79a3e868598 100644 --- a/js/ui/file_manager/ui.file_manager.common.js +++ b/js/ui/file_manager/ui.file_manager.common.js @@ -2,18 +2,6 @@ import { when, Deferred } from '../../core/utils/deferred'; import { noop } from '../../core/utils/common'; import typeUtils from '../../core/utils/type'; -const ErrorCode = { - NoAccess: 0, - FileExists: 1, - FileNotFound: 2, - DirectoryExists: 3, - DirectoryNotFound: 4, - WrongFileExtension: 5, - MaxFileSizeExceeded: 6, - InvalidSymbols: 7, - Other: 32767 -}; - const whenSome = function(arg, onSuccess, onError) { onSuccess = onSuccess || noop; onError = onError || noop; @@ -42,5 +30,17 @@ const whenSome = function(arg, onSuccess, onError) { return when.apply(null, deferreds); }; +const getDisplayFileSize = function(byteSize) { + const sizesTitles = [ 'B', 'KB', 'MB', 'GB', 'TB' ]; + let index = 0; + let displaySize = byteSize; + while(displaySize >= 1024 && index <= sizesTitles.length - 1) { + displaySize /= 1024; + index++; + } + displaySize = Math.round(displaySize * 10) / 10; + return `${displaySize} ${sizesTitles[index]}`; +}; + module.exports = whenSome; -module.exports.ErrorCode = ErrorCode; +module.exports.getDisplayFileSize = getDisplayFileSize; diff --git a/js/ui/file_manager/ui.file_manager.dialog.folder_chooser.js b/js/ui/file_manager/ui.file_manager.dialog.folder_chooser.js index 6bc8f2d19ec6..60801a5e1924 100644 --- a/js/ui/file_manager/ui.file_manager.dialog.folder_chooser.js +++ b/js/ui/file_manager/ui.file_manager.dialog.folder_chooser.js @@ -16,10 +16,18 @@ class FileManagerFolderChooserDialog extends FileManagerDialogBase { super.show(); } + switchToCopyDialog() { + this._setTitle(messageLocalization.format('dxFileManager-dialogDirectoryChooserCopyTitle')); + this._setButtonText(messageLocalization.format('dxFileManager-dialogDirectoryChooserCopyButtonText')); + } + + switchToMoveDialog() { + this._setTitle(messageLocalization.format('dxFileManager-dialogDirectoryChooserMoveTitle')); + this._setButtonText(messageLocalization.format('dxFileManager-dialogDirectoryChooserMoveButtonText')); + } + _getDialogOptions() { return extend(super._getDialogOptions(), { - title: messageLocalization.format('dxFileManager-dialogDirectoryChooserTitle'), - buttonText: messageLocalization.format('dxFileManager-dialogDirectoryChooserButtonText'), contentCssClass: FILE_MANAGER_DIALOG_FOLDER_CHOOSER, popupCssClass: FILE_MANAGER_DIALOG_FOLDER_CHOOSER_POPUP }); diff --git a/js/ui/file_manager/ui.file_manager.dialog.js b/js/ui/file_manager/ui.file_manager.dialog.js index a2f743069193..67a3d888c55e 100644 --- a/js/ui/file_manager/ui.file_manager.dialog.js +++ b/js/ui/file_manager/ui.file_manager.dialog.js @@ -94,6 +94,14 @@ class FileManagerDialogBase extends Widget { this._onClosedAction = this._createActionByOption('onClosed'); } + _setTitle(newTitle) { + this._popup.option('title', newTitle); + } + + _setButtonText(newText) { + this._popup.option('toolbarItems[0].options.text', newText); + } + _getDefaultOptions() { return extend(super._getDefaultOptions(), { onClosed: null diff --git a/js/ui/file_manager/ui.file_manager.dialog_manager.js b/js/ui/file_manager/ui.file_manager.dialog_manager.js new file mode 100644 index 000000000000..d7961465f0d5 --- /dev/null +++ b/js/ui/file_manager/ui.file_manager.dialog_manager.js @@ -0,0 +1,64 @@ +import $ from '../../core/renderer'; +import { extend } from '../../core/utils/extend'; + +import messageLocalization from '../../localization/message'; + +import FileManagerNameEditorDialog from './ui.file_manager.dialog.name_editor'; +import FileManagerFolderChooserDialog from './ui.file_manager.dialog.folder_chooser'; + +class FileManagerDialogManager { + constructor($element, options) { + this._$element = $element; + this._options = options; + + const $chooseFolderDialog = $('
').appendTo(this._$element); + this._chooseDirectoryDialog = new FileManagerFolderChooserDialog($chooseFolderDialog, + extend(this._options['chooseDirectoryDialog'], { onClosed: this._options['onDialogClosed'] })); + + const $renameDialog = $('
').appendTo(this._$element); + this._renameItemDialog = new FileManagerNameEditorDialog($renameDialog, { + title: messageLocalization.format('dxFileManager-dialogRenameItemTitle'), + buttonText: messageLocalization.format('dxFileManager-dialogRenameItemButtonText'), + onClosed: this._options['onDialogClosed'] + }); + + const $createDialog = $('
').appendTo(this._$element); + this._createItemDialog = new FileManagerNameEditorDialog($createDialog, { + title: messageLocalization.format('dxFileManager-dialogCreateDirectoryTitle'), + buttonText: messageLocalization.format('dxFileManager-dialogCreateDirectoryButtonText'), + onClosed: this._options['onDialogClosed'] + }); + + this._confirmationDialog = { // TODO implement this dialog + show: () => { + setTimeout(() => { + this._options['onDialogClosed']({ dialogResult: {} }); + }); + } + }; + } + + getCopyDialog() { + this._chooseDirectoryDialog.switchToCopyDialog(); + return this._chooseDirectoryDialog; + } + + getMoveDialog() { + this._chooseDirectoryDialog.switchToMoveDialog(); + return this._chooseDirectoryDialog; + } + + getRenameItemDialog() { + return this._renameItemDialog; + } + + getCreateItemDialog() { + return this._createItemDialog; + } + + getConfirmationDialog() { + return this._confirmationDialog; + } +} + +module.exports = FileManagerDialogManager; diff --git a/js/ui/file_manager/ui.file_manager.editing.js b/js/ui/file_manager/ui.file_manager.editing.js index 7f84af9061c8..5a9848548ad9 100644 --- a/js/ui/file_manager/ui.file_manager.editing.js +++ b/js/ui/file_manager/ui.file_manager.editing.js @@ -8,8 +8,7 @@ import messageLocalization from '../../localization/message'; import Widget from '../widget/ui.widget'; -import FileManagerNameEditorDialog from './ui.file_manager.dialog.name_editor'; -import FileManagerFolderChooserDialog from './ui.file_manager.dialog.folder_chooser'; +import FileManagerDialogManager from './ui.file_manager.dialog_manager'; import FileManagerFileUploader from './ui.file_manager.file_uploader'; import { FileManagerMessages } from './ui.file_manager.messages'; @@ -31,23 +30,15 @@ class FileManagerEditingControl extends Widget { this._model = this.option('model'); this._uploadOperationInfoMap = {}; - this._renameItemDialog = this._createEnterNameDialog( - messageLocalization.format('dxFileManager-dialogRenameItemTitle'), - messageLocalization.format('dxFileManager-dialogRenameItemButtonText')); - this._createFolderDialog = this._createEnterNameDialog( - messageLocalization.format('dxFileManager-dialogCreateDirectoryTitle'), - messageLocalization.format('dxFileManager-dialogCreateDirectoryButtonText')); - - const $chooseFolderDialog = $('
').appendTo(this.$element()); - this._chooseFolderDialog = this._createComponent($chooseFolderDialog, FileManagerFolderChooserDialog, { - provider: this._controller._fileProvider, - getDirectories: this._controller.getDirectories.bind(this._controller), - getCurrentDirectory: this._controller.getCurrentDirectory.bind(this._controller), - onClosed: this._onDialogClosed.bind(this) + this._dialogManager = new FileManagerDialogManager(this.$element(), { + chooseDirectoryDialog: { + provider: this._controller._fileProvider, + getDirectories: this._controller.getDirectories.bind(this._controller), + getCurrentDirectory: this._controller.getCurrentDirectory.bind(this._controller), + }, + onDialogClosed: this._onDialogClosed.bind(this) }); - this._confirmationDialog = this._createConfirmationDialog(); - this._fileUploader = this._createFileUploader(); this._createMetadataMap(); @@ -83,25 +74,6 @@ class FileManagerEditingControl extends Widget { }; } - _createEnterNameDialog(title, buttonText) { - const $dialog = $('
').appendTo(this.$element()); - return this._createComponent($dialog, FileManagerNameEditorDialog, { - title: title, - buttonText: buttonText, - onClosed: this._onDialogClosed.bind(this) - }); - } - - _createConfirmationDialog() { - return { // TODO implement this dialog - show: () => { - setTimeout(() => { - this._onDialogClosed({ dialogResult: {} }); - }); - } - }; - } - _createMetadataMap() { this._metadataMap = { @@ -269,31 +241,31 @@ class FileManagerEditingControl extends Widget { _tryCreate(parentDirectories) { const parentDirectoryInfo = parentDirectories && parentDirectories[0] || this._getCurrentDirectory(); const newDirName = messageLocalization.format('dxFileManager-newDirectoryName'); - return this._showDialog(this._createFolderDialog, newDirName) + return this._showDialog(this._dialogManager.getCreateItemDialog(), newDirName) .then(({ name }) => this._controller.createDirectory(parentDirectoryInfo, name)); } _tryRename(itemInfos) { const itemInfo = itemInfos && itemInfos[0] || this._model.getMultipleSelectedItems()[0]; - return this._showDialog(this._renameItemDialog, itemInfo.fileItem.name) + return this._showDialog(this._dialogManager.getRenameItemDialog(), itemInfo.fileItem.name) .then(({ name }) => this._controller.renameItem(itemInfo, name)); } _tryDelete(itemInfos) { itemInfos = itemInfos || this._model.getMultipleSelectedItems(); - return this._showDialog(this._confirmationDialog) + return this._showDialog(this._dialogManager.getConfirmationDialog()) .then(() => this._controller.deleteItems(itemInfos)); } _tryMove(itemInfos) { itemInfos = itemInfos || this._model.getMultipleSelectedItems(); - return this._showDialog(this._chooseFolderDialog) + return this._showDialog(this._dialogManager.getMoveDialog()) .then(({ folder }) => this._controller.moveItems(itemInfos, folder)); } _tryCopy(itemInfos) { itemInfos = itemInfos || this._model.getMultipleSelectedItems(); - return this._showDialog(this._chooseFolderDialog) + return this._showDialog(this._dialogManager.getCopyDialog()) .then(({ folder }) => this._controller.copyItems(itemInfos, folder)); } @@ -466,7 +438,7 @@ class FileManagerActionContext { this._onlyFiles = !this._actionMetadata.affectsAllItems && this._itemInfos.every(info => !info.fileItem.isDirectory); this._items = this._itemInfos.map(itemInfo => itemInfo.fileItem); this._multipleItems = this._items.length > 1; - this._location = directoryInfo.fileItem.name; + this._location = directoryInfo.getDisplayName(); this._singleRequest = true; diff --git a/js/ui/file_manager/ui.file_manager.file_actions_button.js b/js/ui/file_manager/ui.file_manager.file_actions_button.js index e0976c478f9d..510648490e91 100644 --- a/js/ui/file_manager/ui.file_manager.file_actions_button.js +++ b/js/ui/file_manager/ui.file_manager.file_actions_button.js @@ -20,12 +20,9 @@ class FileManagerFileActionsButton extends Widget { .addClass(FILE_MANAGER_FILE_ACTIONS_BUTTON); this._button = this._createComponent($button, Button, { - text: '⋮', + icon: 'overflow', stylingMode: 'text', - onClick: e => this._raiseClick(e), - template: () => { - return $('').html('⋮'); - } + onClick: e => this._raiseClick(e) }); super._initMarkup(); diff --git a/js/ui/file_manager/ui.file_manager.files_tree_view.js b/js/ui/file_manager/ui.file_manager.files_tree_view.js index b7f45cfaae0b..e1799c031768 100644 --- a/js/ui/file_manager/ui.file_manager.files_tree_view.js +++ b/js/ui/file_manager/ui.file_manager.files_tree_view.js @@ -32,9 +32,9 @@ class FileManagerFilesTreeView extends Widget { rootValue: '', createChildren: this._onFilesTreeViewCreateSubDirectories.bind(this), itemTemplate: this._createFilesTreeViewItemTemplate.bind(this), - keyExpr: 'fileItem.key', - parentIdExpr: 'parentDirectory.fileItem.key', - displayExpr: 'fileItem.name', + keyExpr: 'getInternalKey', + parentIdExpr: 'parentDirectory.getInternalKey', + displayExpr: itemInfo => itemInfo.getDisplayName(), hasItemsExpr: 'fileItem.hasSubDirs', onItemClick: this._createActionByOption('onDirectoryClick'), onItemExpanded: e => this._onFilesTreeViewItemExpanded(e), @@ -100,7 +100,7 @@ class FileManagerFilesTreeView extends Widget { const $image = getImageContainer(itemData.icon); const $text = $('') - .text(itemData.fileItem.name) + .text(itemData.getDisplayName()) .addClass(FILE_MANAGER_DIRS_TREE_ITEM_TEXT_CLASS); const $button = $('
'); @@ -134,7 +134,7 @@ class FileManagerFilesTreeView extends Widget { _updateFocusedElement() { const directoryInfo = this._getCurrentDirectory(); - const $element = this._getItemElementByKey(directoryInfo.fileItem.key); + const $element = this._getItemElementByKey(directoryInfo.getInternalKey()); if(this._$focusedElement) { this._$focusedElement.toggleClass(FILE_MANAGER_DIRS_TREE_FOCUSED_ITEM_CLASS, false); } @@ -201,7 +201,7 @@ class FileManagerFilesTreeView extends Widget { if(!directoryInfo || directoryInfo.items.length === 0) { return deferred.reject().promise(); } - const treeViewNode = this._filesTreeView._dataAdapter.getNodeByKey(directoryInfo.fileItem.key); + const treeViewNode = this._filesTreeView._dataAdapter.getNodeByKey(directoryInfo.getInternalKey()); if(!treeViewNode) { return deferred.reject().promise(); } @@ -210,7 +210,7 @@ class FileManagerFilesTreeView extends Widget { } treeViewNode.expandedDeferred = deferred; - this._filesTreeView.expandItem(directoryInfo.fileItem.key); + this._filesTreeView.expandItem(directoryInfo.getInternalKey()); return deferred.promise(); } diff --git a/js/ui/file_manager/ui.file_manager.item_list.details.js b/js/ui/file_manager/ui.file_manager.item_list.details.js index c56b5f6e3417..71f0b06103db 100644 --- a/js/ui/file_manager/ui.file_manager.item_list.details.js +++ b/js/ui/file_manager/ui.file_manager.item_list.details.js @@ -7,7 +7,7 @@ import CustomStore from '../../data/custom_store'; import FileManagerItemListBase from './ui.file_manager.item_list'; import FileManagerFileActionsButton from './ui.file_manager.file_actions_button'; -import { getDisplayFileSize } from './ui.file_manager.utils.js'; +import { getDisplayFileSize } from './ui.file_manager.common'; const FILE_MANAGER_DETAILS_ITEM_LIST_CLASS = 'dx-filemanager-details'; const FILE_MANAGER_DETAILS_ITEM_THUMBNAIL_CLASS = 'dx-filemanager-details-item-thumbnail'; diff --git a/js/ui/file_manager/ui.file_manager.item_list.thumbnails.js b/js/ui/file_manager/ui.file_manager.item_list.thumbnails.js index 798ebfc6f6fa..0786ae6b8b79 100644 --- a/js/ui/file_manager/ui.file_manager.item_list.thumbnails.js +++ b/js/ui/file_manager/ui.file_manager.item_list.thumbnails.js @@ -4,7 +4,7 @@ import { when } from '../../core/utils/deferred'; import eventsEngine from '../../events/core/events_engine'; import { addNamespace } from '../../events/utils'; import { name as contextMenuEventName } from '../../events/contextmenu'; -import { getDisplayFileSize } from './ui.file_manager.utils.js'; +import { getDisplayFileSize } from './ui.file_manager.common'; import messageLocalization from '../../localization/message'; import FileManagerItemListBase from './ui.file_manager.item_list'; diff --git a/js/ui/file_manager/ui.file_manager.js b/js/ui/file_manager/ui.file_manager.js index 1cb362f61ac1..d0f50c50dd2e 100644 --- a/js/ui/file_manager/ui.file_manager.js +++ b/js/ui/file_manager/ui.file_manager.js @@ -45,9 +45,10 @@ class FileManager extends Widget { this._controller = new FileItemsController({ currentPath: this.option('currentPath'), rootText: this.option('rootFolderName'), - fileProvider: this.option('fileProvider'), + fileProvider: this.option('fileSystemProvider'), allowedFileExtensions: this.option('allowedFileExtensions'), - maxUploadFileSize: this.option('upload').maxFileSize, + uploadMaxFileSize: this.option('upload').maxFileSize, + uploadChunkSize: this.option('upload').chunkSize, onSelectedDirectoryChanged: this._onSelectedDirectoryChanged.bind(this) }); this._commandManager = new FileManagerCommandManager(this.option('permissions')); @@ -68,7 +69,8 @@ class FileManager extends Widget { this._notificationControl = this._createComponent($notificationControl, FileManagerNotificationControl, { progressPanelContainer: this.$element(), contentTemplate: container => this._createWrapper(container), - onActionProgress: e => this._onActionProgress(e) + onActionProgress: e => this._onActionProgress(e), + positionTarget: `.${FILE_MANAGER_CONTAINER_CLASS}` }); this._editing.option('notificationControl', this._notificationControl); } @@ -301,7 +303,7 @@ class FileManager extends Widget { ? this._controller.getDirectoryContents(selectedDir) : this._controller.getFiles(selectedDir); - if(this.option('itemView.showParentFolder') && !selectedDir.fileItem.isRoot) { + if(this.option('itemView.showParentFolder') && !selectedDir.fileItem.isRoot()) { const parentDirItem = selectedDir.fileItem.createClone(); parentDirItem.isParentFolder = true; parentDirItem.name = '..'; @@ -311,7 +313,7 @@ class FileManager extends Widget { const itemInfosCopy = [...items]; itemInfosCopy.unshift({ fileItem: parentDirItem, - icon: 'folder' + icon: 'parentfolder' }); return itemInfosCopy; }); @@ -340,7 +342,7 @@ class FileManager extends Widget { _getDefaultOptions() { return extend(super._getDefaultOptions(), { - fileProvider: null, + fileSystemProvider: null, currentPath: '', @@ -361,7 +363,7 @@ class FileManager extends Widget { toolbar: { items: [ - 'showNavPane', 'create', 'upload', 'viewSwitcher', + 'showNavPane', 'create', 'upload', 'switchView', { name: 'separator', location: 'after' @@ -433,7 +435,14 @@ class FileManager extends Widget { * @type number * @default 0 */ - maxFileSize: 0 + maxFileSize: 0, + + /** + * @name dxFileManagerOptions.upload.chunkSize + * @type number + * @default 200000 + */ + chunkSize: 200000 }, permissions: { @@ -456,11 +465,11 @@ class FileManager extends Widget { */ move: false, /** - * @name dxFileManagerOptions.permissions.remove + * @name dxFileManagerOptions.permissions.delete * @type boolean * @default false */ - remove: false, + delete: false, /** * @name dxFileManagerOptions.permissions.rename * @type boolean @@ -490,7 +499,7 @@ class FileManager extends Widget { case 'currentPath': this._setCurrentPath(args.value); break; - case 'fileProvider': + case 'fileSystemProvider': case 'selectionMode': case 'customizeThumbnail': case 'customizeDetailColumns': @@ -542,14 +551,15 @@ class FileManager extends Widget { } _onSelectedDirectoryChanged() { + const currentDirectory = this._getCurrentDirectory(); const currentPath = this._controller.getCurrentPath(); this._filesTreeView.updateCurrentDirectory(); this._itemView.refresh(); - this._breadcrumbs.setCurrentDirectory(this._getCurrentDirectory()); + this._breadcrumbs.setCurrentDirectory(currentDirectory); this.option('currentPath', currentPath); - this._onCurrentDirectoryChangedAction(); + this._onCurrentDirectoryChangedAction({ directory: currentDirectory.fileItem }); } getDirectories(parentDirectoryInfo) { @@ -576,7 +586,7 @@ class FileManager extends Widget { _onSelectedItemOpened({ fileItemInfo }) { const fileItem = fileItemInfo.fileItem; if(!fileItem.isDirectory) { - this._onSelectedFileOpenedAction({ fileItem }); + this._onSelectedFileOpenedAction({ file: fileItem }); return; } diff --git a/js/ui/file_manager/ui.file_manager.messages.js b/js/ui/file_manager/ui.file_manager.messages.js index 27e1d911b9af..d797383e5bde 100644 --- a/js/ui/file_manager/ui.file_manager.messages.js +++ b/js/ui/file_manager/ui.file_manager.messages.js @@ -1,5 +1,5 @@ import messageLocalization from '../../localization/message'; -import { ErrorCode } from './ui.file_manager.common'; +import ErrorCode from '../../file_management/errors'; export const FileManagerMessages = { get: (errorId, args) => { diff --git a/js/ui/file_manager/ui.file_manager.notification.js b/js/ui/file_manager/ui.file_manager.notification.js index f910c9e88a8d..82ff2fd39570 100644 --- a/js/ui/file_manager/ui.file_manager.notification.js +++ b/js/ui/file_manager/ui.file_manager.notification.js @@ -205,7 +205,12 @@ export default class FileManagerNotificationControl extends Widget { visible: false, closeOnOutsideClick: true, animation: { duration: 0 }, - position: { my: 'right top', at: 'right bottom', of: '.dx-filemanager-toolbar', offset: '-50 -5' } // TODO make option for this + position: { + my: 'right top', + at: 'right top', + of: this.option('positionTarget'), + offset: '-10 -5' + } }); } return this._notificationPopup; diff --git a/js/ui/file_manager/ui.file_manager.notification.progress_panel.js b/js/ui/file_manager/ui.file_manager.notification.progress_panel.js index 8d003b71e93e..90198eacbbf4 100644 --- a/js/ui/file_manager/ui.file_manager.notification.progress_panel.js +++ b/js/ui/file_manager/ui.file_manager.notification.progress_panel.js @@ -28,6 +28,7 @@ const FILE_MANAGER_PROGRESS_BOX_WRAPPER_CLASS = `${FILE_MANAGER_PROGRESS_BOX_CLA const FILE_MANAGER_PROGRESS_BOX_COMMON_CLASS = `${FILE_MANAGER_PROGRESS_BOX_CLASS}-common`; const FILE_MANAGER_PROGRESS_BOX_PROGRESS_BAR_CLASS = `${FILE_MANAGER_PROGRESS_BOX_CLASS}-progress-bar`; const FILE_MANAGER_PROGRESS_BOX_CLOSE_BUTTON_CLASS = `${FILE_MANAGER_PROGRESS_BOX_CLASS}-close-button`; +const DX_CARD_CLASS = 'dx-card'; class FileManagerProgressPanel extends Widget { @@ -161,6 +162,9 @@ class FileManagerProgressPanel extends Widget { _createDetailsItem($container, item, itemIndex, skipProgressBox, showCloseButton) { const $detailsItem = $('
').appendTo($container); + if(itemIndex !== -1) { + $detailsItem.addClass(DX_CARD_CLASS); + } return this._createProgressBox($detailsItem, { commonText: item.commonText, imageUrl: item.imageUrl, diff --git a/js/ui/file_manager/ui.file_manager.toolbar.js b/js/ui/file_manager/ui.file_manager.toolbar.js index b29ecc0172b9..1c9041c57ba6 100644 --- a/js/ui/file_manager/ui.file_manager.toolbar.js +++ b/js/ui/file_manager/ui.file_manager.toolbar.js @@ -43,7 +43,7 @@ const DEFAULT_ITEM_CONFIGS = { locateInMenu: 'auto' } }, - viewSwitcher: { + switchView: { location: 'after' }, download: { @@ -92,7 +92,7 @@ const DEFAULT_ITEM_CONFIGS = { } }; -const ALWAYS_VISIBLE_TOOLBAR_ITEMS = [ 'separator', 'viewSwitcher' ]; +const ALWAYS_VISIBLE_TOOLBAR_ITEMS = [ 'separator', 'switchView' ]; const REFRESH_ICON_MAP = { default: 'dx-filemanager-i dx-filemanager-i-refresh', @@ -199,7 +199,7 @@ class FileManagerToolbar extends Widget { case 'separator': result = this._createSeparatorItem(); break; - case 'viewSwitcher': + case 'switchView': result = this._createViewModeItem(); break; } diff --git a/js/ui/file_uploader.d.ts b/js/ui/file_uploader.d.ts index f9521cdff40e..97377035d032 100644 --- a/js/ui/file_uploader.d.ts +++ b/js/ui/file_uploader.d.ts @@ -12,22 +12,19 @@ import Editor, { EditorOptions } from './editor/editor'; +import UploadInfo from '../file_management/upload_info'; + export interface dxFileUploaderOptions extends EditorOptions { /** * @docid dxFileUploaderOptions.abortUpload * @type function * @type_function_param1 file:File - * @type_function_param2 uploadInfo:object - * @type_function_param2_field1 bytesUploaded:Number - * @type_function_param2_field2 chunkCount:Number - * @type_function_param2_field3 customData:object - * @type_function_param2_field4 chunkBlob:Blob - * @type_function_param2_field5 chunkIndex:Number + * @type_function_param2 uploadInfo?:UploadInfo * @type_function_return Promise|any * @prevFileNamespace DevExpress.ui * @public */ - abortUpload?: ((file: File, uploadInfo: { bytesUploaded?: number, chunkCount?: number, customData?: any, chunkBlob?: Blob, chunkIndex?: number }) => Promise | JQueryPromise | any); + abortUpload?: ((file: File, uploadInfo?: UploadInfo) => Promise | JQueryPromise | any); /** * @docid dxFileUploaderOptions.accept * @type string @@ -264,17 +261,12 @@ export interface dxFileUploaderOptions extends EditorOptions { * @docid dxFileUploaderOptions.uploadChunk * @type function * @type_function_param1 file:File - * @type_function_param2 uploadInfo:object - * @type_function_param2_field1 bytesUploaded:Number - * @type_function_param2_field2 chunkCount:Number - * @type_function_param2_field3 customData:object - * @type_function_param2_field4 chunkBlob:Blob - * @type_function_param2_field5 chunkIndex:Number + * @type_function_param2 uploadInfo:UploadInfo * @type_function_return Promise|any * @prevFileNamespace DevExpress.ui * @public */ - uploadChunk?: ((file: File, uploadInfo: { bytesUploaded?: number, chunkCount?: number, customData?: any, chunkBlob?: Blob, chunkIndex?: number }) => Promise | JQueryPromise | any); + uploadChunk?: ((file: File, uploadInfo: UploadInfo) => Promise | JQueryPromise | any); /** * @docid dxFileUploaderOptions.uploadFailedMessage * @type string diff --git a/js/ui/form/ui.form.layout_manager.js b/js/ui/form/ui.form.layout_manager.js index ed5024df9a52..b301e5d3fd33 100644 --- a/js/ui/form/ui.form.layout_manager.js +++ b/js/ui/form/ui.form.layout_manager.js @@ -1199,7 +1199,9 @@ const LayoutManager = Widget.inherit({ } }); editorInstance.on('valueChanged', args => { - if(!this._disableEditorValueChangedHandler && !(isObject(args.value) && args.value === args.previousValue)) { + // TODO: This need only for the KO integration + const isValueReferenceType = isObject(args.value) || Array.isArray(args.value); + if(!this._disableEditorValueChangedHandler && !(isValueReferenceType && args.value === args.previousValue)) { this._updateFieldValue(dataField, args.value); } }); diff --git a/js/ui/gantt.d.ts b/js/ui/gantt.d.ts index 7d976bf29397..069d699f66d4 100644 --- a/js/ui/gantt.d.ts +++ b/js/ui/gantt.d.ts @@ -161,14 +161,23 @@ export interface dxGanttTimeMarker { */ cssClass?: string; /** - * @docid dxGanttTimeMarker.dateTime + * @docid dxGanttTimeMarker.end * @type Date|number|string|function * @type_function_return Date|number|string * @default undefined * @prevFileNamespace DevExpress.ui * @public */ - dateTime?: Date | number | string | (() => Date | number | string); + end?: Date | number | string | (() => Date | number | string); + /** + * @docid dxGanttTimeMarker.start + * @type Date|number|string|function + * @type_function_return Date|number|string + * @default undefined + * @prevFileNamespace DevExpress.ui + * @public + */ + start?: Date | number | string | (() => Date | number | string); /** /** * @docid dxGanttTimeMarker.title diff --git a/js/ui/grid_core/ui.grid_core.adaptivity.js b/js/ui/grid_core/ui.grid_core.adaptivity.js index c1371a156adc..7d99b4d3eb21 100644 --- a/js/ui/grid_core/ui.grid_core.adaptivity.js +++ b/js/ui/grid_core/ui.grid_core.adaptivity.js @@ -41,6 +41,7 @@ const EDIT_MODE_ROW = 'row'; const EDIT_MODE_FORM = 'form'; const EDIT_MODE_POPUP = 'popup'; const REVERT_TOOLTIP_CLASS = 'revert-tooltip'; +const GROUP_CELL_CLASS = 'dx-group-cell'; function getColumnId(that, column) { return that._columnsController.getColumnId(column); @@ -384,7 +385,7 @@ const AdaptiveColumnsController = modules.ViewController.inherit({ }, _isCellValid: function($cell) { - return $cell && $cell.length && !$cell.hasClass(MASTER_DETAIL_CELL_CLASS); + return $cell && $cell.length && !$cell.hasClass(MASTER_DETAIL_CELL_CLASS) && !$cell.hasClass(GROUP_CELL_CLASS); }, _addCssClassToColumn: function(cssClassName, visibleIndex) { @@ -1026,6 +1027,7 @@ module.exports = { rowType: ADAPTIVE_ROW_TYPE, key: item.key, data: item.data, + node: item.node, modifiedValues: item.modifiedValues, isNewRow: item.isNewRow, values: item.values diff --git a/js/ui/grid_core/ui.grid_core.column_headers.js b/js/ui/grid_core/ui.grid_core.column_headers.js index 57c6d152384f..f65341cde225 100644 --- a/js/ui/grid_core/ui.grid_core.column_headers.js +++ b/js/ui/grid_core/ui.grid_core.column_headers.js @@ -50,13 +50,19 @@ module.exports = { const indicatorCount = $indicatorElements && $indicatorElements.length; const columnAlignment = that._getColumnAlignment(column.alignment); + const sortIndicatorClassName = `.${that._getIndicatorClassName('sort')}`; + const sortIndexIndicatorClassName = `.${that._getIndicatorClassName('sortIndex')}`; + + const $sortIndicator = $visibleIndicatorElements.filter(sortIndicatorClassName); + const $sortIndexIndicator = $visibleIndicatorElements.children().filter(sortIndexIndicatorClassName); + $cellContent = $cellContent || $cell.children('.' + that.addWidgetPrefix(CELL_CONTENT_CLASS)); $cellContent .toggleClass(TEXT_CONTENT_ALIGNMENT_CLASS_PREFIX + columnAlignment, indicatorCount > 0) .toggleClass(TEXT_CONTENT_ALIGNMENT_CLASS_PREFIX + (columnAlignment === 'left' ? 'right' : 'left'), indicatorCount > 0 && column.alignment === 'center') - .toggleClass(SORT_INDICATOR_CLASS, !!$visibleIndicatorElements.filter('.' + that._getIndicatorClassName('sort')).length) - .toggleClass(SORT_INDEX_INDICATOR_CLASS, !!$visibleIndicatorElements.children().filter('.' + that._getIndicatorClassName('sortIndex')).length) + .toggleClass(SORT_INDICATOR_CLASS, !!$sortIndicator.length) + .toggleClass(SORT_INDEX_INDICATOR_CLASS, !!$sortIndexIndicator.length) .toggleClass(HEADER_FILTER_INDICATOR_CLASS, !!$visibleIndicatorElements.filter('.' + that._getIndicatorClassName('headerFilter')).length); } diff --git a/js/ui/grid_core/ui.grid_core.columns_controller.js b/js/ui/grid_core/ui.grid_core.columns_controller.js index 47f8093a6dea..12520778d3f8 100644 --- a/js/ui/grid_core/ui.grid_core.columns_controller.js +++ b/js/ui/grid_core/ui.grid_core.columns_controller.js @@ -21,7 +21,8 @@ import dateLocalization from '../../localization/date'; import messageLocalization from '../../localization/message'; import { when, Deferred } from '../../core/utils/deferred'; import Store from '../../data/abstract_store'; -import { DataSource, normalizeDataSourceOptions } from '../../data/data_source/data_source'; +import { DataSource } from '../../data/data_source/data_source'; +import { normalizeDataSourceOptions } from '../../data/data_source/utils'; import filterUtils from '../shared/filtering'; const USER_STATE_FIELD_NAMES_15_1 = ['filterValues', 'filterType', 'fixed', 'fixedPosition']; diff --git a/js/ui/grid_core/ui.grid_core.data_controller.js b/js/ui/grid_core/ui.grid_core.data_controller.js index 866f84d1f912..b6303bb626b6 100644 --- a/js/ui/grid_core/ui.grid_core.data_controller.js +++ b/js/ui/grid_core/ui.grid_core.data_controller.js @@ -602,11 +602,6 @@ module.exports = { }; each(rowIndices, function(index, rowIndex) { - let oldItem; - let newItem; - let oldNextItem; - let newNextItem; - let strict; let columnIndices; rowIndex += rowIndexCorrection + rowIndexDelta; @@ -614,12 +609,12 @@ module.exports = { if(prevIndex === rowIndex) return; prevIndex = rowIndex; - oldItem = that._items[rowIndex]; - oldNextItem = that._items[rowIndex + 1]; - newItem = items[rowIndex]; - newNextItem = items[rowIndex + 1]; + const oldItem = that._items[rowIndex]; + const oldNextItem = that._items[rowIndex + 1]; + const newItem = items[rowIndex]; + const newNextItem = items[rowIndex + 1]; - strict = equalItems(oldItem, oldNextItem) || equalItems(newItem, newNextItem); + const strict = equalItems(oldItem, oldNextItem) || equalItems(newItem, newNextItem); if(newItem) { newItem.rowIndex = rowIndex; diff --git a/js/ui/grid_core/ui.grid_core.editing.js b/js/ui/grid_core/ui.grid_core.editing.js index 1f48e1a59c3e..10a2d909c110 100644 --- a/js/ui/grid_core/ui.grid_core.editing.js +++ b/js/ui/grid_core/ui.grid_core.editing.js @@ -2598,9 +2598,11 @@ module.exports = { }); }, _rowClick: function(e) { + const isEditForm = $(e.rowElement).hasClass(this.addWidgetPrefix(EDIT_FORM_CLASS)); + e.event[TARGET_COMPONENT_NAME] = this.component; - if(!this._editCellByClick(e, 'click')) { + if(!this._editCellByClick(e, 'click') && !isEditForm) { this.callBase.apply(this, arguments); } }, diff --git a/js/ui/grid_core/ui.grid_core.filter_custom_operations.js b/js/ui/grid_core/ui.grid_core.filter_custom_operations.js index 4de8bd625ee7..4b8075c113c7 100644 --- a/js/ui/grid_core/ui.grid_core.filter_custom_operations.js +++ b/js/ui/grid_core/ui.grid_core.filter_custom_operations.js @@ -3,7 +3,7 @@ import { renderValueText } from '../filter_builder/filter_builder'; const $ = require('../../core/renderer'); const messageLocalization = require('../../localization/message'); const extend = require('../../core/utils/extend').extend; -const DataSourceModule = require('../../data/data_source/data_source'); +const DataSource = require('../../data/data_source/data_source').DataSource; const deferredUtils = require('../../core/utils/deferred'); const utils = require('../filter_builder/utils'); @@ -57,7 +57,7 @@ function baseOperation(grid) { if(!headerFilterDataSource && lookup.items) { dataSourceOptions.store = lookup.items; } - const dataSource = new DataSourceModule.DataSource(dataSourceOptions); + const dataSource = new DataSource(dataSourceOptions); const result = new deferredUtils.Deferred(); dataSource.load().done(items => { diff --git a/js/ui/grid_core/ui.grid_core.focus.js b/js/ui/grid_core/ui.grid_core.focus.js index 8491f832f6a6..9706e7aa1cef 100644 --- a/js/ui/grid_core/ui.grid_core.focus.js +++ b/js/ui/grid_core/ui.grid_core.focus.js @@ -22,10 +22,14 @@ exports.FocusController = core.ViewController.inherit((function() { optionChanged: function(args) { if(args.name === 'focusedRowIndex') { + const focusedRowKey = this.option('focusedRowKey'); this._focusRowByIndex(args.value); + this._triggerFocusedRowChangedIfNeed(focusedRowKey, args.value); args.handled = true; } else if(args.name === 'focusedRowKey') { + const focusedRowIndex = this.option('focusedRowIndex'); this._focusRowByKey(args.value); + this._triggerFocusedRowChangedIfNeed(args.value, focusedRowIndex); args.handled = true; } else if(args.name === 'focusedColumnIndex') { args.handled = true; @@ -38,6 +42,18 @@ exports.FocusController = core.ViewController.inherit((function() { } }, + _triggerFocusedRowChangedIfNeed: function(focusedRowKey, focusedRowIndex) { + const focusedRowIndexByKey = this.getFocusedRowIndexByKey(focusedRowKey); + + if(focusedRowIndex === focusedRowIndexByKey) { + const rowIndex = this._dataController.getRowIndexByKey(focusedRowKey); + if(rowIndex >= 0) { + const $rowElement = $(this.getView('rowsView').getRowElement(rowIndex)); + this.getController('keyboardNavigation')._fireFocusedRowChanged($rowElement, focusedRowIndex); + } + } + }, + _focusRowByIndex: function(index) { if(!this.option('focusedRowEnabled')) { return; @@ -119,13 +135,17 @@ exports.FocusController = core.ViewController.inherit((function() { return; } + const keyboardController = this.getController('keyboardNavigation'); + this.option('focusedRowKey', undefined); - this.getController('keyboardNavigation').setFocusedRowIndex(-1); + keyboardController.setFocusedRowIndex(-1); this.option('focusedRowIndex', -1); this.getController('data').updateItems({ changeType: 'updateFocusedRow', focusedRowKey: undefined }); + + keyboardController._fireFocusedRowChanged(undefined, -1); }, _isValidFocusedRowIndex: function(rowIndex) { @@ -291,22 +311,20 @@ exports.FocusController = core.ViewController.inherit((function() { const that = this; const focusedRowIndex = that._dataController.getRowIndexByKey(change.focusedRowKey); const rowsView = that.getView('rowsView'); - let $focusedRow; let $tableElement; each(rowsView.getTableElements(), function(index, element) { + const isMainTable = index === 0; $tableElement = $(element); + that._clearPreviousFocusedRow($tableElement, focusedRowIndex); - const isMainTable = index === 0; - $focusedRow = that._prepareFocusedRow({ + + that._prepareFocusedRow({ changedItem: change.items[focusedRowIndex], $tableElement: $tableElement, focusedRowIndex: focusedRowIndex, isMainTable: isMainTable }); - if(isMainTable) { - that.getController('keyboardNavigation')._fireFocusedRowChanged($focusedRow); - } }); }, _clearPreviousFocusedRow: function($tableElement, focusedRowIndex) { @@ -488,25 +506,16 @@ module.exports = { }, _fireChanged: function(e) { - let isPartialUpdateWithDeleting; + this.callBase(e); if(this.option('focusedRowEnabled') && this._dataSource) { const isPartialUpdate = e.changeType === 'update' && e.repaintChangesOnly; - - isPartialUpdateWithDeleting = isPartialUpdate && e.changeTypes && e.changeTypes.indexOf('remove') >= 0; - - if(isPartialUpdateWithDeleting) { - this.callBase(e); - } + const isPartialUpdateWithDeleting = isPartialUpdate && e.changeTypes && e.changeTypes.indexOf('remove') >= 0; if(e.changeType === 'refresh' && e.items.length || isPartialUpdateWithDeleting) { this.processUpdateFocusedRow(); } } - - if(!isPartialUpdateWithDeleting) { - this.callBase(e); - } }, processUpdateFocusedRow: function() { const prevPageIndex = this._prevPageIndex; @@ -542,7 +551,9 @@ module.exports = { focusController._focusRowByIndex(); } } else { - this.option('focusedRowIndex', -1); + if(!isVirtualScrolling && this.getRowIndexByKey(focusedRowKey) < 0) { + this.option('focusedRowIndex', -1); + } } } else if(!pagingByRendering) { focusController._focusRowByKeyOrIndex(); diff --git a/js/ui/grid_core/ui.grid_core.grid_view.js b/js/ui/grid_core/ui.grid_core.grid_view.js index 1f5a9148e46d..5f64590a0963 100644 --- a/js/ui/grid_core/ui.grid_core.grid_view.js +++ b/js/ui/grid_core/ui.grid_core.grid_view.js @@ -587,7 +587,7 @@ const ResizingController = modules.ViewController.inherit({ const $rootElement = that.component.$element(); const groupElement = $rootElement.children().get(0); const rootElementHeight = $rootElement && ($rootElement.get(0).clientHeight || $rootElement.height()); - const maxHeight = parseFloat($rootElement.css('maxHeight')); + const maxHeight = parseInt($rootElement.css('maxHeight')); const maxHeightHappened = maxHeight && rootElementHeight >= maxHeight; const height = that.option('height') || $rootElement.get(0).style.height; const editorFactory = that.getController('editorFactory'); diff --git a/js/ui/grid_core/ui.grid_core.header_filter.js b/js/ui/grid_core/ui.grid_core.header_filter.js index 52b3ccc13899..79135dee0867 100644 --- a/js/ui/grid_core/ui.grid_core.header_filter.js +++ b/js/ui/grid_core/ui.grid_core.header_filter.js @@ -10,7 +10,7 @@ import { each } from '../../core/utils/iterator'; import { isDefined, isObject, isFunction } from '../../core/utils/type'; import { getDefaultAlignment } from '../../core/utils/position'; import { extend } from '../../core/utils/extend'; -import { normalizeDataSourceOptions } from '../../data/data_source/data_source'; +import { normalizeDataSourceOptions } from '../../data/data_source/utils'; import dateLocalization from '../../localization/date'; import { isWrapped } from '../../core/utils/variable_wrapper'; import { Deferred } from '../../core/utils/deferred'; diff --git a/js/ui/grid_core/ui.grid_core.keyboard_navigation.js b/js/ui/grid_core/ui.grid_core.keyboard_navigation.js index 5ab8deb4def3..e4d004c0832a 100644 --- a/js/ui/grid_core/ui.grid_core.keyboard_navigation.js +++ b/js/ui/grid_core/ui.grid_core.keyboard_navigation.js @@ -14,7 +14,6 @@ import { isElementInCurrentGrid } from './ui.grid_core.utils'; import browser from '../../core/utils/browser'; import { keyboard } from '../../events/short'; - const ROWS_VIEW_CLASS = 'rowsview'; const EDIT_FORM_CLASS = 'edit-form'; const GROUP_FOOTER_CLASS = 'group-footer'; @@ -126,7 +125,6 @@ const KeyboardNavigationController = core.ViewController.inherit({ _initViewHandlers: function() { const that = this; const pointerDownAction = that.createAction(that._pointerDownHandler); - const pointerUpAction = that.createAction(that._clickHandler); const rowsView = that.getView('rowsView'); rowsView.renderCompleted.add(function(e) { @@ -142,9 +140,6 @@ const KeyboardNavigationController = core.ViewController.inherit({ eventsEngine.off($rowsView, eventUtils.addNamespace(pointerEvents.down, 'dxDataGridKeyboardNavigation'), pointerDownAction); eventsEngine.on($rowsView, eventUtils.addNamespace(pointerEvents.down, 'dxDataGridKeyboardNavigation'), clickSelector, pointerDownAction); - eventsEngine.off($rowsView, eventUtils.addNamespace(pointerEvents.up, 'dxDataGridKeyboardNavigation'), pointerUpAction); - eventsEngine.on($rowsView, eventUtils.addNamespace(pointerEvents.up, 'dxDataGridKeyboardNavigation'), clickSelector, pointerUpAction); - that._initKeyDownHandler($rowsView, e => that._keyDownHandler(e)); that._setRowsViewAttributes($rowsView); @@ -465,7 +460,8 @@ const KeyboardNavigationController = core.ViewController.inherit({ } this._updateFocusedCellPosition($cell); - $cell = this._getNextCellByTabKey($event, direction, elementType); + const nextCellInfo = this._getNextCellByTabKey($event, direction, elementType); + $cell = nextCellInfo.$cell; if(!$cell || this._handleTabKeyOnMasterDetailCell($cell, direction)) { return false; @@ -483,7 +479,7 @@ const KeyboardNavigationController = core.ViewController.inherit({ this._editingController.closeEditCell(); } - if(this._focusCell($cell)) { + if(this._focusCell($cell, !nextCellInfo.isHighlighted)) { if(!this._isRowEditMode() && isEditingAllowed) { this._editingController.editCell(this.getVisibleRowIndex(), this._focusedCellPosition.columnIndex); } else { @@ -517,7 +513,9 @@ const KeyboardNavigationController = core.ViewController.inherit({ } } - $cell = this._getNextCellByTabKey($event, direction, elementType); + const nextCellInfo = this._getNextCellByTabKey($event, direction, elementType); + $cell = nextCellInfo.$cell; + if(!$cell) { return false; } @@ -527,7 +525,7 @@ const KeyboardNavigationController = core.ViewController.inherit({ return false; } - this._focusCell($cell); + this._focusCell($cell, !nextCellInfo.isHighlighted); if(!isEditorCell(this, $cell)) { this._focusInteractiveElement($cell, eventArgs.shift); @@ -541,13 +539,17 @@ const KeyboardNavigationController = core.ViewController.inherit({ const args = $cell && this._fireFocusedCellChanging($event, $cell, true); if(!args || args.cancel) { - return; + return {}; } if(args.$newCellElement) { $cell = args.$newCellElement; } - return $cell; + + return { + $cell, + isHighlighted: args.isHighlighted + }; }, _checkNewLineTransition: function($event, $cell) { const rowIndex = this.getVisibleRowIndex(); @@ -714,7 +716,7 @@ const KeyboardNavigationController = core.ViewController.inherit({ // #endregion Key_Handlers // #region Click_Handler - _clickHandler: function(e) { + _pointerDownHandler: function(e) { const event = e.event; let $target = $(event.currentTarget); const rowsView = this.getView('rowsView'); @@ -722,6 +724,12 @@ const KeyboardNavigationController = core.ViewController.inherit({ const $parent = $target.parent(); const isEditingRow = $parent.hasClass(EDIT_ROW_CLASS); const isInteractiveElement = $(event.target).is(INTERACTIVE_ELEMENTS_SELECTOR); + const isCommandButtonTarget = $(event.target).hasClass('dx-link'); + + if(isCommandButtonTarget) { + this.setCellFocusType(); + return; + } if(this._isEventInCurrentGrid(event) && this._isCellValid($target, !isInteractiveElement)) { $target = this._isInsideEditForm($target) ? $(event.target) : $target; @@ -742,28 +750,14 @@ const KeyboardNavigationController = core.ViewController.inherit({ this._resetFocusedCell(); } }, - _isEventInCurrentGrid: function(event) { - return isElementInCurrentGrid(this, $(event.target)); - }, - - _pointerDownHandler: function(e) { - const $target = $(e.event.target); - const isEditRow = $target.closest('tr').hasClass(EDIT_ROW_CLASS); - - if(!isEditRow) { - const $targetCell = $target.closest('td'); - $targetCell.addClass(CELL_FOCUS_DISABLED_CLASS); - } - }, _clickTargetCellHandler: function(event, $cell) { const columnIndex = this.getView('rowsView').getCellIndex($cell); const column = this._columnsController.getVisibleColumns()[columnIndex]; const isCellEditMode = this._isCellEditMode(); - let args; this.setCellFocusType(); - args = this._fireFocusChangingEvents(event, $cell, true); + const args = this._fireFocusChangingEvents(event, $cell, true); $cell = args.$newCellElement; if(!args.cancel) { @@ -788,7 +782,8 @@ const KeyboardNavigationController = core.ViewController.inherit({ } else { const $target = event && $(event.target); const isInteractiveTarget = $target && $target.not($cell).is(INTERACTIVE_ELEMENTS_SELECTOR); - const isDisabled = !args.isHighlighted || isInteractiveTarget; + const isEditor = !column.command && $cell.hasClass(EDITOR_CELL_CLASS); + const isDisabled = !isEditor && (!args.isHighlighted || isInteractiveTarget); this._focus($cell, isDisabled, isInteractiveTarget); } } else { @@ -886,7 +881,7 @@ const KeyboardNavigationController = core.ViewController.inherit({ }, _focus: function($cell, disableFocus, isInteractiveElement) { - const $row = ($cell && $cell.is('td')) ? $cell.parent() : $cell; + const $row = ($cell && !$cell.hasClass(ROW_CLASS)) ? $cell.closest(`.${ROW_CLASS}`) : $cell; if($row && isNotFocusedRow($row)) { return; @@ -931,7 +926,7 @@ const KeyboardNavigationController = core.ViewController.inherit({ const that = this; setTimeout(function() { let $cell = that._getFocusedCell(); - const isEditing = that._editingController.isEditing(); + const isEditing = that.getController('editing').isEditing(); if($cell && !(that._isMasterDetailCell($cell) && !that._isRowEditMode())) { if(that._hasSkipRow($cell.parent())) { @@ -943,7 +938,8 @@ const KeyboardNavigationController = core.ViewController.inherit({ return; } if($cell.is('td') || $cell.hasClass(that.addWidgetPrefix(EDIT_FORM_ITEM_CLASS))) { - if(that.getController('editorFactory').focus()) { + const isCommandCell = $cell.is(COMMAND_CELL_SELECTOR); + if(!isCommandCell && that.getController('editorFactory').focus()) { that._focus($cell); } else if(that._isCellEditMode()) { that._focus($cell, that._isHiddenFocus); @@ -1009,9 +1005,9 @@ const KeyboardNavigationController = core.ViewController.inherit({ } }, - _focusCell: function($cell) { + _focusCell: function($cell, isDisabled) { if(this._isCellValid($cell)) { - this._focus($cell); + this._focus($cell, isDisabled); return true; } }, @@ -1536,6 +1532,10 @@ const KeyboardNavigationController = core.ViewController.inherit({ }, // #endregion Events + _isEventInCurrentGrid: function(event) { + return isElementInCurrentGrid(this, $(event.target)); + }, + _isRowEditMode: function() { const editMode = this.getController('editing').getEditMode(); return editMode === EDIT_MODE_ROW || editMode === EDIT_MODE_FORM; @@ -1571,8 +1571,7 @@ const KeyboardNavigationController = core.ViewController.inherit({ }, _getRowIndex: function($row) { - const that = this; - const focusedView = that._focusedView; + const focusedView = this._focusedView; let rowIndex = -1; if(focusedView) { @@ -1580,7 +1579,7 @@ const KeyboardNavigationController = core.ViewController.inherit({ } if(rowIndex >= 0) { - rowIndex += that._dataController.getRowIndexOffset(); + rowIndex += this.getController('data').getRowIndexOffset(); } return rowIndex; @@ -1680,7 +1679,7 @@ const KeyboardNavigationController = core.ViewController.inherit({ }, _getCellElementFromTarget: function(target) { - return $(target).closest('.' + ROW_CLASS + '> td'); + return $(target).closest(`.${ROW_CLASS} > td`); }, _getRowsViewElement: function() { @@ -1739,8 +1738,6 @@ module.exports = { */ editOnKeyPress: false } - - }; }, controllers: { @@ -1927,8 +1924,14 @@ module.exports = { this._keyboardNavigationController = this.getController('keyboardNavigation'); }, closeEditCell: function() { - this.getController('keyboardNavigation')._fastEditingStarted = false; - return this.callBase.apply(this, arguments); + const keyboardNavigation = this.getController('keyboardNavigation'); + keyboardNavigation._fastEditingStarted = false; + + const result = this.callBase.apply(this, arguments); + + keyboardNavigation._updateFocus(); + + return result; }, _delayedInputFocus: function() { this._keyboardNavigationController._isNeedScroll = true; diff --git a/js/ui/grid_core/ui.grid_core.selection.js b/js/ui/grid_core/ui.grid_core.selection.js index 98714a2fde40..9b466e380e8e 100644 --- a/js/ui/grid_core/ui.grid_core.selection.js +++ b/js/ui/grid_core/ui.grid_core.selection.js @@ -76,7 +76,16 @@ exports.SelectionController = gridCore.Controller.inherit((function() { }; const selectionCellTemplate = (container, options) => { - const rowsView = options.component.getView('rowsView'); + const component = options.component; + const rowsView = component.getView('rowsView'); + + if(component.option('renderAsync')) { + const selectedRowKeys = component.getSelectedRowKeys(); + + if(selectedRowKeys.indexOf(options.row.key) !== -1) { + options.value = true; + } + } rowsView.renderSelectCheckBoxContainer($(container), options); }; diff --git a/js/ui/grid_core/ui.grid_core.sorting_mixin.js b/js/ui/grid_core/ui.grid_core.sorting_mixin.js index 8d318b80ee3b..c0efb44fa7d8 100644 --- a/js/ui/grid_core/ui.grid_core.sorting_mixin.js +++ b/js/ui/grid_core/ui.grid_core.sorting_mixin.js @@ -24,7 +24,9 @@ module.exports = { rootElement.find('.' + SORT_CLASS).remove(); !$indicatorsContainer.children().length && $indicatorsContainer.remove(); - if((sortingMode === 'single' || sortingMode === 'multiple') && column.allowSorting || isDefined(column.sortOrder)) { + const isSortingAllowed = (sortingMode === 'single' || sortingMode === 'multiple') && column.allowSorting; + + if(!isDefined(column.groupIndex) && (isSortingAllowed || isDefined(column.sortOrder))) { ariaSortState = column.sortOrder === 'asc' ? 'ascending' : 'descending'; $sortIndicator = that.callBase(options) .toggleClass(SORTUP_CLASS, column.sortOrder === 'asc') diff --git a/js/ui/grid_core/ui.grid_core.validating.js b/js/ui/grid_core/ui.grid_core.validating.js index 05ea3d275127..c44d0b1fcdc6 100644 --- a/js/ui/grid_core/ui.grid_core.validating.js +++ b/js/ui/grid_core/ui.grid_core.validating.js @@ -359,7 +359,6 @@ module.exports = { processItems: function(items, changeType) { const that = this; let i; - let itemsCount; const editData = that._editData; const dataController = that.getController('data'); const getIndexByEditData = function(editData, items) { @@ -376,25 +375,25 @@ module.exports = { return index; }; + + items = that.callBase(items, changeType); + const itemsCount = items.length; + const addInValidItem = function(editData) { const data = { key: editData.key }; const index = getIndexByEditData(editData, items); - let rowIndex; if(index >= 0) { return; } editData.rowIndex = editData.rowIndex > itemsCount ? editData.rowIndex % itemsCount : editData.rowIndex; - rowIndex = editData.rowIndex; + const rowIndex = editData.rowIndex; data[INSERT_INDEX] = 1; items.splice(rowIndex, 0, data); }; - items = that.callBase(items, changeType); - itemsCount = items.length; - if(that.getEditMode() === EDIT_MODE_BATCH && changeType !== 'prepend' && changeType !== 'append') { for(i = 0; i < editData.length; i++) { if(editData[i].type && editData[i].pageIndex === that._pageIndex && editData[i].key.pageIndex !== that._pageIndex) { @@ -447,7 +446,12 @@ module.exports = { }, _createInvisibleColumnValidators: function(editData) { - const validatingController = this.getController('validating'); const columnsController = this.getController('columns'); const invisibleColumns = this._getInvisibleColumns(editData).filter((column) => !column.isBand); const groupColumns = columnsController.getGroupColumns().filter((column) => !column.showWhenGrouped && invisibleColumns.indexOf(column) === -1); const invisibleColumnValidators = []; + const validatingController = this.getController('validating'); + const columnsController = this.getController('columns'); + + const invisibleColumns = this._getInvisibleColumns(editData).filter((column) => !column.isBand); + const groupColumns = columnsController.getGroupColumns().filter((column) => !column.showWhenGrouped && invisibleColumns.indexOf(column) === -1); + const invisibleColumnValidators = []; invisibleColumns.push(...groupColumns); diff --git a/js/ui/pivot_grid/data_source.js b/js/ui/pivot_grid/data_source.js index 111132fd04b4..65d4c9821ad0 100644 --- a/js/ui/pivot_grid/data_source.js +++ b/js/ui/pivot_grid/data_source.js @@ -1,4 +1,4 @@ -import { normalizeDataSourceOptions } from '../../data/data_source/data_source'; +import { normalizeDataSourceOptions } from '../../data/data_source/utils'; import Store from '../../data/abstract_store'; import { executeAsync } from '../../core/utils/common'; import { isFunction, isNumeric, isDefined, isString, isPlainObject } from '../../core/utils/type'; diff --git a/js/ui/pivot_grid/ui.pivot_grid.field_chooser_base.js b/js/ui/pivot_grid/ui.pivot_grid.field_chooser_base.js index b57f26f23f9d..eae725a425fb 100644 --- a/js/ui/pivot_grid/ui.pivot_grid.field_chooser_base.js +++ b/js/ui/pivot_grid/ui.pivot_grid.field_chooser_base.js @@ -341,6 +341,14 @@ const FieldChooserBase = Widget.inherit(columnStateMixin).inherit(sortingMixin). } else { const d = new Deferred(); dataSource.getFieldValues(mainGroupField.index, that.option('headerFilter.showRelevantValues'), paginate ? options : undefined).done(function(data) { + const emptyValue = that.option('headerFilter.texts.emptyValue'); + + data.forEach((element) => { + if(!element.text) { + element.text = emptyValue; + } + }); + if(paginate) { d.resolve(data); } else { diff --git a/js/ui/scheduler/appointmentPopup.js b/js/ui/scheduler/appointmentPopup.js index 1c636d509132..8751ffc3bfee 100644 --- a/js/ui/scheduler/appointmentPopup.js +++ b/js/ui/scheduler/appointmentPopup.js @@ -107,7 +107,7 @@ export default class AppointmentPopup { return { height: 'auto', maxHeight: '100%', - onHiding: () => { this._appointmentForm.resetValues(); this.scheduler.focus(); }, + onHiding: () => { this.scheduler.focus(); }, contentTemplate: () => this._createPopupContent(), defaultOptionsRules: [ { diff --git a/js/ui/scheduler/rendering_strategies/ui.scheduler.appointments.strategy.base.js b/js/ui/scheduler/rendering_strategies/ui.scheduler.appointments.strategy.base.js index 2c63e3067a72..690e3e9ef1eb 100644 --- a/js/ui/scheduler/rendering_strategies/ui.scheduler.appointments.strategy.base.js +++ b/js/ui/scheduler/rendering_strategies/ui.scheduler.appointments.strategy.base.js @@ -7,6 +7,8 @@ import { isNumeric } from '../../../core/utils/type'; import typeUtils from '../../../core/utils/type'; import themes from '../../themes'; +import utils from '../utils'; + const toMs = dateUtils.dateToMilliseconds; const APPOINTMENT_MIN_SIZE = 2; @@ -534,7 +536,7 @@ class BaseRenderingStrategy { } _adjustDurationByDaylightDiff(duration, startDate, endDate) { - const daylightDiff = this.instance.fire('getDaylightOffset', startDate, endDate); + const daylightDiff = utils.getDaylightOffset(startDate, endDate); return this._needAdjustDuration(daylightDiff) ? this._calculateDurationByDaylightDiff(duration, daylightDiff) : duration; } diff --git a/js/ui/scheduler/rendering_strategies/ui.scheduler.appointments.strategy.horizontal_month_line.js b/js/ui/scheduler/rendering_strategies/ui.scheduler.appointments.strategy.horizontal_month_line.js index d5ac8d65de31..14c7c30bb912 100644 --- a/js/ui/scheduler/rendering_strategies/ui.scheduler.appointments.strategy.horizontal_month_line.js +++ b/js/ui/scheduler/rendering_strategies/ui.scheduler.appointments.strategy.horizontal_month_line.js @@ -5,6 +5,7 @@ import query from '../../../data/query'; const HOURS_IN_DAY = 24; const MINUTES_IN_HOUR = 60; const MILLISECONDS_IN_MINUTE = 60000; +const ZERO_APPOINTMENT_DURATION_IN_DAYS = 1; class HorizontalMonthLineRenderingStrategy extends HorizontalAppointmentsStrategy { calculateAppointmentWidth(appointment, position, isRecurring) { @@ -12,15 +13,15 @@ class HorizontalMonthLineRenderingStrategy extends HorizontalAppointmentsStrateg const endDate = new Date(this.endDate(appointment, position, isRecurring, true)); const cellWidth = this.getDefaultCellWidth() || this.getAppointmentMinSize(); - const duration = this._getDurationInHour(startDate, endDate) / HOURS_IN_DAY; + const duration = this._getDurationInDays(startDate, endDate); const width = this.cropAppointmentWidth(Math.ceil(duration) * cellWidth, cellWidth); return width; } - _getDurationInHour(startDate, endDate) { + _getDurationInDays(startDate, endDate) { const adjustedDuration = this._adjustDurationByDaylightDiff(endDate.getTime() - startDate.getTime(), startDate, endDate); - return adjustedDuration / dateUtils.dateToMilliseconds('hour'); + return (adjustedDuration / dateUtils.dateToMilliseconds('day')) || ZERO_APPOINTMENT_DURATION_IN_DAYS; } getDeltaTime(args, initialSize) { diff --git a/js/ui/scheduler/ui.scheduler.appointment_form.js b/js/ui/scheduler/ui.scheduler.appointment_form.js index ebdc9de135bc..8996d14815bf 100644 --- a/js/ui/scheduler/ui.scheduler.appointment_form.js +++ b/js/ui/scheduler/ui.scheduler.appointment_form.js @@ -30,13 +30,15 @@ const SchedulerAppointmentForm = { }, _getAllDayStartDate: function(startDate) { - return startDate.setHours(0, 0, 0, 0); + return new Date(new Date(startDate).setHours(0, 0, 0, 0)); }, _getAllDayEndDate: function(startDate) { - const endDate = new Date(startDate); - endDate.setDate(startDate.getDate() + 1); - return endDate; + return new Date(new Date(startDate).setDate(startDate.getDate() + 1)); + }, + + _getStartDateWithStartHour: function(startDate, startDayHour) { + return new Date(new Date(startDate).setHours(startDayHour)); }, _updateLabelLocation: function(formWidth) { @@ -64,6 +66,19 @@ const SchedulerAppointmentForm = { return this._appointmentForm; }, + _dateBoxValueChanged: function(args, dateExpr, isNeedCorrect) { + this._validateAppointmentFormDate(args.component, args.value, args.previousValue); + + const value = dateSerialization.deserializeDate(args.value); + const previousValue = dateSerialization.deserializeDate(args.previousValue); + const dateEditor = this._appointmentForm.getEditor(dateExpr); + const dateValue = dateSerialization.deserializeDate(dateEditor.option('value')); + if(!this._appointmentForm._lockDateShiftFlag && dateValue && value && isNeedCorrect(dateValue, value)) { + const duration = previousValue ? dateValue.getTime() - previousValue.getTime() : 0; + dateEditor.option('value', new Date(value.getTime() + duration)); + } + }, + prepareAppointmentFormEditors: function(dataExprs, schedulerInst) { const that = this; @@ -91,17 +106,7 @@ const SchedulerAppointmentForm = { firstDayOfWeek: schedulerInst.option('firstDayOfWeek') }, onValueChanged: function(args) { - that._validateAppointmentFormDate(args.component, args.value, args.previousValue); - - const value = dateSerialization.deserializeDate(args.value); - const previousValue = dateSerialization.deserializeDate(args.previousValue); - const endDateEditor = that._appointmentForm.getEditor(dataExprs.endDateExpr); - const endValue = dateSerialization.deserializeDate(endDateEditor.option('value')); - if(!that._appointmentForm._lockDateShiftFlag && typeUtils.isDefined(value) && typeUtils.isDefined(endValue) - && !!endValue && endValue < value) { - const duration = endValue.getTime() - previousValue.getTime(); - endDateEditor.option('value', new Date(value.getTime() + duration)); - } + that._dateBoxValueChanged(args, dataExprs.endDateExpr, (endValue, startValue) => { return endValue < startValue; }); } } }, @@ -133,16 +138,7 @@ const SchedulerAppointmentForm = { firstDayOfWeek: schedulerInst.option('firstDayOfWeek') }, onValueChanged: function(args) { - that._validateAppointmentFormDate(args.component, args.value, args.previousValue); - - const value = dateSerialization.deserializeDate(args.value); - const previousValue = dateSerialization.deserializeDate(args.previousValue); - const startDateEditor = that._appointmentForm.getEditor(dataExprs.startDateExpr); - const startValue = dateSerialization.deserializeDate(startDateEditor.option('value')); - if(!that._appointmentForm._lockDateShiftFlag && !!value && startValue > value) { - const duration = previousValue ? previousValue.getTime() - startValue.getTime() : 0; - startDateEditor.option('value', new Date(value.getTime() - duration)); - } + that._dateBoxValueChanged(args, dataExprs.startDateExpr, (startValue, endValue) => { return endValue < startValue; }); } } }, @@ -171,26 +167,22 @@ const SchedulerAppointmentForm = { const value = args.value; const startDateEditor = that._appointmentForm.getEditor(dataExprs.startDateExpr); const endDateEditor = that._appointmentForm.getEditor(dataExprs.endDateExpr); + const startDate = dateSerialization.deserializeDate(startDateEditor.option('value')); - if(startDateEditor && endDateEditor) { - startDateEditor.option('type', value ? 'date' : 'datetime'); - endDateEditor.option('type', value ? 'date' : 'datetime'); - - if(!startDateEditor.option('value')) { - return; - } - - const startDate = dateSerialization.deserializeDate(startDateEditor.option('value')); - + if(!that._appointmentForm._lockDateShiftFlag && startDate) { if(value) { - startDateEditor.option('value', that._getAllDayStartDate(startDate)); - endDateEditor.option('value', that._getAllDayEndDate(startDate)); + const allDayStartDate = that._getAllDayStartDate(startDate); + startDateEditor.option('value', allDayStartDate); + endDateEditor.option('value', that._getAllDayEndDate(allDayStartDate)); } else { - startDate.setHours(schedulerInst.option('startDayHour')); - startDateEditor.option('value', startDate); - endDateEditor.option('value', schedulerInst._workSpace.calculateEndDate(dateSerialization.deserializeDate(startDateEditor.option('value')))); + const startDateWithStartHour = that._getStartDateWithStartHour(startDate, schedulerInst.option('startDayHour')); + const endDate = schedulerInst._workSpace.calculateEndDate(startDateWithStartHour); + startDateEditor.option('value', startDateWithStartHour); + endDateEditor.option('value', endDate); } } + startDateEditor.option('type', value ? 'date' : 'datetime'); + endDateEditor.option('type', value ? 'date' : 'datetime'); } } }, diff --git a/js/ui/scheduler/ui.scheduler.appointments.js b/js/ui/scheduler/ui.scheduler.appointments.js index 51173a2ab6ea..2d820082ef4c 100644 --- a/js/ui/scheduler/ui.scheduler.appointments.js +++ b/js/ui/scheduler/ui.scheduler.appointments.js @@ -108,15 +108,9 @@ const SchedulerAppointments = CollectionWidget.inherit({ }, _focusInHandler: function(e) { - clearTimeout(this._appointmentFocusedTimeout); this.callBase.apply(this, arguments); this._$currentAppointment = $(e.target); this.option('focusedElement', getPublicElement($(e.target))); - const that = this; - - this._appointmentFocusedTimeout = setTimeout(function() { - that.notifyObserver('appointmentFocused'); - }); }, _focusOutHandler: function() { @@ -719,7 +713,7 @@ const SchedulerAppointments = CollectionWidget.inherit({ }; } - appointmentSetting.targetedAppointmentData = this.invoke('getTargetedAppointmentData', appointmentData, $appointment, true); + appointmentSetting.targetedAppointmentData = this.invoke('getTargetedAppointmentData', appointmentData, $appointment); this._virtualAppointments[virtualGroupIndex].items.settings.push(appointmentSetting); this._virtualAppointments[virtualGroupIndex].items.data.push(appointmentData); @@ -785,6 +779,7 @@ const SchedulerAppointments = CollectionWidget.inherit({ }, _processRecurrenceAppointment: function(appointment, index, skipLongAppointments) { + // NOTE: this method is actual only for agenda const recurrenceRule = this.invoke('getField', 'recurrenceRule', appointment); const result = { parts: [], diff --git a/js/ui/scheduler/ui.scheduler.js b/js/ui/scheduler/ui.scheduler.js index a0bb73df96f8..2221addfe98e 100644 --- a/js/ui/scheduler/ui.scheduler.js +++ b/js/ui/scheduler/ui.scheduler.js @@ -1063,6 +1063,35 @@ const Scheduler = Widget.inherit({ return this._calculateTimezoneByValue(this.option('timeZone'), date); }, + _getDaylightOffsetByCustomTimezone: function(startDate, endDate) { + return this._getTimezoneOffsetByOption(startDate) - this._getTimezoneOffsetByOption(endDate); + }, + + _getDaylightOffsetByAppointmentTimezone: function(startDate, endDate, appointmentTimezone) { + return this._calculateTimezoneByValue(appointmentTimezone, startDate) - this._calculateTimezoneByValue(appointmentTimezone, endDate); + }, + + _getCorrectedDateByDaylightOffsets: function(originalStartDate, date, startDateTimezone) { + const daylightOffsetByOption = this._getDaylightOffsetByCustomTimezone(originalStartDate, date); + const daylightOffsetByAppointment = this._getDaylightOffsetByAppointmentTimezone(originalStartDate, date, startDateTimezone); + const diff = daylightOffsetByOption - daylightOffsetByAppointment; + + return new Date(date.getTime() - diff * toMs('hour')); + }, + + getCorrectedDatesByDaylightOffsets: function(originalStartDate, dates, appointmentData) { + const startDateTimeZone = this.fire('getField', 'startDateTimeZone', appointmentData); + const needCheckTimezoneOffset = typeUtils.isDefined(startDateTimeZone) && typeUtils.isDefined(this._getTimezoneOffsetByOption(originalStartDate)); + + if(needCheckTimezoneOffset) { + dates = dates.map((date) => { + return this._getCorrectedDateByDaylightOffsets(originalStartDate, date, startDateTimeZone); + }); + } + + return dates; + }, + _calculateTimezoneByValue: function(timezone, date) { let result = timezone; diff --git a/js/ui/scheduler/ui.scheduler.resource_manager.js b/js/ui/scheduler/ui.scheduler.resource_manager.js index 21d98e81aad0..a7f085b2295a 100644 --- a/js/ui/scheduler/ui.scheduler.resource_manager.js +++ b/js/ui/scheduler/ui.scheduler.resource_manager.js @@ -7,8 +7,9 @@ import { extend } from '../../core/utils/extend'; import { inArray } from '../../core/utils/array'; import query from '../../data/query'; import dataCoreUtils from '../../core/utils/data'; -import DataSourceModule from '../../data/data_source/data_source'; +import { DataSource } from '../../data/data_source/data_source'; import { when, Deferred } from '../../core/utils/deferred'; +import { normalizeDataSourceOptions } from '../../data/data_source/utils'; const getValueExpr = resource => resource.valueExpr || 'id'; const getDisplayExpr = resource => resource.displayExpr || 'text'; @@ -20,11 +21,11 @@ export default class ResourceManager { } _wrapDataSource(dataSource) { - if(dataSource instanceof DataSourceModule.DataSource) { + if(dataSource instanceof DataSource) { return dataSource; } else { - return new DataSourceModule.DataSource({ - store: DataSourceModule.normalizeDataSourceOptions(dataSource).store, + return new DataSource({ + store: normalizeDataSourceOptions(dataSource).store, pageSize: 0 }); } diff --git a/js/ui/scheduler/ui.scheduler.subscribes.js b/js/ui/scheduler/ui.scheduler.subscribes.js index 36d30630ec19..e9baa4a36454 100644 --- a/js/ui/scheduler/ui.scheduler.subscribes.js +++ b/js/ui/scheduler/ui.scheduler.subscribes.js @@ -61,7 +61,9 @@ const subscribes = { dates.push(startDate); initialDates = dates; } else { + dates = this.getCorrectedDatesByDaylightOffsets(originalStartDate, dates, appointmentData); initialDates = dates; + dates = dates.map((date) => { return dateUtils.roundDateByStartDayHour(date, this._getCurrentViewOption('startDayHour')); }); @@ -231,10 +233,6 @@ const subscribes = { appointmentTakesSeveralDays: function(appointment) { return this._appointmentModel.appointmentTakesSeveralDays(appointment); }, - // NOTE: T312051, remove after fix scrollable bug T324196 - appointmentFocused: function() { - this._workSpace.restoreScrollTop(); - }, getTextAndFormatDate(data, currentData, format) { const fields = ['startDate', 'endDate', 'startDateTimeZone', 'endDateTimeZone', 'allDay', 'text']; @@ -745,10 +743,6 @@ const subscribes = { }; }, - getDaylightOffset: function(startDate, endDate) { - return startDate.getTimezoneOffset() - endDate.getTimezoneOffset(); - }, - getTimezonesDisplayName: function() { return SchedulerTimezones.getTimezonesDisplayName(); }, @@ -765,7 +759,7 @@ const subscribes = { return SchedulerTimezones.getTimezonesIdsByDisplayName(displayName); }, - getTargetedAppointmentData: function(appointmentData, appointmentElement, skipTimezoneConvert) { + getTargetedAppointmentData: function(appointmentData, appointmentElement) { const $appointmentElement = $(appointmentElement); const appointmentIndex = $appointmentElement.data(this._appointments._itemIndexKey()); @@ -778,7 +772,7 @@ const subscribes = { extend(true, result, appointmentData, recurringData); - if(this._isAppointmentRecurrence(appointmentData) && !skipTimezoneConvert) { + if(this._isAppointmentRecurrence(appointmentData)) { this._convertDatesByTimezoneBack(false, result); // TODO: temporary solution fox fix T848058, more information in the ticket } diff --git a/js/ui/scheduler/utils.js b/js/ui/scheduler/utils.js index df009675a3c3..c9483d86922f 100644 --- a/js/ui/scheduler/utils.js +++ b/js/ui/scheduler/utils.js @@ -3,17 +3,24 @@ import dateUtils from '../../core/utils/date'; const toMs = dateUtils.dateToMilliseconds; const getTimezoneOffsetChangeInMinutes = (startDate, endDate, updatedStartDate, updatedEndDate) => { - return new Date(endDate).getTimezoneOffset() - - new Date(startDate).getTimezoneOffset() + - new Date(updatedStartDate).getTimezoneOffset() - - new Date(updatedEndDate).getTimezoneOffset(); + return getDaylightOffset(updatedStartDate, updatedEndDate) - getDaylightOffset(startDate, endDate); }; const getTimezoneOffsetChangeInMs = (startDate, endDate, updatedStartDate, updatedEndDate) => { return getTimezoneOffsetChangeInMinutes(startDate, endDate, updatedStartDate, updatedEndDate) * toMs('minute'); }; +const getDaylightOffset = (startDate, endDate) => { + return new Date(startDate).getTimezoneOffset() - new Date(endDate).getTimezoneOffset(); +}; + +const getDaylightOffsetInMs = (startDate, endDate) => { + return getDaylightOffset(startDate, endDate) * toMs('minute'); +}; + const utils = { + getDaylightOffset: getDaylightOffset, + getDaylightOffsetInMs: getDaylightOffsetInMs, getTimezoneOffsetChangeInMinutes: getTimezoneOffsetChangeInMinutes, getTimezoneOffsetChangeInMs: getTimezoneOffsetChangeInMs }; diff --git a/js/ui/scheduler/workspaces/ui.scheduler.timeline_work_week.js b/js/ui/scheduler/workspaces/ui.scheduler.timeline_work_week.js index 46c1a6e2e09a..abfcf652c4ba 100644 --- a/js/ui/scheduler/workspaces/ui.scheduler.timeline_work_week.js +++ b/js/ui/scheduler/workspaces/ui.scheduler.timeline_work_week.js @@ -1,10 +1,11 @@ const registerComponent = require('../../../core/component_registrator'); const SchedulerTimelineWeek = require('./ui.scheduler.timeline_week'); const dateUtils = require('../../../core/utils/date'); +const workWeekUtils = require('./utils.work_week'); const toMs = dateUtils.dateToMilliseconds; const TIMELINE_CLASS = 'dx-scheduler-timeline-work-week'; -const MONDAY_INDEX = 1; +const LAST_DAY_WEEK_INDEX = 5; const SchedulerTimelineWorkWeek = SchedulerTimelineWeek.inherit({ _getElementClass: function() { @@ -16,35 +17,28 @@ const SchedulerTimelineWorkWeek = SchedulerTimelineWeek.inherit({ }, _firstDayOfWeek: function() { - return this.option('firstDayOfWeek') || MONDAY_INDEX; + return workWeekUtils.getFirstDayOfWeek(this.option('firstDayOfWeek')); }, + _isSkippedData: workWeekUtils.isDataOnWeekend, + _incrementDate: function(date) { const day = date.getDay(); - if(day === 5) { + if(day === LAST_DAY_WEEK_INDEX) { date.setDate(date.getDate() + 2); } this.callBase(date); }, - _getOffsetByCount: function(cellIndex, rowIndex) { + _getOffsetByCount: function(cellIndex) { const weekendCount = Math.floor(cellIndex / (5 * this._getCellCountInDay())); - if(weekendCount > 0) { - return toMs('day') * weekendCount * 2; - } else { - return 0; - } + return toMs('day') * weekendCount * 2; }, - _getWeekendsCount: function(days) { - return 2 * Math.floor(days / 7); - }, + _getWeekendsCount: workWeekUtils.getWeekendsCount, _setFirstViewDate: function() { - this._firstViewDate = dateUtils.getFirstWeekDate(this.option('currentDate'), this._firstDayOfWeek()); - - this._firstViewDate = dateUtils.normalizeDateByWeek(this._firstViewDate, this.option('currentDate')); - + this._firstViewDate = workWeekUtils.getFirstViewDate(this.option('currentDate'), this._firstDayOfWeek()); this._setStartDayHour(this._firstViewDate); } }); diff --git a/js/ui/scheduler/workspaces/ui.scheduler.work_space.js b/js/ui/scheduler/workspaces/ui.scheduler.work_space.js index 31498a6a7bca..1b0a06ffe45c 100644 --- a/js/ui/scheduler/workspaces/ui.scheduler.work_space.js +++ b/js/ui/scheduler/workspaces/ui.scheduler.work_space.js @@ -29,6 +29,7 @@ const tableCreator = require('../ui.scheduler.table_creator'); const VerticalShader = require('../shaders/ui.scheduler.current_time_shader.vertical'); const AppointmentDragBehavior = require('../appointmentDragBehavior'); const FIXED_CONTAINER_CLASS = require('../constants').FIXED_CONTAINER_CLASS; +const utils = require('../utils'); const COMPONENT_CLASS = 'dx-scheduler-work-space'; const GROUPED_WORKSPACE_CLASS = 'dx-scheduler-work-space-grouped'; @@ -2166,10 +2167,16 @@ const SchedulerWorkSpace = Widget.inherit({ : 0; }, + _isSkippedData: function() { return false; }, + getCoordinatesByDateInGroup: function(date, appointmentResources, inAllDayRow) { const indexes = this._getGroupIndexes(appointmentResources); const result = []; + if(this._isSkippedData(date)) { + return result; + } + if(indexes.length) { for(let i = 0; i < indexes.length; i++) { result.push(this.getCoordinatesByDate(date, indexes[i], inAllDayRow)); @@ -2338,7 +2345,7 @@ const SchedulerWorkSpace = Widget.inherit({ }, _adjustEndViewDateByDaylightDiff: function(startDate, endDate) { - const daylightDiff = this.invoke('getDaylightOffset', startDate, endDate) * toMs('minute') || 0; + const daylightDiff = utils.getDaylightOffsetInMs(startDate, endDate); const endDateOfLastViewCell = new Date(endDate.getTime() - daylightDiff); @@ -2475,11 +2482,6 @@ const SchedulerWorkSpace = Widget.inherit({ return result; }, - // NOTE: T312051, remove after fix scrollable bug T324196 - restoreScrollTop: function() { - this.$element().scrollTop(0); - }, - scrollToTime: function(hours, minutes, date) { const min = this.getStartViewDate(); const max = this.getEndViewDate(); diff --git a/js/ui/scheduler/workspaces/ui.scheduler.work_space_work_week.js b/js/ui/scheduler/workspaces/ui.scheduler.work_space_work_week.js index 0eb250d0ffde..bcc381172813 100644 --- a/js/ui/scheduler/workspaces/ui.scheduler.work_space_work_week.js +++ b/js/ui/scheduler/workspaces/ui.scheduler.work_space_work_week.js @@ -1,8 +1,8 @@ const registerComponent = require('../../../core/component_registrator'); const dateUtils = require('../../../core/utils/date'); +const workWeekUtils = require('./utils.work_week'); const toMs = dateUtils.dateToMilliseconds; const SchedulerWorkSpaceWeek = require('./ui.scheduler.work_space_week'); -const dateLocalization = require('../../../localization/date'); const WORK_WEEK_CLASS = 'dx-scheduler-work-space-work-week'; @@ -21,9 +21,11 @@ const SchedulerWorkSpaceWorkWeek = SchedulerWorkSpaceWeek.inherit({ }, _firstDayOfWeek: function() { - return this.option('firstDayOfWeek') || 1; + return workWeekUtils.getFirstDayOfWeek(this.option('firstDayOfWeek')); }, + _isSkippedData: workWeekUtils.isDataOnWeekend, + _getDateByIndex: function(headerIndex) { const resultDate = new Date(this._firstViewDate); @@ -48,15 +50,10 @@ const SchedulerWorkSpaceWorkWeek = SchedulerWorkSpaceWeek.inherit({ this.callBase(); }, - _getWeekendsCount: function(days) { - return 2 * Math.floor(days / 7); - }, + _getWeekendsCount: workWeekUtils.getWeekendsCount, _setFirstViewDate: function() { - this._firstViewDate = dateUtils.getFirstWeekDate(this._getViewStartByOptions(), this._firstDayOfWeek() || dateLocalization.firstDayOfWeekIndex()); - - this._firstViewDate = dateUtils.normalizeDateByWeek(this._firstViewDate, this._getViewStartByOptions()); - + this._firstViewDate = workWeekUtils.getFirstViewDate(this._getViewStartByOptions(), this._firstDayOfWeek()); this._setStartDayHour(this._firstViewDate); }, diff --git a/js/ui/scheduler/workspaces/utils.work_week.js b/js/ui/scheduler/workspaces/utils.work_week.js new file mode 100644 index 000000000000..d10d373c3cab --- /dev/null +++ b/js/ui/scheduler/workspaces/utils.work_week.js @@ -0,0 +1,23 @@ +const dateUtils = require('../../../core/utils/date'); +const MONDAY_INDEX = 1; +const SATURDAY_INDEX = 6; +const SUNDAY_INDEX = 0; + +export const isDataOnWeekend = (date) => { + const day = date.getDay(); + return day === SATURDAY_INDEX || day === SUNDAY_INDEX; +}; + +export const getFirstDayOfWeek = (firstDayOfWeekOption) => { + return firstDayOfWeekOption || MONDAY_INDEX; +}; + +export const getWeekendsCount = (days) => { + return 2 * Math.floor(days / 7); +}; + +export const getFirstViewDate = (viewStart, firstDayOfWeek) => { + const firstViewDate = dateUtils.getFirstWeekDate(viewStart, firstDayOfWeek); + return dateUtils.normalizeDateByWeek(firstViewDate, viewStart); +}; + diff --git a/js/ui/scroll_view/ui.scroll_view.native.pull_down.js b/js/ui/scroll_view/ui.scroll_view.native.pull_down.js index 18a15d538877..4a52bf7a22a1 100644 --- a/js/ui/scroll_view/ui.scroll_view.native.pull_down.js +++ b/js/ui/scroll_view/ui.scroll_view.native.pull_down.js @@ -173,11 +173,7 @@ const PullDownNativeScrollViewStrategy = NativeStrategy.inherit({ }, _isReachBottom: function() { - if(browser.msie) { - return this._reachBottomEnabled && this._location - (this._scrollOffset + this._bottomPocketSize) <= 0.1; - } else { - return this._reachBottomEnabled && this._location <= this._scrollOffset + this._bottomPocketSize; - } + return this._reachBottomEnabled && this._location - (this._scrollOffset + this._bottomPocketSize) <= 0.5; // T858013 }, _reachBottom: function() { diff --git a/js/ui/scroll_view/ui.scroll_view.simulated.js b/js/ui/scroll_view/ui.scroll_view.simulated.js index 7ba3129c3c48..7dcb84d8a12f 100644 --- a/js/ui/scroll_view/ui.scroll_view.simulated.js +++ b/js/ui/scroll_view/ui.scroll_view.simulated.js @@ -98,7 +98,7 @@ const ScrollViewScroller = simulatedStrategy.Scroller.inherit({ }, _isReachBottom: function() { - return this._reachBottomEnabled && this._location <= this._bottomBound; + return this._reachBottomEnabled && (this._location - this._bottomBound <= 0.5); // T858013 }, _scrollComplete: function() { diff --git a/js/ui/shared/ui.editor_factory_mixin.js b/js/ui/shared/ui.editor_factory_mixin.js index 91c29e127444..bb5940ae5767 100644 --- a/js/ui/shared/ui.editor_factory_mixin.js +++ b/js/ui/shared/ui.editor_factory_mixin.js @@ -8,7 +8,7 @@ const browser = require('../../core/utils/browser'); const extend = require('../../core/utils/extend').extend; const devices = require('../../core/devices'); const getPublicElement = require('../../core/utils/dom').getPublicElement; -const normalizeDataSourceOptions = require('../../data/data_source/data_source').normalizeDataSourceOptions; +const normalizeDataSourceOptions = require('../../data/data_source/utils').normalizeDataSourceOptions; const normalizeKeyName = require('../../events/utils').normalizeKeyName; require('../text_box'); @@ -89,7 +89,6 @@ const EditorFactoryMixin = (function() { }, displayFormat: options.format, type: options.dataType, - formatWidthCalculator: null, dateSerializationFormat: null, width: options.parentType === 'filterBuilder' ? undefined : 'auto' }, options); diff --git a/js/ui/sortable.js b/js/ui/sortable.js index 3071217411e2..96414f4e281f 100644 --- a/js/ui/sortable.js +++ b/js/ui/sortable.js @@ -254,9 +254,10 @@ const Sortable = Draggable.inherit({ }, _isValidPoint: function(visibleIndex, draggableVisibleIndex, dropInsideItem) { + const allowDropInsideItem = this.option('allowDropInsideItem'); const allowReordering = dropInsideItem || this._allowReordering(); - if(!allowReordering && visibleIndex !== 0) { + if(!allowReordering && (visibleIndex !== 0 || !allowDropInsideItem)) { return false; } diff --git a/js/ui/switch.js b/js/ui/switch.js index fc6e7bfda3c7..088a285ff16c 100644 --- a/js/ui/switch.js +++ b/js/ui/switch.js @@ -373,6 +373,7 @@ const Switch = Editor.inherit({ complete: function() { that._swiping = false; const pos = that.option('value') + offsetDirection * e.event.targetOffset; + that._saveValueChangeEvent(e.event); that.option('value', Boolean(pos)); that._feedbackDeferred.resolve(); that._toggleActiveState(that.$element(), false); diff --git a/js/ui/tab_panel.js b/js/ui/tab_panel.js index 4bb8ddd09e07..6eb4314fed71 100644 --- a/js/ui/tab_panel.js +++ b/js/ui/tab_panel.js @@ -310,7 +310,17 @@ const TabPanel = MultiView.inherit({ this._tabs.repaint(); break; case 'selectedIndex': - case 'selectedItem': + case 'selectedItem': { + this._setTabsOption(fullName, value); + this.callBase(args); + + if(this.option('focusStateEnabled') === true) { + const selectedIndex = this.option('selectedIndex'); + const selectedTabContent = this._itemElements().eq(selectedIndex); + this.option('focusedElement', getPublicElement(selectedTabContent)); + } + break; + } case 'itemHoldTimeout': case 'focusStateEnabled': case 'hoverStateEnabled': diff --git a/js/ui/tag_box.js b/js/ui/tag_box.js index e32e3d39cf89..12725b0d0014 100644 --- a/js/ui/tag_box.js +++ b/js/ui/tag_box.js @@ -17,7 +17,7 @@ import messageLocalization from '../localization/message'; import { addNamespace, normalizeKeyName } from '../events/utils'; import { name as clickEvent } from '../events/click'; import caret from './text_box/utils.caret'; -import { normalizeLoadResult } from '../data/data_source/data_source'; +import { normalizeLoadResult } from '../data/data_source/utils'; import SelectBox from './select_box'; import { BindableTemplate } from '../core/templates/bindable_template'; diff --git a/js/ui/tooltip/tooltip.js b/js/ui/tooltip/tooltip.js index e6bd944e5950..cb376927acf0 100644 --- a/js/ui/tooltip/tooltip.js +++ b/js/ui/tooltip/tooltip.js @@ -5,6 +5,7 @@ const extend = require('../../core/utils/extend').extend; const Popover = require('../popover'); const TOOLTIP_CLASS = 'dx-tooltip'; const TOOLTIP_WRAPPER_CLASS = 'dx-tooltip-wrapper'; +const isWindow = require('../../core/utils/type').isWindow; const Tooltip = Popover.inherit({ _getDefaultOptions: function() { @@ -73,7 +74,9 @@ const Tooltip = Popover.inherit({ const $target = $(this.option('target')); const label = showing ? this._contentId : undefined; - this.setAria('describedby', label, $target); + if(!isWindow($target.get(0))) { + this.setAria('describedby', label, $target); + } } }); diff --git a/js/ui/tree_list/ui.tree_list.data_source_adapter.js b/js/ui/tree_list/ui.tree_list.data_source_adapter.js index 73f5eedf8dda..48492fd7bf23 100644 --- a/js/ui/tree_list/ui.tree_list.data_source_adapter.js +++ b/js/ui/tree_list/ui.tree_list.data_source_adapter.js @@ -595,9 +595,9 @@ let DataSourceAdapterTreeList = DataSourceAdapter.inherit((function() { if(options.collapseVisibleNodes || expandedRowKeys.length) { this.option('expandedRowKeys', expandedRowKeys); } + this._isReload = false; this.executeAction('onNodesInitialized', { root: this._rootNode }); this._isNodesInitializing = false; - this._isReload = false; } data = this._createVisibleItemsByNodes(this._rootNode.children, options); diff --git a/js/ui/tree_list/ui.tree_list.editing.js b/js/ui/tree_list/ui.tree_list.editing.js index 3daf918058fd..bccb5f15acb7 100644 --- a/js/ui/tree_list/ui.tree_list.editing.js +++ b/js/ui/tree_list/ui.tree_list.editing.js @@ -124,7 +124,7 @@ const EditingController = editingModule.controllers.editing.inherit((function() parentIdSetter(options.data, parentKey); - this.callBase.apply(this, arguments); + return this.callBase.apply(this, arguments); }, allowAdding: function(options) { diff --git a/js/ui/tree_view.d.ts b/js/ui/tree_view.d.ts index f88fd53c4ef2..e5c3e014de39 100644 --- a/js/ui/tree_view.d.ts +++ b/js/ui/tree_view.d.ts @@ -241,7 +241,7 @@ export interface dxTreeViewOptions extends HierarchicalCollectionWidgetOptions= canvas.left && x <= canvas.right && y >= canvas.top && y <= canvas.bottom); -} - function correctLegendHoverMode(mode) { if(LEGEND_HOVER_MODES.indexOf(mode) > -1) { return mode; @@ -654,10 +651,10 @@ extend(PieTracker.prototype, baseTrackerPrototype, { const that = this; const item = that._legend.getItemByCoord(x, y); - that._resetHoveredArgument(); - if(item) { + if(item && that._hoveredArgument !== item.argument) { + that._resetHoveredArgument(); that._hoverArgument(item.argument, item.argumentIndex); - } else { + } else if(!item) { that.clearHover(); } }, diff --git a/js/viz/components/legend.js b/js/viz/components/legend.js index 0ad30f9253d4..a9cfa712b032 100644 --- a/js/viz/components/legend.js +++ b/js/viz/components/legend.js @@ -977,7 +977,7 @@ extend(legendPrototype, { let titleY = titleBox.y + titleOptions.margin.top; let titleX = 0; - if(titleOptions.verticalAlignment === BOTTOM) { + if(titleOptions.verticalAlignment === BOTTOM && that._markersGroup) { titleY += that._markersGroup.getBBox().height; } diff --git a/js/viz/core/utils.js b/js/viz/core/utils.js index 13ea1702a4e6..bc088b01d2a6 100644 --- a/js/viz/core/utils.js +++ b/js/viz/core/utils.js @@ -616,6 +616,10 @@ function rangesAreEqual(range, rangeFromOptions) { } } +function pointInCanvas(canvas, x, y) { + return (x >= canvas.left && x <= canvas.right && y >= canvas.top && y <= canvas.bottom); +} + exports.getVizRangeObject = getVizRangeObject; exports.convertVisualRangeObject = convertVisualRangeObject; exports.adjustVisualRange = adjustVisualRange; @@ -642,3 +646,4 @@ exports.normalizeBBox = normalizeBBox; exports.PANE_PADDING = PANE_PADDING; exports.rangesAreEqual = rangesAreEqual; +exports.pointInCanvas = pointInCanvas; diff --git a/js/viz/series/points/bar_point.js b/js/viz/series/points/bar_point.js index 9dbb3a542127..4b7c3d616f78 100644 --- a/js/viz/series/points/bar_point.js +++ b/js/viz/series/points/bar_point.js @@ -16,6 +16,17 @@ const LEFT = 'left'; const TOP = 'top'; const BOTTOM = 'bottom'; +function getLabelOrientation(point) { + const initialValue = point.initialValue; + const invert = point._getValTranslator().getBusinessRange().invert; + const isDiscreteValue = point.series.valueAxisType === 'discrete'; + const isFullStacked = point.series.isFullStackedSeries(); + const notAxisInverted = (!isDiscreteValue && ((initialValue >= 0 && !invert) || + (initialValue < 0 && invert))) || + (isDiscreteValue && !invert) || + (isFullStacked); + return notAxisInverted ? TOP : BOTTOM; +} module.exports = _extend({}, symbolPoint, { correctCoordinates(correctOptions) { @@ -33,13 +44,25 @@ module.exports = _extend({}, symbolPoint, { } }, - _getGraphicBBox: function() { - return { + _getGraphicBBox: function(location) { + const bBox = { x: this.x, y: this.y, width: this.width, height: this.height }; + if(location) { + const isTop = location === 'top'; + if(!this._options.rotated) { + bBox.y = isTop ? bBox.y : bBox.y + bBox.height; + bBox.height = 0; + } else { + bBox.x = isTop ? bBox.x + bBox.width : bBox.x; + bBox.width = 0; + } + } + + return bBox; }, _getLabelConnector: function(location) { @@ -47,23 +70,10 @@ module.exports = _extend({}, symbolPoint, { }, _getLabelPosition: function() { - const that = this; - let position; - const initialValue = that.initialValue; - const invert = that._getValTranslator().getBusinessRange().invert; - const isDiscreteValue = that.series.valueAxisType === 'discrete'; - const isFullStacked = that.series.isFullStackedSeries(); - const notAxisInverted = (!isDiscreteValue && ((initialValue >= 0 && !invert) || - (initialValue < 0 && invert))) || - (isDiscreteValue && !invert) || - (isFullStacked); - - if(!that._options.rotated) { - position = notAxisInverted ? TOP : BOTTOM; - } else { - position = notAxisInverted ? RIGHT : LEFT; + let position = getLabelOrientation(this); + if(this._options.rotated) { + position = position === TOP ? RIGHT : LEFT; } - return position; }, @@ -85,15 +95,9 @@ module.exports = _extend({}, symbolPoint, { return coords; }, - _checkLabelPosition: function(label, coord) { - const that = this; - const visibleArea = that._getVisibleArea(); - - if(that._isPointInVisibleArea(visibleArea, that._getGraphicBBox())) { - return that._moveLabelOnCanvas(coord, visibleArea, label.getBoundingRect()); - } - - return coord; + _drawLabel: function() { + this._label.pointPosition = this._label.getLayoutOptions().position !== 'inside' && getLabelOrientation(this); + symbolPoint._drawLabel.call(this); }, hideInsideLabel: function(label, coord) { @@ -113,25 +117,6 @@ module.exports = _extend({}, symbolPoint, { return false; }, - _moveLabelOnCanvas: function(coord, visibleArea, labelBBox) { - let x = coord.x; - let y = coord.y; - if(visibleArea.minX > x) { - x = visibleArea.minX; - } - if(visibleArea.maxX < (x + labelBBox.width)) { - x = visibleArea.maxX - labelBBox.width; - } - if(visibleArea.minY > y) { - y = visibleArea.minY; - } - if(visibleArea.maxY < (y + labelBBox.height)) { - y = visibleArea.maxY - labelBBox.height; - } - - return { x: x, y: y }; - }, - _showForZeroValues: function() { return this._options.label.showForZeroValues || this.initialValue; }, diff --git a/js/viz/series/points/candlestick_point.js b/js/viz/series/points/candlestick_point.js index ef6e4a407253..d5609f9a4c4b 100644 --- a/js/viz/series/points/candlestick_point.js +++ b/js/viz/series/points/candlestick_point.js @@ -170,7 +170,7 @@ module.exports = _extend({}, barPoint, { }; }, - _getGraphicBBox: function() { + _getGraphicBBox: function(location) { const that = this; const rotated = that._options.rotated; const x = that.x; @@ -178,12 +178,25 @@ module.exports = _extend({}, barPoint, { const lowY = that.lowY; const highY = that.highY; - return { + const bBox = { x: !rotated ? x - _round(width / 2) : lowY, y: !rotated ? highY : x - _round(width / 2), width: !rotated ? width : highY - lowY, height: !rotated ? lowY - highY : width }; + + if(location) { + const isTop = location === 'top'; + if(!this._options.rotated) { + bBox.y = isTop ? bBox.y : bBox.y + bBox.height; + bBox.height = 0; + } else { + bBox.x = isTop ? bBox.x + bBox.width : bBox.x; + bBox.width = 0; + } + } + + return bBox; }, getTooltipParams: function(location) { diff --git a/js/viz/series/points/polar_point.js b/js/viz/series/points/polar_point.js index fdb4748f0b20..a099f77668b3 100644 --- a/js/viz/series/points/polar_point.js +++ b/js/viz/series/points/polar_point.js @@ -21,7 +21,24 @@ exports.polarSymbolPoint = _extend({}, symbolPoint, { _getLabelCoords: piePoint._getLabelCoords, - _moveLabelOnCanvas: barPoint._moveLabelOnCanvas, + _moveLabelOnCanvas: function(coord, visibleArea, labelBBox) { + let x = coord.x; + let y = coord.y; + if(visibleArea.minX > x) { + x = visibleArea.minX; + } + if(visibleArea.maxX < (x + labelBBox.width)) { + x = visibleArea.maxX - labelBBox.width; + } + if(visibleArea.minY > y) { + y = visibleArea.minY; + } + if(visibleArea.maxY < (y + labelBBox.height)) { + y = visibleArea.maxY - labelBBox.height; + } + + return { x: x, y: y }; + }, _getLabelPosition: function() { return 'outside'; @@ -135,7 +152,7 @@ exports.polarBarPoint = _extend({}, barPoint, { _getErrorBarSettings: exports.polarSymbolPoint._getErrorBarSettings, - _moveLabelOnCanvas: barPoint._moveLabelOnCanvas, + _moveLabelOnCanvas: exports.polarSymbolPoint._moveLabelOnCanvas, _getLabelCoords: piePoint._getLabelCoords, diff --git a/js/viz/series/points/range_bar_point.js b/js/viz/series/points/range_bar_point.js index 66e0c521f428..c26e76c4d5d4 100644 --- a/js/viz/series/points/range_bar_point.js +++ b/js/viz/series/points/range_bar_point.js @@ -82,21 +82,6 @@ module.exports = _extend({}, barPoint, { _getLabelCoords: rangeSymbolPointMethods._getLabelCoords, - _getGraphicBBox: function(location) { - const isTop = location === 'top'; - const bBox = barPoint._getGraphicBBox.call(this); - - if(!this._options.rotated) { - bBox.y = isTop ? bBox.y : bBox.y + bBox.height; - bBox.height = 0; - } else { - bBox.x = isTop ? bBox.x + bBox.width : bBox.x; - bBox.width = 0; - } - - return bBox; - }, - getLabel: rangeSymbolPointMethods.getLabel, getLabels: rangeSymbolPointMethods.getLabels, diff --git a/js/viz/series/points/symbol_point.js b/js/viz/series/points/symbol_point.js index e758f87d1408..21946108002f 100644 --- a/js/viz/series/points/symbol_point.js +++ b/js/viz/series/points/symbol_point.js @@ -329,9 +329,10 @@ module.exports = { const visibleArea = that._getVisibleArea(); const labelBBox = label.getBoundingRect(); const graphicBBox = that._getGraphicBBox(label.pointPosition); + const fullGraphicBBox = that._getGraphicBBox(); const offset = LABEL_OFFSET; - if(that._isPointInVisibleArea(visibleArea, graphicBBox)) { + if(that._isPointInVisibleArea(visibleArea, fullGraphicBBox)) { if(!that._options.rotated) { if(visibleArea.minX > coord.x) { coord.x = visibleArea.minX; diff --git a/js/viz/sparklines/base_sparkline.js b/js/viz/sparklines/base_sparkline.js index 6df117420361..da8418f9453d 100644 --- a/js/viz/sparklines/base_sparkline.js +++ b/js/viz/sparklines/base_sparkline.js @@ -1,19 +1,40 @@ const eventsEngine = require('../../events/core/events_engine'); const domAdapter = require('../../core/dom_adapter'); -const ready = require('../../core/utils/ready_callbacks').add; const isFunction = require('../../core/utils/type').isFunction; const BaseWidget = require('../core/base_widget'); const extend = require('../../core/utils/extend').extend; +const addNamespace = require('../../events/utils').addNamespace; +const pointerEvents = require('../../events/pointer'); +const pointInCanvas = require('../core/utils').pointInCanvas; const DEFAULT_LINE_SPACING = 2; -const DEFAULT_EVENTS_DELAY = 100; +const EVENT_NS = 'sparkline-tooltip'; +const POINTER_ACTION = addNamespace([pointerEvents.down, pointerEvents.move], EVENT_NS); -const eventUtils = require('../../events/utils'); const translator2DModule = require('../translators/translator2d'); const _extend = extend; +const _floor = Math.floor; const _noop = require('../../core/utils/common').noop; +function inCanvas({ left, top, bottom, right, width, height }, x, y) { + return pointInCanvas({ + left, + top, + right: width - right, + bottom: height - bottom, + width, + height + }, x, y); +} + +function pointerHandler({ data }) { + const that = data.widget; + + that._enableOutHandler(); + that._showTooltip(); +} + function generateDefaultCustomizeTooltipCallback(fontOptions, rtlEnabled) { const lineSpacing = fontOptions.lineSpacing; const lineHeight = ((lineSpacing !== undefined && lineSpacing !== null) ? lineSpacing : DEFAULT_LINE_SPACING) + fontOptions.size; @@ -67,92 +88,6 @@ function createAxis(isHorizontal) { }; } -// for ie11 -const menuEvents = { - 'contextmenu.sparkline-tooltip': function(event) { - if(eventUtils.isTouchEvent(event) || eventUtils.isPointerEvent(event)) { - event.preventDefault(); - } - }, - 'MSHoldVisual.sparkline-tooltip': function(event) { - event.preventDefault(); - } -}; - -const mouseEvents = { - 'mouseover.sparkline-tooltip': function(event) { - isPointerDownCalled = false; - const widget = event.data.widget; - widget._x = event.pageX; - widget._y = event.pageY; - widget._tooltipTracker.off(mouseMoveEvents).on(mouseMoveEvents, event.data); - widget._showTooltip(); - }, - 'mouseout.sparkline-tooltip': function(event) { - if(isPointerDownCalled) { - return; - } - const widget = event.data.widget; - widget._tooltipTracker.off(mouseMoveEvents); - widget._hideTooltip(DEFAULT_EVENTS_DELAY); - } -}; - -const mouseMoveEvents = { - 'mousemove.sparkline-tooltip': function(event) { - const widget = event.data.widget; - widget._x = event.pageX; - widget._y = event.pageY; - widget._showTooltip(); - } -}; - -let active_touch_tooltip_widget = null; -const touchStartTooltipProcessing = function(event) { - let widget = active_touch_tooltip_widget; - if(widget && widget !== event.data.widget) { - widget._hideTooltip(DEFAULT_EVENTS_DELAY); - } - widget = active_touch_tooltip_widget = event.data.widget; - widget._showTooltip(); - widget._touch = true; -}; -const touchStartDocumentProcessing = function() { - const widget = active_touch_tooltip_widget; - if(widget) { - if(!widget._touch) { - widget._hideTooltip(DEFAULT_EVENTS_DELAY); - active_touch_tooltip_widget = null; - } - widget._touch = null; - } -}; -const touchEndDocumentProcessing = function() { - const widget = active_touch_tooltip_widget; - if(widget) { - widget._hideTooltip(DEFAULT_EVENTS_DELAY); - active_touch_tooltip_widget = null; - } -}; -let isPointerDownCalled = false; - - -const touchEvents = { - 'pointerdown.sparkline-tooltip': touchStartTooltipProcessing, - 'touchstart.sparkline-tooltip': touchStartTooltipProcessing -}; -ready(function() { - eventsEngine.subscribeGlobal(domAdapter.getDocument(), { - 'pointerdown.sparkline-tooltip': function() { - isPointerDownCalled = true; - touchStartDocumentProcessing(); - }, - 'touchstart.sparkline-tooltip': touchStartDocumentProcessing, - 'pointerup.sparkline-tooltip': touchEndDocumentProcessing, - 'touchend.sparkline-tooltip': touchEndDocumentProcessing - }); -}); - /* eslint-disable-next-line */ let _initTooltip; @@ -237,54 +172,64 @@ const BaseSparkline = BaseWidget.inherit({ }; }, - _initTooltipEvents: function() { - let that = this; - const data = { widget: that }; + _initTooltipEvents() { + const data = { widget: this }; - that._showTooltipCallback = function() { - let tooltip; + this._renderer.root.off('.' + EVENT_NS) + .on(POINTER_ACTION, data, pointerHandler); + }, - if(!that._tooltipShown) { - that._tooltipShown = true; - tooltip = that._getTooltip(); - tooltip.isEnabled() && that._tooltip.show(that._getTooltipData(), that._getTooltipCoords(), {}); - } - ///#DEBUG - that._DEBUG_showCallback && that._DEBUG_showCallback(); - ///#ENDDEBUG - }; - that._hideTooltipCallback = function() { - ///#DEBUG - const tooltipWasShown = that._tooltipShown; - ///#ENDDEBUG - that._hideTooltipTimeout = null; - if(that._tooltipShown) { - that._tooltipShown = false; - that._tooltip.hide(); - } - ///#DEBUG - that._DEBUG_hideCallback && that._DEBUG_hideCallback(tooltipWasShown); - ///#ENDDEBUG - }; - that._disposeCallbacks = function() { - that = that._showTooltipCallback = that._hideTooltipCallback = that._disposeCallbacks = null; - }; - that._tooltipTracker.on(mouseEvents, data).on(touchEvents, data); + _showTooltip() { + const that = this; + let tooltip; + + if(!that._tooltipShown) { + that._tooltipShown = true; + tooltip = that._getTooltip(); + tooltip.isEnabled() && that._tooltip.show(that._getTooltipData(), that._getTooltipCoords(), {}); + } + }, - // for ie11 - that._tooltipTracker.on(menuEvents); + _hideTooltip() { + if(this._tooltipShown) { + this._tooltipShown = false; + this._tooltip.hide(); + } }, _stopCurrentHandling() { this._hideTooltip(); }, - _disposeTooltipEvents: function() { + _enableOutHandler() { const that = this; - clearTimeout(that._hideTooltipTimeout); + if(that._outHandler) { + return; + } - that._tooltipTracker.off(); - that._disposeCallbacks(); + const handler = ({ pageX, pageY }) =>{ + const { left, top } = that._renderer.getRootOffset(); + const x = _floor(pageX - left); + const y = _floor(pageY - top); + if(!inCanvas(that._canvas, x, y)) { + that._hideTooltip(); + that._disableOutHandler(); + } + }; + + eventsEngine.on(domAdapter.getDocument(), POINTER_ACTION, handler); + this._outHandler = handler; + }, + + _disableOutHandler() { + this._outHandler && eventsEngine.off(domAdapter.getDocument(), POINTER_ACTION, this._outHandler); + this._outHandler = null; + }, + + _disposeTooltipEvents: function() { + this._tooltipTracker.off(); + this._disableOutHandler(); + this._renderer.root.off('.' + EVENT_NS); }, _getTooltip: function() { @@ -301,12 +246,6 @@ const BaseSparkline = BaseWidget.inherit({ module.exports = BaseSparkline; -///#DEBUG -module.exports._DEBUG_reset = function() { - active_touch_tooltip_widget = null; -}; -///#ENDDEBUG - // PLUGINS_SECTION BaseSparkline.addPlugin(require('../core/tooltip').plugin); @@ -336,34 +275,6 @@ BaseSparkline.prototype._setTooltipOptions = function() { })); }; -BaseSparkline.prototype._showTooltip = function() { - const that = this; - - ///#DEBUG - ++that._DEBUG_clearHideTooltipTimeout; - ///#ENDDEBUG - clearTimeout(that._hideTooltipTimeout); - that._hideTooltipTimeout = null; - that._showTooltipCallback(); -}; - -BaseSparkline.prototype._hideTooltip = function(delay) { - const that = this; - - ///#DEBUG - ++that._DEBUG_clearShowTooltipTimeout; - ///#ENDDEBUG - clearTimeout(that._hideTooltipTimeout); - if(delay) { - ///#DEBUG - ++that._DEBUG_hideTooltipTimeoutSet; - ///#ENDDEBUG - that._hideTooltipTimeout = setTimeout(that._hideTooltipCallback, delay); - } else { - that._hideTooltipCallback(); - } -}; - // PLUGINS_SECTION // T422022 const exportPlugin = extend(true, {}, require('../core/export').plugin, { diff --git a/package.json b/package.json index ca555f5bbc4d..f995e300c1c4 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,7 @@ "license": "SEE LICENSE IN README.md", "dependencies": { "devexpress-diagram": "0.2.12", - "devexpress-gantt": "0.1.2", + "devexpress-gantt": "0.1.4", "jszip": "^2.0.0 || ^3.0.0", "quill": "^1.3.7", "showdown": "^1.8.6", @@ -72,6 +72,7 @@ "gulp-babel": "^8.0.0", "gulp-clean-css": "^4.2.0", "gulp-concat": "^2.6.0", + "gulp-dart-sass": "^0.9.1", "gulp-eol": "^0.1.2", "gulp-eslint": "^6.0.0", "gulp-file": "^0.4.0", @@ -105,6 +106,7 @@ "lazypipe": "^1.0.1", "less": "3.9.0", "less-plugin-autoprefix": "^2.0.0", + "less2sass": "^1.0.3", "lint-staged": "^3.4.0", "map-stream": "0.0.7", "merge-stream": "^2.0.0", diff --git a/shippable.yml b/shippable.yml index 9a2753ca9aaa..499749a5f049 100644 --- a/shippable.yml +++ b/shippable.yml @@ -8,8 +8,14 @@ env: - TARGET=test CONSTEL=misc - TARGET=test CONSTEL=ui - TARGET=test CONSTEL=ui.editors + - TARGET=test CONSTEL=ui.editors TZ='PST8PDT' + - TARGET=test CONSTEL=ui.editors TZ='Japan' + - TARGET=test CONSTEL=ui.editors TZ='Australia/ACT' - TARGET=test CONSTEL=ui.grid - TARGET=test CONSTEL=ui.scheduler + - TARGET=test CONSTEL=ui.scheduler TZ='PST8PDT' + - TARGET=test CONSTEL=ui.scheduler TZ='Japan' + - TARGET=test CONSTEL=ui.scheduler TZ='Australia/ACT' - TARGET=test CONSTEL=viz - TARGET=test PERF=true JQUERY=true NO_HEADLESS=true - TARGET=test MOBILE_UA=ios9 CONSTEL=ui @@ -25,11 +31,12 @@ env: - TARGET=test BROWSER=firefox JQUERY=true CONSTEL=ui.scheduler - TARGET=test BROWSER=firefox JQUERY=true CONSTEL=viz - TARGET=test_functional COMPONENT=dataGrid - - TARGET=test_functional COMPONENT=scheduler + - TARGET=test_functional COMPONENT=scheduler QUARANTINE_MODE=true - TARGET=test_functional COMPONENT=editors - TARGET=test_functional COMPONENT=navigation - TARGET=test_themebuilder - TARGET=test_jest + - TARGET=test_scss build: diff --git a/styles/mixins.less b/styles/mixins.less index 2f94e0712da1..94e68bae2458 100644 --- a/styles/mixins.less +++ b/styles/mixins.less @@ -62,12 +62,6 @@ } } -.pseudo-link() { - border-bottom: 1px dashed; - display: inline-block; - line-height: normal; -} - .hide-input-cursor() { border: none; color: transparent; diff --git a/styles/widgets/base/colorView.less b/styles/widgets/base/colorView.less index 8d2e92c224ca..49635ec5cc01 100644 --- a/styles/widgets/base/colorView.less +++ b/styles/widgets/base/colorView.less @@ -1,14 +1,17 @@ -.dx-colorview-palette-handle { - background: radial-gradient(transparent 5px, @COLORVIEW_HANDLE_BORDER_COLOR 6px, @COLORVIEW_HANDLE_COLOR 7px, @COLORVIEW_HANDLE_COLOR 12px, @COLORVIEW_HANDLE_BORDER_COLOR 13px); - box-shadow: 0 1px 1px 0 @COLORVIEW_HANDLE_BORDER_COLOR; -} -.dx-colorview-hue-scale-handle { - border: 1px solid @COLORVIEW_HANDLE_BORDER_COLOR; - box-shadow: inset -5px 0 0 3px @COLORVIEW_HANDLE_COLOR, inset 5px 0 0 3px @COLORVIEW_HANDLE_COLOR, inset -6px 0 1px 4px @COLORVIEW_HANDLE_BORDER_COLOR, inset 6px 0 1px 4px @COLORVIEW_HANDLE_BORDER_COLOR; -} +.dx-base-colorview-styles(@handle-color, @handle-border-color) { + .dx-colorview-palette-handle { + background: radial-gradient(transparent 5px, @handle-border-color 6px, @handle-color 7px, @handle-color 12px, @handle-border-color 13px); + box-shadow: 0 1px 1px 0 @handle-border-color; + } + + .dx-colorview-hue-scale-handle { + border: 1px solid @handle-border-color; + box-shadow: inset -5px 0 0 3px @handle-color, inset 5px 0 0 3px @handle-color, inset -6px 0 1px 4px @handle-border-color, inset 6px 0 1px 4px @handle-border-color; + } -.dx-colorview-alpha-channel-handle { - border: 1px solid @COLORVIEW_HANDLE_BORDER_COLOR; - box-shadow: inset 0 -5px 0 3px @COLORVIEW_HANDLE_COLOR, inset 0 5px 0 3px @COLORVIEW_HANDLE_COLOR, inset 0 -6px 1px 4px @COLORVIEW_HANDLE_BORDER_COLOR, inset 0 6px 1px 4px @COLORVIEW_HANDLE_BORDER_COLOR; + .dx-colorview-alpha-channel-handle { + border: 1px solid @handle-border-color; + box-shadow: inset 0 -5px 0 3px @handle-color, inset 0 5px 0 3px @handle-color, inset 0 -6px 1px 4px @handle-border-color, inset 0 6px 1px 4px @handle-border-color; + } } diff --git a/styles/widgets/base/dataGrid.less b/styles/widgets/base/dataGrid.less index 39efbc63002d..23e7ebebddac 100644 --- a/styles/widgets/base/dataGrid.less +++ b/styles/widgets/base/dataGrid.less @@ -40,11 +40,11 @@ background-color: @datagrid-base-background-color; .dx-sort-up { - .dx-icon-sortup; + .dx-icon(sortup); } .dx-sort-down { - .dx-icon-sortdown; + .dx-icon(sortdown); } .dx-sort-down, @@ -97,7 +97,7 @@ .dx-header-filter { position: relative; color: @HEADER_FILTER_COLOR; - .dx-icon-filter; + .dx-icon(filter); } .dx-header-filter-empty { @@ -197,7 +197,7 @@ } .dx-command-drag .dx-datagrid-drag-icon { - .dx-icon-dragvertical; + .dx-icon(dragvertical); } } @@ -236,7 +236,7 @@ .dx-datagrid-adaptive-more { cursor: pointer; - .dx-icon-more; + .dx-icon(more); .dx-icon-sizing(21px); } diff --git a/styles/widgets/base/diagram.less b/styles/widgets/base/diagram.less index 36f7582642de..0c5087c79152 100644 --- a/styles/widgets/base/diagram.less +++ b/styles/widgets/base/diagram.less @@ -1,4 +1,4 @@ -.diagram-icons-mixin(@toolbar-color, @menu-color, @icon-size) { +.diagram-action-icons-mixin(@toolbar-color, @menu-color, @icon-size) { .dx-diagram-i-connector-begin-none { .diagram-icon-colored(data-uri('image/svg+xml;charset=UTF-8', 'images/widgets/common/diagram/connector-begin-none.svg'), @toolbar-color, 1.46 * @icon-size, @icon-size); } diff --git a/styles/widgets/base/icons.less b/styles/widgets/base/icons.less index ae0c15e56476..493d31d9e0fa 100644 --- a/styles/widgets/base/icons.less +++ b/styles/widgets/base/icons.less @@ -1,4 +1,4 @@ -.dx-icon-sizing(@icon_size, @container_size, @borders_size: 0) { +.dx-icon-sizing(@icon_size, @container_size: @icon_size, @borders_size: 0) { @icon_paddings_dirty: @container_size - @icon_size; @icon_paddings: @icon_paddings_dirty - @borders_size; @icon_padding: floor(@icon_paddings/2); @@ -20,12 +20,6 @@ line-height: @container_size - @icon_paddings_dirty; } -// NOTE: use @container_size: @icon_size parameter declaration in previous mixin when upgrade less -.dx-icon-sizing(@icon_size) { - .dx-icon-sizing(@icon_size, @icon_size); -} - - .dx-icon-font-centered-sizing(@icon_size) { font-size: @icon_size; text-align: center; @@ -47,8 +41,8 @@ margin-right: @size; margin-left: 0; - .dx-rtl &, - .dx-rtl& { + .dx-rtl&, + .dx-rtl & { margin-left: @size; margin-right: 0; } @@ -57,8 +51,8 @@ margin-left: @size; margin-right: 0; - .dx-rtl &, - .dx-rtl& { + .dx-rtl&, + .dx-rtl & { margin-right: @size; margin-left: 0; } @@ -73,271 +67,209 @@ } } -.dx-font-icons-list() { - .dx-icon-add { .dx-font-icon("\f00b"); } - .dx-icon-airplane { .dx-font-icon("\f000"); } - .dx-icon-bookmark { .dx-font-icon("\f017"); } - .dx-icon-box { .dx-font-icon("\f018"); } - .dx-icon-car { .dx-font-icon("\f01b"); } - .dx-icon-card { .dx-font-icon("\f019"); } - .dx-icon-cart { .dx-font-icon("\f01a"); } - .dx-icon-chart { .dx-font-icon("\f01c"); } - .dx-icon-check { .dx-font-icon("\f005"); } - .dx-icon-clear { .dx-font-icon("\f008"); } - .dx-icon-clock { .dx-font-icon("\f01d"); } - .dx-icon-close { .dx-font-icon("\f00a"); } - .dx-icon-coffee { .dx-font-icon("\f02a"); } - .dx-icon-comment { .dx-font-icon("\f01e"); } - - .dx-icon-doc, - .dx-icon-file { - .dx-font-icon("\f021"); - } - .dx-icon-download { .dx-font-icon("\f022"); } - .dx-icon-dragvertical { .dx-font-icon("\f038"); } - .dx-icon-edit { .dx-font-icon("\f023"); } - .dx-icon-email { .dx-font-icon("\f024"); } - .dx-icon-event { .dx-font-icon("\f026"); } - .dx-icon-favorites { .dx-font-icon("\f025"); } - .dx-icon-find { .dx-font-icon("\f027"); } - .dx-icon-filter { .dx-font-icon("\f050"); } - - .dx-icon-folder, - .dx-icon-activefolder { - .dx-font-icon("\f028"); - } - .dx-icon-food { .dx-font-icon("\f029"); } - .dx-icon-gift { .dx-font-icon("\f02b"); } - .dx-icon-globe { .dx-font-icon("\f02c"); } - .dx-icon-group { .dx-font-icon("\f02e"); } - .dx-icon-help { .dx-font-icon("\f02f"); } - .dx-icon-home { .dx-font-icon("\f030"); } - .dx-icon-image { .dx-font-icon("\f031"); } - .dx-icon-info { .dx-font-icon("\f032"); } - .dx-icon-key { .dx-font-icon("\f033"); } - .dx-icon-like { .dx-font-icon("\f034"); } - .dx-icon-map { .dx-font-icon("\f035"); } - .dx-icon-menu { .dx-font-icon("\f00c"); } - .dx-icon-message { .dx-font-icon("\f024"); } - .dx-icon-money { .dx-font-icon("\f036"); } - .dx-icon-music { .dx-font-icon("\f037"); } - .dx-icon-overflow { .dx-font-icon("\f00d"); } - .dx-icon-percent { .dx-font-icon("\f039"); } - .dx-icon-photo { .dx-font-icon("\f03a"); } - .dx-icon-plus { .dx-font-icon("\f00b"); } - .dx-icon-minus { .dx-font-icon("\f074"); } - .dx-icon-preferences { .dx-font-icon("\f03b"); } - .dx-icon-product { .dx-font-icon("\f03c"); } - .dx-icon-pulldown { .dx-font-icon("\f062"); } - .dx-icon-refresh { .dx-font-icon("\f03d"); } - .dx-icon-remove { .dx-font-icon("\f00a"); } - .dx-icon-revert { .dx-font-icon("\f04c"); } - .dx-icon-runner { .dx-font-icon("\f040"); } - .dx-icon-save { .dx-font-icon("\f041"); } - .dx-icon-search { .dx-font-icon("\f027"); } - .dx-icon-tags { .dx-font-icon("\f009"); } - .dx-icon-tel { .dx-font-icon("\f003"); } - .dx-icon-tips { .dx-font-icon("\f004"); } - .dx-icon-todo { .dx-font-icon("\f005"); } - .dx-icon-toolbox { .dx-font-icon("\f007"); } - .dx-icon-trash { .dx-font-icon("\f03e"); } - .dx-icon-user { .dx-font-icon("\f02d"); } - .dx-icon-upload { .dx-font-icon("\f006"); } - .dx-icon-floppy { .dx-font-icon("\f073"); } - - .dx-icon-arrowleft { .dx-font-icon("\f011"); } - .dx-icon-arrowdown { .dx-font-icon("\f015"); } - .dx-icon-arrowright { .dx-font-icon("\f00e"); } - .dx-icon-arrowup { .dx-font-icon("\f013"); } - - .dx-icon-spinleft, - .dx-icon-spinprev { - .dx-font-icon("\f04f"); - } - - .dx-icon-spinright, - .dx-icon-spinnext { - .dx-font-icon("\f04e"); - } - - .dx-icon-spinnext { - .dx-rtl &:before { content: "\f04f"; } //.dx-icon-spinleft - } - - .dx-icon-spinprev { - .dx-rtl &:before { content: "\f04e"; } //.dx-icon-spinright - } - .dx-icon-spindown { .dx-font-icon("\f001"); } - .dx-icon-spinup { .dx-font-icon("\f002"); } - - .dx-icon-chevronleft, - .dx-icon-chevronprev, - .dx-icon-back { - .dx-font-icon("\f012"); - } - - .dx-icon-chevronright, - .dx-icon-chevronnext { - .dx-font-icon("\f010"); - } - - .dx-icon-chevronnext { - .dx-rtl &:before { content: "\f012"; } //.dx-icon-chevronleft - } - - .dx-icon-chevronprev { - .dx-rtl &:before { content: "\f010"; } //.dx-icon-chevronright - } - .dx-icon-chevrondown { .dx-font-icon("\f016"); } - .dx-icon-chevronup { .dx-font-icon("\f014"); } - .dx-icon-chevrondoubleleft { .dx-font-icon("\f042"); } - .dx-icon-chevrondoubleright { .dx-font-icon("\f03f"); } - - .dx-icon-equal { .dx-font-icon("\f044"); } - .dx-icon-notequal { .dx-font-icon("\f045"); } - .dx-icon-less { .dx-font-icon("\f046"); } - .dx-icon-greater { .dx-font-icon("\f047"); } - .dx-icon-lessorequal { .dx-font-icon("\f048"); } - .dx-icon-greaterorequal { .dx-font-icon("\f049"); } - .dx-icon-isblank { .dx-font-icon("\f075"); } - .dx-icon-isnotblank { .dx-font-icon("\f076"); } - - .dx-icon-sortup { .dx-font-icon("\f051"); } - .dx-icon-sortdown { .dx-font-icon("\f052"); } - .dx-icon-sortuptext { .dx-font-icon("\f053"); } - .dx-icon-sortdowntext { .dx-font-icon("\f054"); } - .dx-icon-sorted { .dx-font-icon("\f055"); } - - .dx-icon-expand { .dx-font-icon("\f04a"); } - .dx-icon-collapse { .dx-font-icon("\f04b"); } - - .dx-icon-columnfield { .dx-font-icon("\f057"); } - .dx-icon-rowfield { .dx-font-icon("\f058"); } - .dx-icon-datafield { .dx-font-icon("\f101"); } - .dx-icon-fields { .dx-font-icon("\f059"); } - .dx-icon-fieldchooser { .dx-font-icon("\f05a"); } - .dx-icon-columnchooser { .dx-font-icon("\f04d"); } - - .dx-icon-pin { .dx-font-icon("\f05b"); } - .dx-icon-unpin { .dx-font-icon("\f05c"); } - .dx-icon-pinleft { .dx-font-icon("\f05d"); } - .dx-icon-pinright { .dx-font-icon("\f05e"); } - - .dx-icon-contains { .dx-font-icon("\f063"); } - .dx-icon-startswith { .dx-font-icon("\f064"); } - .dx-icon-endswith { .dx-font-icon("\f065"); } - .dx-icon-doesnotcontain { .dx-font-icon("\f066"); } - .dx-icon-range { .dx-font-icon("\f06a"); } - - .dx-icon-export { .dx-font-icon("\f05f"); } - .dx-icon-exportxlsx { .dx-font-icon("\f060"); } - .dx-icon-exportpdf { .dx-font-icon("\f061"); } - .dx-icon-exportselected { .dx-font-icon("\f06d"); } - - .dx-icon-warning { .dx-font-icon("\f06b"); } - .dx-icon-more { .dx-font-icon("\f06c"); } - - .dx-icon-square { .dx-font-icon("\f067"); } - .dx-icon-clearsquare { .dx-font-icon("\f068"); } - - .dx-icon-back { - .dx-rtl &:before { content: "\f010"; } //.dx-icon-chevronright - } - - .dx-icon-repeat { .dx-font-icon("\f069"); } - - .dx-icon-selectall { .dx-font-icon("\f070"); } - .dx-icon-unselectall { .dx-font-icon("\f071"); } - .dx-icon-print { .dx-font-icon("\f072"); } - - .dx-icon-bold { .dx-font-icon("\f077"); } - .dx-icon-italic { .dx-font-icon("\f078"); } - .dx-icon-underline { .dx-font-icon("\f079"); } - .dx-icon-strike { .dx-font-icon("\f07a"); } - - .dx-icon-indent, - .dx-icon-increaselinespacing { - .dx-font-icon("\f07b"); - } - .dx-icon-font { .dx-font-icon("\f11b"); } - .dx-icon-fontsize { .dx-font-icon("\f07c"); } - .dx-icon-shrinkfont { .dx-font-icon("\f07d"); } - .dx-icon-growfont { .dx-font-icon("\f07e"); } - .dx-icon-color { .dx-font-icon("\f07f"); } - .dx-icon-background { .dx-font-icon("\f080"); } - .dx-icon-fill { .dx-font-icon("\f10d"); } - .dx-icon-palette { .dx-font-icon("\f120"); } - .dx-icon-superscript { .dx-font-icon("\f081"); } - .dx-icon-subscript { .dx-font-icon("\f082"); } - .dx-icon-header { .dx-font-icon("\f083"); } - .dx-icon-blockquote { .dx-font-icon("\f084"); } - .dx-icon-formula { .dx-font-icon("\f056"); } - .dx-icon-codeblock { .dx-font-icon("\f085"); } - .dx-icon-orderedlist { .dx-font-icon("\f086"); } - .dx-icon-bulletlist { .dx-font-icon("\f087"); } - .dx-icon-increaseindent { .dx-font-icon("\f088"); } - .dx-icon-decreaseindent { .dx-font-icon("\f089"); } - .dx-icon-decreaselinespacing { .dx-font-icon("\f106"); } - .dx-icon-alignleft { .dx-font-icon("\f08a"); } - .dx-icon-alignright { .dx-font-icon("\f08b"); } - .dx-icon-aligncenter { .dx-font-icon("\f08c"); } - .dx-icon-alignjustify { .dx-font-icon("\f08d"); } - .dx-icon-link { .dx-font-icon("\f08e"); } - .dx-icon-video { .dx-font-icon("\f08f"); } - .dx-icon-mention { .dx-font-icon("\f090"); } - .dx-icon-variable { .dx-font-icon("\f091"); } - .dx-icon-clearformat { .dx-font-icon("\f092"); } - .dx-icon-fullscreen { .dx-font-icon("\f11a"); } - .dx-icon-hierarchy { .dx-font-icon("\f124"); } - - .dx-icon-docfile { .dx-font-icon("\f111"); } - .dx-icon-docxfile { .dx-font-icon("\f110"); } - .dx-icon-pdffile { .dx-font-icon("\f118"); } - .dx-icon-pptfile { .dx-font-icon("\f114"); } - .dx-icon-pptxfile { .dx-font-icon("\f115"); } - .dx-icon-rtffile { .dx-font-icon("\f112"); } - .dx-icon-txtfile { .dx-font-icon("\f113"); } - .dx-icon-xlsfile { .dx-font-icon("\f116"); } - .dx-icon-xlsxfile { .dx-font-icon("\f117"); } - - .dx-icon-copy { .dx-font-icon("\f107"); } - .dx-icon-cut { .dx-font-icon("\f10a"); } - .dx-icon-paste { .dx-font-icon("\f108"); } - .dx-icon-share { .dx-font-icon("\f11f"); } - - .dx-icon-inactivefolder { .dx-font-icon("\f105"); } - .dx-icon-newfolder { .dx-font-icon("\f123"); } - .dx-icon-movetofolder { .dx-font-icon("\f121"); } - .dx-icon-parentfolder { .dx-font-icon("\f122"); } - .dx-icon-rename { .dx-font-icon("\f109"); } - - .dx-icon-detailslayout { .dx-font-icon("\f10b"); } - .dx-icon-contentlayout { .dx-font-icon("\f11e"); } - .dx-icon-smalliconslayout { .dx-font-icon("\f119"); } - .dx-icon-mediumiconslayout { .dx-font-icon("\f10c"); } - - - .dx-icon-undo { - .dx-font-icon("\f04c"); - .dx-rtl &:before { content: "\f093"; } // redo icon - } - - .dx-icon-redo { - .dx-font-icon("\f093"); - .dx-rtl &:before { content: "\f04c"; } // undo icon - } - - .dx-icon-hidepanel { - .dx-font-icon("\f11c"); - .dx-rtl &:before { content: "\f11d"; } // showpanel icon - } +// stylelint-disable property-no-unknown +@icons: { + add: "\f00b"; + airplane: "\f000"; + bookmark: "\f017"; + box: "\f018"; + car: "\f01b"; + card: "\f019"; + cart: "\f01a"; + chart: "\f01c"; + check: "\f005"; + clear: "\f008"; + clock: "\f01d"; + close: "\f00a"; + coffee: "\f02a"; + comment: "\f01e"; + doc: "\f021"; + file: "\f021"; + download: "\f022"; + dragvertical: "\f038"; + edit: "\f023"; + email: "\f024"; + event: "\f026"; + favorites: "\f025"; + find: "\f027"; + filter: "\f050"; + folder: "\f028"; + activefolder: "\f028"; + food: "\f029"; + gift: "\f02b"; + globe: "\f02c"; + group: "\f02e"; + help: "\f02f"; + home: "\f030"; + image: "\f031"; + info: "\f032"; + key: "\f033"; + like: "\f034"; + map: "\f035"; + menu: "\f00c"; + message: "\f024"; + money: "\f036"; + music: "\f037"; + overflow: "\f00d"; + percent: "\f039"; + photo: "\f03a"; + plus: "\f00b"; + minus: "\f074"; + preferences: "\f03b"; + product: "\f03c"; + pulldown: "\f062"; + refresh: "\f03d"; + remove: "\f00a"; + revert: "\f04c"; + runner: "\f040"; + save: "\f041"; + search: "\f027"; + tags: "\f009"; + tel: "\f003"; + tips: "\f004"; + todo: "\f005"; + toolbox: "\f007"; + trash: "\f03e"; + user: "\f02d"; + upload: "\f006"; + floppy: "\f073"; + arrowleft: "\f011"; + arrowdown: "\f015"; + arrowright: "\f00e"; + arrowup: "\f013"; + spinleft: "\f04f"; + spinprev: "\f04f"; + spinright: "\f04e"; + spinnext: "\f04e"; + spindown: "\f001"; + spinup: "\f002"; + chevronleft: "\f012"; + chevronprev: "\f012"; + back: "\f012"; + chevronright: "\f010"; + chevronnext: "\f010"; + chevrondown: "\f016"; + chevronup: "\f014"; + chevrondoubleleft: "\f042"; + chevrondoubleright: "\f03f"; + equal: "\f044"; + notequal: "\f045"; + less: "\f046"; + greater: "\f047"; + lessorequal: "\f048"; + greaterorequal: "\f049"; + isblank: "\f075"; + isnotblank: "\f076"; + sortup: "\f051"; + sortdown: "\f052"; + sortuptext: "\f053"; + sortdowntext: "\f054"; + sorted: "\f055"; + expand: "\f04a"; + collapse: "\f04b"; + columnfield: "\f057"; + rowfield: "\f058"; + datafield: "\f101"; + fields: "\f059"; + fieldchooser: "\f05a"; + columnchooser: "\f04d"; + pin: "\f05b"; + unpin: "\f05c"; + pinleft: "\f05d"; + pinright: "\f05e"; + contains: "\f063"; + startswith: "\f064"; + endswith: "\f065"; + doesnotcontain: "\f066"; + range: "\f06a"; + export: "\f05f"; + exportxlsx: "\f060"; + exportpdf: "\f061"; + exportselected: "\f06d"; + warning: "\f06b"; + more: "\f06c"; + square: "\f067"; + clearsquare: "\f068"; + repeat: "\f069"; + selectall: "\f070"; + unselectall: "\f071"; + print: "\f072"; + bold: "\f077"; + italic: "\f078"; + underline: "\f079"; + strike: "\f07a"; + indent: "\f07b"; + increaselinespacing: "\f07b"; + font: "\f11b"; // stylelint-disable-line font-family-no-missing-generic-family-keyword + fontsize: "\f07c"; + shrinkfont: "\f07d"; + growfont: "\f07e"; + color: "\f07f"; + background: "\f080"; + fill: "\f10d"; + palette: "\f120"; + superscript: "\f081"; + subscript: "\f082"; + header: "\f083"; + blockquote: "\f084"; + formula: "\f056"; + codeblock: "\f085"; + orderedlist: "\f086"; + bulletlist: "\f087"; + increaseindent: "\f088"; + decreaseindent: "\f089"; + decreaselinespacing: "\f106"; + alignleft: "\f08a"; + alignright: "\f08b"; + aligncenter: "\f08c"; + alignjustify: "\f08d"; + link: "\f08e"; + video: "\f08f"; + mention: "\f090"; + variable: "\f091"; + clearformat: "\f092"; + fullscreen: "\f11a"; + hierarchy: "\f124"; + docfile: "\f111"; + docxfile: "\f110"; + pdffile: "\f118"; + pptfile: "\f114"; + pptxfile: "\f115"; + rtffile: "\f112"; + txtfile: "\f113"; + xlsfile: "\f116"; + xlsxfile: "\f117"; + copy: "\f107"; + cut: "\f10a"; + paste: "\f108"; + share: "\f11f"; + inactivefolder: "\f105"; + newfolder: "\f123"; + movetofolder: "\f121"; + parentfolder: "\f122"; + rename: "\f109"; + detailslayout: "\f10b"; + contentlayout: "\f11e"; + smalliconslayout: "\f119"; + mediumiconslayout: "\f10c"; + undo: "\f04c"; + redo: "\f093"; + hidepanel: "\f11c"; + showpanel: "\f11d"; +} +// stylelint-enable - .dx-icon-showpanel { - .dx-font-icon("\f11d"); - .dx-rtl &:before { content: "\f11c"; } // hidepanel icon - } +.dx-icon(@name) { + .dx-font-icon(@icons[$@name]); } +.dx-font-icons-list() { + each(@icons, { + .dx-icon-@{key} { + .dx-icon(@key); + } + }); +} .dx-font-icons(@font-file: "dxicons", @font-name: "DevExtreme Generic Icons", @font-name-safari: "devextreme_generic_icons") { @font-face { @@ -363,3 +295,38 @@ .dx-font-icons-list(); } +.dx-rtl { + .dx-icon-spinnext:before { + content: "\f04f"; //.dx-icon-spinleft + } + + .dx-icon-spinprev:before { + content: "\f04e"; //.dx-icon-spinright + } + + .dx-icon-chevronnext:before { + content: "\f012"; //.dx-icon-chevronleft + } + + .dx-icon-chevronprev:before, + .dx-icon-back:before { + content: "\f010"; //.dx-icon-chevronright + } + + .dx-icon-undo:before { + content: "\f093"; // redo icon + } + + .dx-icon-redo:before { + content: "\f04c"; // undo icon + } + + .dx-icon-hidepanel:before { + content: "\f11d"; // showpanel icon + } + + .dx-icon-showpanel:before { + content: "\f11c"; // hidepanel icon + } +} + diff --git a/styles/widgets/base/pivotGrid.less b/styles/widgets/base/pivotGrid.less index be9f8666da12..0be841251605 100644 --- a/styles/widgets/base/pivotGrid.less +++ b/styles/widgets/base/pivotGrid.less @@ -42,16 +42,16 @@ } .dx-sort-up { - .dx-icon-sortup; + .dx-icon(sortup); } .dx-sort-down { - .dx-icon-sortdown; + .dx-icon(sortdown); } .dx-header-filter { color: @HEADER_FILTER_COLOR; - .dx-icon-filter; + .dx-icon(filter); font-size: @PIVOTGRID_ICON_SIZE; width: @PIVOTGRID_ICON_SIZE; @@ -342,9 +342,7 @@ td.dx-white-space-column { border-top: @PIVOTGRID_BORDER_WIDTH solid transparent; background-color: @PIVOTGRID_TOTALCOLOR; - width: 24px; padding: 0; - min-width: 24px; } } diff --git a/styles/widgets/base/scheduler.less b/styles/widgets/base/scheduler.less index 720aa3b1261a..ce0e71c02e26 100644 --- a/styles/widgets/base/scheduler.less +++ b/styles/widgets/base/scheduler.less @@ -630,7 +630,7 @@ .dx-scheduler-date-time-indicator { margin-left: @SCHEDULER_LEFT_COLUMN_WIDTH; height: @SCHEDULER_TIME_INDICATOR_SIZE; - .dx-icon-spinright; + .dx-icon(spinright); .dx-scheduler-small & { margin-left: @SCHEDULER_LEFT_COLUMN_WIDTH * @SCHEDULER_SMALL_SIZE_FACTOR; @@ -672,7 +672,7 @@ &.dx-rtl { .dx-scheduler-date-time-indicator { margin-left: 0; - .dx-icon-spinleft; + .dx-icon(spinleft); &:before { margin-right: -@SCHEDULER_TIME_INDICATOR_LEFT; @@ -731,7 +731,7 @@ .dx-scheduler-date-time-indicator { width: @SCHEDULER_TIME_INDICATOR_SIZE; top: 0; - .dx-icon-spindown; + .dx-icon(spindown); &:before { margin-left: -@SCHEDULER_TIME_INDICATOR_TOP; @@ -1819,12 +1819,12 @@ position: absolute; top: 3px; right: @SCHEDULER_REDUCED_ICON_OFFSET; - .dx-icon-arrowright; + .dx-icon(arrowright); .dx-rtl & { right: auto; left: 3px; - .dx-icon-arrowleft; + .dx-icon(arrowleft); } } diff --git a/styles/widgets/base/treeList.less b/styles/widgets/base/treeList.less index 57cf18596b1e..e154c8e740f4 100644 --- a/styles/widgets/base/treeList.less +++ b/styles/widgets/base/treeList.less @@ -47,7 +47,7 @@ } .dx-command-drag .dx-treelist-drag-icon { - .dx-icon-dragvertical; + .dx-icon(dragvertical); } } @@ -56,11 +56,11 @@ background-color: @treelist-base-background-color; .dx-sort-up { - .dx-icon-sortup; + .dx-icon(sortup); } .dx-sort-down { - .dx-icon-sortdown; + .dx-icon(sortdown); } .dx-sort-down, @@ -97,7 +97,7 @@ .dx-header-filter { position: relative; color: @HEADER_FILTER_COLOR; - .dx-icon-filter; + .dx-icon(filter); } .dx-header-filter-empty { @@ -227,7 +227,7 @@ .dx-treelist-adaptive-more { cursor: pointer; - .dx-icon-more; + .dx-icon(more); .dx-icon-sizing(21px); } diff --git a/styles/widgets/base/validation.less b/styles/widgets/base/validation.less index 9cd94524c2bb..a48bef73a2cc 100644 --- a/styles/widgets/base/validation.less +++ b/styles/widgets/base/validation.less @@ -1,14 +1,18 @@ -.dx-validationsummary-item { - color: @VALIDATION_SUMMARY_COLOR; -} +.dx-base-validation(@summary-color, @message-color, @message-bg-color) { + .dx-validationsummary-item { + color: @summary-color; + } -.dx-validationsummary-item-content { - .pseudo-link(); + .dx-invalid-message > .dx-overlay-content { + color: @message-color; + background-color: @message-bg-color; + } } -.dx-invalid-message > .dx-overlay-content { - color: @VALIDATION_MESSAGE_COLOR; - background-color: @VALIDATION_MESSAGE_BACKGROUND_COLOR; +.dx-validationsummary-item-content { + border-bottom: 1px dashed; + display: inline-block; + line-height: normal; } @keyframes valid-badge-frames { diff --git a/styles/widgets/common/checkBox.less b/styles/widgets/common/checkBox.less index 60585cbd8261..0c5730567cf8 100644 --- a/styles/widgets/common/checkBox.less +++ b/styles/widgets/common/checkBox.less @@ -44,8 +44,8 @@ height: 100%; width: 100%; - .dx-rtl &, - .dx-rtl& { + .dx-rtl&, + .dx-rtl & { margin: 0; padding: 0; } diff --git a/styles/widgets/common/diagram.less b/styles/widgets/common/diagram.less index aa5053cdf92e..82a73b692c77 100644 --- a/styles/widgets/common/diagram.less +++ b/styles/widgets/common/diagram.less @@ -20,6 +20,10 @@ .dx-diagram-toolbar-wrapper { padding: 5px; flex-grow: 0; + + .dx-diagram-toolbar { + background-color: transparent; + } } .dx-diagram-content-wrapper { @@ -29,21 +33,6 @@ overflow: hidden; } - .dx-diagram-left-panel { - flex: 240px 0 0; - overflow-y: auto; - position: relative; - border-right: @TRANSPARENT_BORDER; - } - - .dx-diagram-left-panel > * { - position: absolute; - } - - .dx-diagram-left-panel > .dx-scrollview { - width: 100%; - } - .dx-diagram-drawer-wrapper { flex: 1 0; overflow: hidden; @@ -66,6 +55,93 @@ width: 100%; } + &.dx-diagram-fullscreen { + left: 0; + top: 0; + width: 100% !important; // stylelint-disable-line declaration-no-important + height: 100% !important; // stylelint-disable-line declaration-no-important + position: fixed; + z-index: 2; + } + + .dxdi-canvas { // stylelint-disable-line selector-class-pattern + overflow: hidden; + } +} + +.dx-diagram-toolbox-popup { + &.dx-popup-wrapper .dx-overlay-content { + border-radius: 0; + } + + .dx-popup-title.dx-toolbar { + padding: 0; + background-color: rgba(0, 0, 0, 0.05); + } + + .dx-popup-title .dx-button.dx-button-has-icon:not(.dx-button-has-text), + .dx-popup-title .dx-button-content { + background-color: transparent; + border: 0; + border-radius: 0; + padding: 0; + min-width: 0; + } + + .dx-popup-title .dx-button:not(.dx-closebutton) { + cursor: inherit; + pointer-events: none; + } + + .dx-popup-content { + padding: 0; + + .dx-diagram-toolbox-input { + width: 100%; + border: 0; + } + + .dx-diagram-toolbox-input input, + .dx-diagram-toolbox-input .dx-placeholder:before { + min-height: 0; + font-size: 0.9em; + } + + .dx-diagram-toolbox-input .dx-button { + border: 0; + border-radius: 0; + min-height: 14px; + } + + .dx-diagram-toolbox-panel { + position: relative; + height: 100%; + width: 100%; + overflow-y: auto; + + & > * { + position: absolute; + } + + & > .dx-scrollview { + width: 100%; + } + } + } +} + +.dx-diagram-floating-toolbar-container { + position: absolute; + z-index: 1000; + width: 100%; + + .dx-diagram-toolbar .dx-toolbar-items-container > * { + padding-left: 0; + padding-right: 0; + } +} + +.dx-diagram-toolbar { .dx-diagram-toolbar-separator { height: 100%; border-left: @TRANSPARENT_BORDER; @@ -79,19 +155,6 @@ content: none; } } - - &.dx-diagram-fullscreen { - left: 0; - top: 0; - width: 100% !important; // stylelint-disable-line declaration-no-important - height: 100% !important; // stylelint-disable-line declaration-no-important - position: fixed; - z-index: 2; - } - - .dxdi-canvas { // stylelint-disable-line selector-class-pattern - overflow: hidden; - } } .dx-diagram-toolbar, diff --git a/styles/widgets/common/dropDownEditor.less b/styles/widgets/common/dropDownEditor.less index f9f9141d4fed..581384fbf890 100644 --- a/styles/widgets/common/dropDownEditor.less +++ b/styles/widgets/common/dropDownEditor.less @@ -58,8 +58,8 @@ white-space: nowrap; } - .dx-rtl &, - .dx-rtl& { + .dx-rtl&, + .dx-rtl & { float: left; } } diff --git a/styles/widgets/common/fileManager.less b/styles/widgets/common/fileManager.less index ebf66605f5f0..0786445468df 100644 --- a/styles/widgets/common/fileManager.less +++ b/styles/widgets/common/fileManager.less @@ -28,7 +28,7 @@ .dx-filemanager-notification-popup { & > .dx-overlay-content { - min-width: 400px; + min-width: 240px; max-width: 400px; } @@ -101,7 +101,6 @@ } .dx-filemanager-progress-box-image { - font-size: 30px; margin-right: 10px; } @@ -111,6 +110,10 @@ .dx-filemanager-progress-box-common { padding: 5px 0; + max-width: 330px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; } .dx-filemanager-progress-box-progress-bar { @@ -122,6 +125,7 @@ } .dx-filemanager-progress-box-close-button { + margin-top: 9px; margin-left: 5px; } } @@ -134,6 +138,8 @@ font-size: 0.85em; line-height: normal; word-wrap: break-word; + overflow-y: auto; + max-height: 150px; } .dx-filemanager-toolbar { @@ -231,7 +237,7 @@ float: right; .dx-button-content { - padding: 10px 14px; + padding: 0; } } @@ -392,11 +398,6 @@ } } - .dx-filemanager-file-actions-button { - margin-top: 1px; - margin-bottom: -1px; - } - .dx-filemanager-focused-item .dx-filemanager-file-actions-button, .dx-treeview-item.dx-state-hover .dx-filemanager-file-actions-button { visibility: visible; diff --git a/styles/widgets/common/menu.less b/styles/widgets/common/menu.less index 89cd8a37861a..176102afc7b3 100644 --- a/styles/widgets/common/menu.less +++ b/styles/widgets/common/menu.less @@ -56,8 +56,8 @@ left: auto; right: 0; - .dx-rtl &, - .dx-rtl& { + .dx-rtl&, + .dx-rtl & { left: 0; right: auto; } @@ -73,8 +73,8 @@ .dx-item-content { padding-left: 15px; - .dx-rtl &, - .dx-rtl& { + .dx-rtl&, + .dx-rtl & { padding-right: 15px; } } diff --git a/styles/widgets/common/radioGroup.less b/styles/widgets/common/radioGroup.less index abe61c197658..e2a309c10403 100644 --- a/styles/widgets/common/radioGroup.less +++ b/styles/widgets/common/radioGroup.less @@ -11,8 +11,8 @@ padding-left: 5px; vertical-align: middle; - .dx-rtl &, - .dx-rtl& { + .dx-rtl&, + .dx-rtl & { padding-right: 5px; padding-left: 10px; } @@ -24,8 +24,8 @@ .dx-radiobutton { float: left; - .dx-rtl &, - .dx-rtl& { + .dx-rtl&, + .dx-rtl & { float: right; } } diff --git a/styles/widgets/common/splitter.less b/styles/widgets/common/splitter.less index 6e7f6356c942..751955ca9cfd 100644 --- a/styles/widgets/common/splitter.less +++ b/styles/widgets/common/splitter.less @@ -12,7 +12,6 @@ .dx-splitter-border { z-index: 997; height: 100%; - display: table; width: 7px; cursor: col-resize; diff --git a/styles/widgets/generic/autocomplete.generic.less b/styles/widgets/generic/autocomplete.generic.less index 5b80353a74d2..d5dc4a5d7ec2 100644 --- a/styles/widgets/generic/autocomplete.generic.less +++ b/styles/widgets/generic/autocomplete.generic.less @@ -9,8 +9,8 @@ .autocomplete-badge-offset() { right: @GENERIC_INVALID_BADGE_HORIZONTAL_PADDING; - .dx-rtl &, - .dx-rtl& { + .dx-rtl&, + .dx-rtl & { left: @GENERIC_INVALID_BADGE_HORIZONTAL_PADDING; } } diff --git a/styles/widgets/generic/checkBox.generic.less b/styles/widgets/generic/checkBox.generic.less index d507f094574e..3a99429e864e 100644 --- a/styles/widgets/generic/checkBox.generic.less +++ b/styles/widgets/generic/checkBox.generic.less @@ -53,14 +53,14 @@ background-color: @checkbox-bg; .dx-checkbox-checked & { - .dx-icon-check; + .dx-icon(check); color: @checkbox-checked-color; .dx-icon-font-centered-sizing(@GENERIC_CHECKBOX_ARROW_ICON_SIZE); } .dx-checkbox-indeterminate & { - .dx-icon-square; + .dx-icon(square); color: @checkbox-indeterminate-bg; .dx-icon-font-centered-sizing(@GENERIC_CHECKBOX_INTERMIDIATE_ICON_SIZE); @@ -71,8 +71,8 @@ margin-left: -@GENERIC_CHECKBOX_SIZE; padding-left: @GENERIC_CHECKBOX_SIZE + 5px; - .dx-rtl &, - .dx-rtl& { + .dx-rtl&, + .dx-rtl & { margin-right: -@GENERIC_CHECKBOX_SIZE; padding-right: @GENERIC_CHECKBOX_SIZE + 5px; } diff --git a/styles/widgets/generic/color-schemes/carmine/generic.carmine.less b/styles/widgets/generic/color-schemes/carmine/generic.carmine.less index 5222d87dc5ff..cac96822d236 100644 --- a/styles/widgets/generic/color-schemes/carmine/generic.carmine.less +++ b/styles/widgets/generic/color-schemes/carmine/generic.carmine.less @@ -114,12 +114,24 @@ @base-inverted-icon-color: @base-inverted-text-color; @base-disabled-opacity: 0.5; @base-dropdown-shadow-color: fade(@base-shadow-color, 17.5%); - +@base-invalid-color: @base-danger; +@base-invalid-faded-border-color: fade(@base-invalid-color, 40%); @base-header-color: #627789; +/** +* @name 70. Border radius +* @type text +*/ +@base-border-radius-small: @base-border-radius - 1px; + +/** +* @name 30. Border radius +* @type text +*/ +@base-border-radius-large: @base-border-radius + 2px; + // Validation -@base-invalid-color: @base-danger; @VALIDATION_MESSAGE_COLOR: @base-inverted-text-color; @VALIDATION_MESSAGE_BACKGROUND_COLOR: @base-invalid-color; @@ -127,7 +139,6 @@ @VALIDATION_SUMMARY_COLOR: @base-invalid-color; @validation-overlay-border-radius: @base-border-radius; -@base-invalid-faded-border-color: fade(@base-invalid-color, 40%); // Badges @@ -142,8 +153,6 @@ * @type color */ @badge-bg: #ff5f42; -@badge-invalid-bg: @base-invalid-color; - // TextEditor @@ -196,12 +205,6 @@ @texteditor-border-radius: @base-border-radius; @texteditor-input-border-radius: @base-border-radius; -/** -* @name 70. Border radius -* @type text -*/ -@base-border-radius-small: @base-border-radius - 1px; - // TextBox /** @@ -401,7 +404,7 @@ // ButtonGroup -// Normal Button +// Normal Button (ButtonGroup) /** * @name 10. Selected item text color @@ -422,7 +425,7 @@ @button-group-normal-selected-bg-hover: fade(@button-group-normal-selected-bg, 11%); @button-group-normal-selected-bg-focused: fade(@button-group-normal-selected-bg, 14%); -// Default Button +// Default Button (ButtonGroup) /** * @name 10. Selected item text color @@ -439,7 +442,7 @@ @button-group-default-selected-bg-hover: fade(@button-group-default-selected-bg, 20%); @button-group-default-selected-bg-focused: fade(@button-group-default-selected-bg, 20%); -// Danger Button +// Danger Button (ButtonGroup) /** * @name 10. Selected item text color @@ -456,7 +459,7 @@ @button-group-danger-selected-bg-hover: fade(@button-group-danger-selected-bg, 20%); @button-group-danger-selected-bg-focused: fade(@button-group-danger-selected-bg, 20%); -// Success Button +// Success Button (ButtonGroup) /** * @name 10. Selected item text color @@ -665,12 +668,6 @@ */ @overlay-shader-bg: fade(@base-bg, 80%); -/** -* @name 30. Border radius -* @type text -*/ -@base-border-radius-large: @base-border-radius + 2px; - // Popup /** diff --git a/styles/widgets/generic/color-schemes/contrast/generic.contrast.less b/styles/widgets/generic/color-schemes/contrast/generic.contrast.less index 51487f431dbd..063de6b6879f 100644 --- a/styles/widgets/generic/color-schemes/contrast/generic.contrast.less +++ b/styles/widgets/generic/color-schemes/contrast/generic.contrast.less @@ -48,14 +48,20 @@ @typography-link-color: @base-link-color; @base-disabled-opacity: 0.5; -// Validation - /** * @name 1. Invalid widget state - active color * @type color */ @base-invalid-color: #EA4444; +/** +* @name 2. Invalid widget state - border color +* @type color +*/ +@base-invalid-faded-border-color: @base-invalid-color; + +// Validation + @VALIDATION_MESSAGE_COLOR: @base-text-color; @VALIDATION_MESSAGE_BACKGROUND_COLOR: @base-invalid-color; @@ -65,12 +71,6 @@ @datagrid-row-hovered-color: @base-text-color; -/** -* @name 2. Invalid widget state - border color -* @type color -*/ -@base-invalid-faded-border-color: @base-invalid-color; - /** * @name 20. Label color * @type color @@ -86,7 +86,6 @@ * @type color */ @badge-color: @base-inverted-text-color; -@badge-invalid-bg: @base-invalid-color; /** * @name 20. Badge background color @@ -1005,7 +1004,7 @@ */ @datagrid-cell-modified-border-color: @base-text-color; -@datagrid-row-removed-bg: @base-text-color; +@datagrid-row-removed-bg: fade(@base-success, 50%); /** * @name 73. Invalidate data faded color @@ -1198,7 +1197,7 @@ */ @treelist-cell-modified-border-color: @base-text-color; -@treelist-row-removed-bg: @base-text-color; +@treelist-row-removed-bg: fade(@base-success, 50%); /** * @name 73. Invalidate data faded color diff --git a/styles/widgets/generic/color-schemes/dark/generic.dark.less b/styles/widgets/generic/color-schemes/dark/generic.dark.less index d7d5a47537e1..a3071ac420b1 100644 --- a/styles/widgets/generic/color-schemes/dark/generic.dark.less +++ b/styles/widgets/generic/color-schemes/dark/generic.dark.less @@ -7,46 +7,46 @@ @base-font-family: 'Helvetica Neue', 'Segoe UI', Helvetica, Verdana, sans-serif; /** -* @name 20. Label color +* @name 10. Accent color * @type color */ -@base-label-color: @base-text-color; +@base-accent: #1ca8dd; /** -* @name 30. Link color +* @name 20. Text color * @type color */ -@base-link-color: @base-accent; +@base-text-color: #dedede; /** -* @name 40. Icon color +* @name 30. Background color * @type color */ -@base-icon-color: @base-text-color; +@base-bg: #2a2a2a; /** -* @name 10. Accent color +* @name 40. Border color * @type color */ -@base-accent: #1ca8dd; +@base-border-color: #4d4d4d; /** -* @name 20. Text color +* @name 20. Label color * @type color */ -@base-text-color: #dedede; +@base-label-color: @base-text-color; /** -* @name 30. Background color +* @name 30. Link color * @type color */ -@base-bg: #2a2a2a; +@base-link-color: @base-accent; /** -* @name 40. Border color +* @name 40. Icon color * @type color */ -@base-border-color: #4d4d4d; +@base-icon-color: @base-text-color; /** * @name 120. Border radius @@ -113,16 +113,28 @@ @base-inverted-icon-color: @base-inverted-text-color; @base-disabled-opacity: 0.5; @base-dropdown-shadow-color: fade(@base-shadow-color, 17.5%); +@base-invalid-color: @base-danger; +@base-invalid-faded-border-color: fade(@base-invalid-color, 40%); + +/** +* @name 80. Border radius +* @type text +*/ +@base-border-radius-small: @base-border-radius - 1px; + +/** +* @name 30. Border radius +* @type text +*/ +@base-border-radius-large: @base-border-radius + 2px; // Validation -@base-invalid-color: @base-danger; @VALIDATION_MESSAGE_COLOR: @base-inverted-text-color; @VALIDATION_MESSAGE_BACKGROUND_COLOR: @base-invalid-color; @VALIDATION_SUMMARY_COLOR: @base-invalid-color; @validation-overlay-border-radius: @base-border-radius; -@base-invalid-faded-border-color: fade(@base-invalid-color, 40%); // Badges @@ -137,7 +149,6 @@ * @type color */ @badge-bg: @base-accent; -@badge-invalid-bg: @base-invalid-color; // TextEditor @@ -197,12 +208,6 @@ @texteditor-border-radius: @base-border-radius; @texteditor-input-border-radius: @base-border-radius; -/** -* @name 80. Border radius -* @type text -*/ -@base-border-radius-small: @base-border-radius - 1px; - // TextBox /** @@ -402,7 +407,7 @@ // ButtonGroup -// Normal Button +// Normal Button (ButtonGroup) /** * @name 10. Selected item text color @@ -423,7 +428,7 @@ @button-group-normal-selected-bg-hover: fade(@button-group-normal-selected-bg, 11%); @button-group-normal-selected-bg-focused: fade(@button-group-normal-selected-bg, 14%); -// Default Button +// Default Button (ButtonGroup) /** * @name 10. Selected item text color @@ -440,7 +445,7 @@ @button-group-default-selected-bg-hover: fade(@button-group-default-selected-bg, 20%); @button-group-default-selected-bg-focused: fade(@button-group-default-selected-bg, 20%); -// Danger Button +// Danger Button (ButtonGroup) /** * @name 10. Selected item text color @@ -457,7 +462,7 @@ @button-group-danger-selected-bg-hover: fade(@button-group-danger-selected-bg, 20%); @button-group-danger-selected-bg-focused: fade(@button-group-danger-selected-bg, 20%); -// Success Button +// Success Button (ButtonGroup) /** * @name 10. Selected item text color @@ -666,12 +671,6 @@ */ @overlay-shader-bg: fade(@base-bg, 80%); -/** -* @name 30. Border radius -* @type text -*/ -@base-border-radius-large: @base-border-radius + 2px; - // Popup /** @@ -1072,7 +1071,7 @@ * @name 55. Selected row background color * @type color */ -@datagrid-selection-bg: @base-select-bg; +@datagrid-selection-bg: #444; /** * @name 60. Selected row border color diff --git a/styles/widgets/generic/color-schemes/darkmoon/generic.darkmoon.less b/styles/widgets/generic/color-schemes/darkmoon/generic.darkmoon.less index dadb92e24a58..de907e5cfe03 100644 --- a/styles/widgets/generic/color-schemes/darkmoon/generic.darkmoon.less +++ b/styles/widgets/generic/color-schemes/darkmoon/generic.darkmoon.less @@ -12,12 +12,6 @@ */ @base-label-color: #c1c7c9; -/** -* @name 30. Link color -* @type color -*/ -@base-link-color: @base-accent; - /** * @name 40. Icon color * @type color @@ -36,6 +30,12 @@ */ @base-text-color: #fff; +/** +* @name 30. Link color +* @type color +*/ +@base-link-color: @base-accent; + /** * @name 30. Background color * @type color @@ -106,8 +106,6 @@ */ @base-focus-bg: @base-accent; -@base-border-radius-exsmall: @base-border-radius - 2px; - @base-inverted-bg: darken(@base-bg, 100%); @base-element-bg: @base-bg; @base-shadow-color: @base-inverted-bg; @@ -119,6 +117,20 @@ @base-inverted-icon-color: @base-inverted-text-color; @base-disabled-opacity: 0.5; @base-dropdown-shadow-color: fade(darken(@base-shadow-color, 100%), 17.5%); +@base-invalid-color: @base-danger; +@base-invalid-faded-border-color: fade(@base-invalid-color, 40%); + +/** +* @name 80. Border radius +* @type text +*/ +@base-border-radius-small: @base-border-radius - 1px; + +/** +* @name 30. Border radius +* @type text +*/ +@base-border-radius-large: @base-border-radius + 2px; // Badges @@ -134,21 +146,17 @@ * @type color */ @badge-bg: lighten(@base-accent, 25%); -@badge-invalid-bg: @base-invalid-color; @screen-text-color: screen(@base-bg, #686868); @base-grid-selected-border-color: #45c7de; // Validation -@base-invalid-color: @base-danger; @VALIDATION_MESSAGE_COLOR: @base-inverted-text-color; @VALIDATION_MESSAGE_BACKGROUND_COLOR: @base-invalid-color; - @VALIDATION_SUMMARY_COLOR: @base-invalid-color; - @validation-overlay-border-radius: @base-border-radius; -@base-invalid-faded-border-color: fade(@base-invalid-color, 40%); + // TextEditor @@ -206,12 +214,6 @@ @texteditor-border-radius: @base-border-radius; @texteditor-input-border-radius: @base-border-radius; -/** -* @name 80. Border radius -* @type text -*/ -@base-border-radius-small: @base-border-radius - 1px; - // TextBox /** @@ -413,7 +415,7 @@ // ButtonGroup -// Normal Button +// Normal Button (ButtonGroup) /** * @name 10. Selected item text color @@ -434,7 +436,7 @@ @button-group-normal-selected-bg-hover: fade(@button-group-normal-selected-bg, 11%); @button-group-normal-selected-bg-focused: fade(@button-group-normal-selected-bg, 14%); -// Default Button +// Default Button (ButtonGroup) /** * @name 10. Selected item text color @@ -451,7 +453,7 @@ @button-group-default-selected-bg-hover: fade(@button-group-default-selected-bg, 20%); @button-group-default-selected-bg-focused: fade(@button-group-default-selected-bg, 20%); -// Danger Button +// Danger Button (ButtonGroup) /** * @name 10. Selected item text color @@ -468,7 +470,7 @@ @button-group-danger-selected-bg-hover: fade(@button-group-danger-selected-bg, 20%); @button-group-danger-selected-bg-focused: fade(@button-group-danger-selected-bg, 20%); -// Success Button +// Success Button (ButtonGroup) /** * @name 10. Selected item text color @@ -674,12 +676,6 @@ */ @overlay-shader-bg: fade(@base-bg, 80%); -/** -* @name 30. Border radius -* @type text -*/ -@base-border-radius-large: @base-border-radius + 2px; - // Popup /** diff --git a/styles/widgets/generic/color-schemes/darkviolet/generic.darkviolet.less b/styles/widgets/generic/color-schemes/darkviolet/generic.darkviolet.less index eb3f53054778..202eda6e952d 100644 --- a/styles/widgets/generic/color-schemes/darkviolet/generic.darkviolet.less +++ b/styles/widgets/generic/color-schemes/darkviolet/generic.darkviolet.less @@ -6,12 +6,6 @@ */ @base-font-family: 'Helvetica Neue', 'Segoe UI', Helvetica, Verdana, sans-serif; -/** -* @name 20. Label color -* @type color -*/ -@base-label-color: @base-text-color; - /** * @name 30. Link color * @type color @@ -36,6 +30,12 @@ */ @base-text-color: #f5f6f7; +/** +* @name 20. Label color +* @type color +*/ +@base-label-color: @base-text-color; + /** * @name 30. Background color * @type color @@ -118,15 +118,27 @@ @base-selected-border: #6c48a8; @base-accent-highlight-color: #6b2bd9; @base-dropdown-shadow-color: fade(@base-shadow-color, 17.5%); +@base-invalid-color: @base-danger; +@base-invalid-faded-border-color: fade(@base-invalid-color, 40%); + +/** +* @name 80. Border radius +* @type text +*/ +@base-border-radius-small: @base-border-radius - 1px; + +/** +* @name 30. Border radius +* @type text +*/ +@base-border-radius-large: @base-border-radius + 2px; // Validation -@base-invalid-color: @base-danger; @VALIDATION_MESSAGE_COLOR: @base-inverted-text-color; @VALIDATION_MESSAGE_BACKGROUND_COLOR: @base-invalid-color; @VALIDATION_SUMMARY_COLOR: @base-invalid-color; @validation-overlay-border-radius: @base-border-radius; -@base-invalid-faded-border-color: fade(@base-invalid-color, 40%); // Badges @@ -141,7 +153,6 @@ * @type color */ @badge-bg: @base-accent-highlight-color; -@badge-invalid-bg: @base-invalid-color; // TextEditor @@ -200,12 +211,6 @@ @texteditor-border-radius: @base-border-radius; @texteditor-input-border-radius: @base-border-radius; -/** -* @name 80. Border radius -* @type text -*/ -@base-border-radius-small: @base-border-radius - 1px; - // TextBox /** @@ -405,7 +410,7 @@ // ButtonGroup -// Normal Button +// Normal Button (ButtonGroup) /** * @name 10. Selected item text color @@ -426,7 +431,7 @@ @button-group-normal-selected-bg-hover: fade(@button-group-normal-selected-bg, 11%); @button-group-normal-selected-bg-focused: fade(@button-group-normal-selected-bg, 14%); -// Default Button +// Default Button (ButtonGroup) /** * @name 10. Selected item text color @@ -443,7 +448,7 @@ @button-group-default-selected-bg-hover: fade(@button-group-default-selected-bg, 20%); @button-group-default-selected-bg-focused: fade(@button-group-default-selected-bg, 20%); -// Danger Button +// Danger Button (ButtonGroup) /** * @name 10. Selected item text color @@ -460,7 +465,7 @@ @button-group-danger-selected-bg-hover: fade(@button-group-danger-selected-bg, 20%); @button-group-danger-selected-bg-focused: fade(@button-group-danger-selected-bg, 20%); -// Success Button +// Success Button (ButtonGroup) /** * @name 10. Selected item text color @@ -669,12 +674,6 @@ */ @overlay-shader-bg: fade(@base-bg, 80%); -/** -* @name 30. Border radius -* @type text -*/ -@base-border-radius-large: @base-border-radius + 2px; - // Popup /** diff --git a/styles/widgets/generic/color-schemes/greenmist/generic.greenmist.less b/styles/widgets/generic/color-schemes/greenmist/generic.greenmist.less index ce078cd59212..d6dd1248eae5 100644 --- a/styles/widgets/generic/color-schemes/greenmist/generic.greenmist.less +++ b/styles/widgets/generic/color-schemes/greenmist/generic.greenmist.less @@ -115,19 +115,27 @@ @base-inverted-icon-color: @base-inverted-text-color; @base-disabled-opacity: 0.5; @base-dropdown-shadow-color: fade(@base-shadow-color, 17.5%); +@base-invalid-color: @base-danger; +@base-invalid-faded-border-color: fade(@base-invalid-color, 40%); +/** +* @name 80. Border radius +* @type text +*/ +@base-border-radius-small: @base-border-radius - 1px; -// Validation +/** +* @name 30. Border radius +* @type text +*/ +@base-border-radius-large: @base-border-radius + 2px; -@base-invalid-color: @base-danger; +// Validation @VALIDATION_MESSAGE_COLOR: @base-inverted-text-color; @VALIDATION_MESSAGE_BACKGROUND_COLOR: @base-invalid-color; - @VALIDATION_SUMMARY_COLOR: @base-invalid-color; - @validation-overlay-border-radius: @base-border-radius; -@base-invalid-faded-border-color: fade(@base-invalid-color, 40%); // Badges @@ -142,7 +150,6 @@ * @type color */ @badge-bg: #23ada4; -@badge-invalid-bg: @base-invalid-color; // TextEditor @@ -201,12 +208,6 @@ @texteditor-border-radius: @base-border-radius; @texteditor-input-border-radius: @base-border-radius; -/** -* @name 80. Border radius -* @type text -*/ -@base-border-radius-small: @base-border-radius - 1px; - // TextBox /** @@ -406,7 +407,7 @@ // ButtonGroup -// Normal Button +// Normal Button (ButtonGroup) /** * @name 10. Selected item text color @@ -427,7 +428,7 @@ @button-group-normal-selected-bg-hover: fade(@button-group-normal-selected-bg, 11%); @button-group-normal-selected-bg-focused: fade(@button-group-normal-selected-bg, 14%); -// Default Button +// Default Button (ButtonGroup) /** * @name 10. Selected item text color @@ -444,7 +445,7 @@ @button-group-default-selected-bg-hover: fade(@button-group-default-selected-bg, 20%); @button-group-default-selected-bg-focused: fade(@button-group-default-selected-bg, 20%); -// Danger Button +// Danger Button (ButtonGroup) /** * @name 10. Selected item text color @@ -461,7 +462,7 @@ @button-group-danger-selected-bg-hover: fade(@button-group-danger-selected-bg, 20%); @button-group-danger-selected-bg-focused: fade(@button-group-danger-selected-bg, 20%); -// Success Button +// Success Button (ButtonGroup) /** * @name 10. Selected item text color @@ -670,12 +671,6 @@ */ @overlay-shader-bg: fade(@base-bg, 80%); -/** -* @name 30. Border radius -* @type text -*/ -@base-border-radius-large: @base-border-radius + 2px; - // Popup /** diff --git a/styles/widgets/generic/color-schemes/light/generic.light.less b/styles/widgets/generic/color-schemes/light/generic.light.less index a4954eb4c5bf..7129b448fc66 100644 --- a/styles/widgets/generic/color-schemes/light/generic.light.less +++ b/styles/widgets/generic/color-schemes/light/generic.light.less @@ -7,34 +7,34 @@ @base-font-family: 'Helvetica Neue', 'Segoe UI', Helvetica, Verdana, sans-serif; /** -* @name 20. Label color +* @name 10. Accent color * @type color */ -@base-label-color: @base-text-color; +@base-accent: #337ab7; /** -* @name 30. Link color +* @name 20. Text color * @type color */ -@base-link-color: @base-accent; +@base-text-color: #333; /** -* @name 40. Icon color +* @name 20. Label color * @type color */ -@base-icon-color: @base-text-color; +@base-label-color: @base-text-color; /** -* @name 10. Accent color +* @name 30. Link color * @type color */ -@base-accent: #337ab7; +@base-link-color: @base-accent; /** -* @name 20. Text color +* @name 40. Icon color * @type color */ -@base-text-color: #333; +@base-icon-color: @base-text-color; /** * @name 30. Background color @@ -115,16 +115,27 @@ @base-inverted-icon-color: @base-inverted-text-color; @base-disabled-opacity: 0.5; @base-dropdown-shadow-color: fade(@base-shadow-color, 17.5%); +@base-invalid-color: @base-danger; +@base-invalid-faded-border-color: fade(@base-invalid-color, 40%); + +/** +* @name 80. Border radius +* @type text +*/ +@base-border-radius-small: @base-border-radius - 1px; + +/** +* @name 30. Border radius +* @type text +*/ +@base-border-radius-large: @base-border-radius + 2px; // Validation -@base-invalid-color: @base-danger; @VALIDATION_MESSAGE_COLOR: @base-inverted-text-color; @VALIDATION_MESSAGE_BACKGROUND_COLOR: @base-invalid-color; @VALIDATION_SUMMARY_COLOR: @base-invalid-color; - @validation-overlay-border-radius: @base-border-radius; -@base-invalid-faded-border-color: fade(@base-invalid-color, 40%); // Badges @@ -139,7 +150,6 @@ * @type color */ @badge-bg: @base-accent; -@badge-invalid-bg: @base-invalid-color; // TextEditor @@ -197,12 +207,6 @@ @texteditor-border-radius: @base-border-radius; @texteditor-input-border-radius: @base-border-radius; -/** -* @name 80. Border radius -* @type text -*/ -@base-border-radius-small: @base-border-radius - 1px; - // TextBox /** @@ -402,7 +406,7 @@ // ButtonGroup -// Normal Button +// Normal Button (ButtonGroup) /** * @name 10. Selected item text color @@ -423,7 +427,7 @@ @button-group-normal-selected-bg-hover: fade(@button-group-normal-selected-bg, 11%); @button-group-normal-selected-bg-focused: fade(@button-group-normal-selected-bg, 14%); -// Default Button +// Default Button (ButtonGroup) /** * @name 10. Selected item text color @@ -440,7 +444,7 @@ @button-group-default-selected-bg-hover: fade(@button-group-default-selected-bg, 20%); @button-group-default-selected-bg-focused: fade(@button-group-default-selected-bg, 20%); -// Danger Button +// Danger Button (ButtonGroup) /** * @name 10. Selected item text color @@ -457,7 +461,7 @@ @button-group-danger-selected-bg-hover: fade(@button-group-danger-selected-bg, 20%); @button-group-danger-selected-bg-focused: fade(@button-group-danger-selected-bg, 20%); -// Success Button +// Success Button (ButtonGroup) /** * @name 10. Selected item text color @@ -665,12 +669,6 @@ */ @overlay-shader-bg: fade(@base-bg, 80%); -/** -* @name 30. Border radius -* @type text -*/ -@base-border-radius-large: @base-border-radius + 2px; - // Popup /** @@ -1067,7 +1065,7 @@ * @name 55. Selected row background color * @type color */ -@datagrid-selection-bg: @base-select-bg; +@datagrid-selection-bg: #e6e6e6; /** * @name 60. Selected row border color diff --git a/styles/widgets/generic/color-schemes/softblue/generic.softblue.less b/styles/widgets/generic/color-schemes/softblue/generic.softblue.less index f6730e252c38..0269a9162964 100644 --- a/styles/widgets/generic/color-schemes/softblue/generic.softblue.less +++ b/styles/widgets/generic/color-schemes/softblue/generic.softblue.less @@ -7,34 +7,34 @@ @base-font-family: 'Helvetica Neue', 'Segoe UI', Helvetica, Verdana, sans-serif; /** -* @name 20. Label color +* @name 40. Icon color * @type color */ -@base-label-color: #8c8c8c; +@base-icon-color: #99a1a8; /** -* @name 30. Link color +* @name 10. Accent color * @type color */ -@base-link-color: @base-accent; +@base-accent: #7ab8eb; /** -* @name 40. Icon color +* @name 20. Text color * @type color */ -@base-icon-color: #99a1a8; +@base-text-color: #333; /** -* @name 10. Accent color +* @name 20. Label color * @type color */ -@base-accent: #7ab8eb; +@base-label-color: #8c8c8c; /** -* @name 20. Text color +* @name 30. Link color * @type color */ -@base-text-color: #333; +@base-link-color: @base-accent; /** * @name 30. Background color @@ -106,8 +106,6 @@ */ @base-focus-bg: @base-accent; -@base-border-radius-exsmall: @base-border-radius - 2px; - @base-inverted-bg: darken(@base-bg, 100%); @base-element-bg: @base-bg; @base-shadow-color: @base-inverted-bg; @@ -122,16 +120,27 @@ @base-grid-selection-background: #d1e0ed; @base-grid-selectedrow-border-color: #e1ecf5; @base-dropdown-shadow-color: fade(@base-shadow-color, 17.5%); +@base-invalid-color: @base-danger; +@base-invalid-faded-border-color: fade(@base-invalid-color, 40%); + +/** +* @name 80. Border radius +* @type text +*/ +@base-border-radius-small: @base-border-radius - 1px; + +/** +* @name 30. Border radius +* @type text +*/ +@base-border-radius-large: @base-border-radius + 2px; // Validation -@base-invalid-color: @base-danger; @VALIDATION_MESSAGE_COLOR: @base-inverted-text-color; @VALIDATION_MESSAGE_BACKGROUND_COLOR: @base-invalid-color; @VALIDATION_SUMMARY_COLOR: @base-invalid-color; - @validation-overlay-border-radius: @base-border-radius; -@base-invalid-faded-border-color: fade(@base-invalid-color, 40%); // Badges @@ -146,7 +155,6 @@ * @type color */ @badge-bg: difference(@base-accent, #171717); // #7ab8eb => #60a1d6 -@badge-invalid-bg: @base-invalid-color; // TextEditor @@ -206,12 +214,6 @@ @texteditor-border-radius: @base-border-radius; @texteditor-input-border-radius: @base-border-radius; -/** -* @name 80. Border radius -* @type text -*/ -@base-border-radius-small: @base-border-radius - 1px; - // TextBox /** @@ -412,7 +414,7 @@ // ButtonGroup -// Normal Button +// Normal Button (ButtonGroup) /** * @name 10. Selected item text color @@ -433,7 +435,7 @@ @button-group-normal-selected-bg-hover: fade(@button-group-normal-selected-bg, 11%); @button-group-normal-selected-bg-focused: fade(@button-group-normal-selected-bg, 14%); -// Default Button +// Default Button (ButtonGroup) /** * @name 10. Selected item text color @@ -450,7 +452,7 @@ @button-group-default-selected-bg-hover: fade(@button-group-default-selected-bg, 20%); @button-group-default-selected-bg-focused: fade(@button-group-default-selected-bg, 20%); -// Danger Button +// Danger Button (ButtonGroup) /** * @name 10. Selected item text color @@ -467,7 +469,7 @@ @button-group-danger-selected-bg-hover: fade(@button-group-danger-selected-bg, 20%); @button-group-danger-selected-bg-focused: fade(@button-group-danger-selected-bg, 20%); -// Success Button +// Success Button (ButtonGroup) /** * @name 10. Selected item text color @@ -676,12 +678,6 @@ */ @overlay-shader-bg: fade(@base-bg, 80%); -/** -* @name 30. Border radius -* @type text -*/ -@base-border-radius-large: @base-border-radius + 2px; - // Popup /** diff --git a/styles/widgets/generic/colorView.generic.less b/styles/widgets/generic/colorView.generic.less index ac9b2d958677..6be66559df0b 100644 --- a/styles/widgets/generic/colorView.generic.less +++ b/styles/widgets/generic/colorView.generic.less @@ -2,6 +2,8 @@ @import (once) "./numberBox.generic.less"; @import (once) "./textBox.generic.less"; +.dx-base-colorview-styles(@COLORVIEW_HANDLE_COLOR, @COLORVIEW_HANDLE_BORDER_COLOR); + .dx-size-default() { @GENERIC_COLORVIEW_CONTAINER_WIDTH: 450px; @GENERIC_COLORVIEW_PALETTE_WIDTH: 288px; diff --git a/styles/widgets/generic/common.generic.less b/styles/widgets/generic/common.generic.less index df9a2cbe0b12..855ff61e0f62 100644 --- a/styles/widgets/generic/common.generic.less +++ b/styles/widgets/generic/common.generic.less @@ -90,6 +90,7 @@ } @GENERIC_INVALID_BADGE_HORIZONTAL_PADDING: (@GENERIC_BASE_INLINE_BORDEREDWIDGET_INNER_SIZE - @GENERIC_INVALID_BADGE_SIZE) / 2; @GENERIC_INVALID_BADGE_HALFHORIZONTAL_PADDING: @GENERIC_INVALID_BADGE_HORIZONTAL_PADDING / 2; +@badge-invalid-bg: @base-invalid-color; .badge-settings() { diff --git a/styles/widgets/generic/contextMenu.generic.less b/styles/widgets/generic/contextMenu.generic.less index 9c5aae21c20c..954b432fbdfc 100644 --- a/styles/widgets/generic/contextMenu.generic.less +++ b/styles/widgets/generic/contextMenu.generic.less @@ -13,7 +13,7 @@ } .dx-menu-item-popout { - .dx-icon-spinright; + .dx-icon(spinright); .dx-icon-font-centered-sizing(@GENERIC_BASE_ICON_SIZE); } @@ -24,8 +24,8 @@ .dx-menu-no-icons > .dx-menu-item-wrapper > .dx-menu-item > .dx-menu-item-content .dx-menu-item-text { padding-left: @GENERIC_MENU_ITEM_PADDING_BASE; - .dx-rtl &, - .dx-rtl& { + .dx-rtl&, + .dx-rtl & { padding-right: @GENERIC_MENU_ITEM_PADDING_BASE; padding-left: @GENERIC_MENU_PADDING_BIG; } diff --git a/styles/widgets/generic/dataGrid.generic.less b/styles/widgets/generic/dataGrid.generic.less index acda015bec33..5e25c6ea4b1b 100644 --- a/styles/widgets/generic/dataGrid.generic.less +++ b/styles/widgets/generic/dataGrid.generic.less @@ -57,14 +57,14 @@ } .dx-datagrid-group-opened { - .dx-icon-spindown; + .dx-icon(spindown); .dx-icon-sizing(@GENERIC_BASE_ICON_SIZE); color: @datagrid-spin-icon-color; } .dx-datagrid-group-closed { - .dx-icon-spinright; + .dx-icon(spinright); .dx-icon-sizing(@GENERIC_BASE_ICON_SIZE); color: @datagrid-spin-icon-color; diff --git a/styles/widgets/generic/dateBox.generic.less b/styles/widgets/generic/dateBox.generic.less index e9e74915ad0c..d5fc2854a497 100644 --- a/styles/widgets/generic/dateBox.generic.less +++ b/styles/widgets/generic/dateBox.generic.less @@ -58,7 +58,7 @@ .dx-datebox-calendar { .dx-dropdowneditor-icon { - .dx-icon-event(); + .dx-icon(event); .dx-dropdowneditor-button-icon(); } @@ -146,7 +146,7 @@ .dx-datebox-list { .dx-dropdowneditor-icon { - .dx-icon-clock; + .dx-icon(clock); .dx-dropdowneditor-button-icon(); } } diff --git a/styles/widgets/generic/diagram.generic.less b/styles/widgets/generic/diagram.generic.less index 38e65f0cbe11..ed763fd257d7 100644 --- a/styles/widgets/generic/diagram.generic.less +++ b/styles/widgets/generic/diagram.generic.less @@ -7,6 +7,7 @@ @import (once) "./form.generic.less"; @import (once) "./toolbar.generic.less"; @import (once) "./contextMenu.generic.less"; +@import (once) "./overlay.generic.less"; @import (once) "./fileUploader.generic.less"; @import (once) "./popup.generic.less"; @@ -14,6 +15,24 @@ @DIAGRAM_TOOLBAR_COLORBUTTON_BORDER_WIDTH: 3px; @DIAGRAM_TOUCHBAR_ITEM_PADDING: 5px; +@DIAGRAM_TOOLBOX_TITLE_SIZE: 12px; + +.dx-size-default() { + @DIAGRAM_TOOLBOX_ACCORDION_H_PADDING: 8px; + @DIAGRAM_TOOLBOX_ACCORDION_V_PADDING: 6px; + @DIAGRAM_TOOLBOX_INPUT_H_PADDING: 8px; + @DIAGRAM_TOOLBOX_INPUT_V_PADDING: 6px; + @DIAGRAM_TOOLBOX_INPUT_IMAGE_SIZE: 12px; +} + +.dx-size-compact() { + @DIAGRAM_TOOLBOX_ACCORDION_H_PADDING: 6px; + @DIAGRAM_TOOLBOX_ACCORDION_V_PADDING: 4px; + @DIAGRAM_TOOLBOX_INPUT_H_PADDING: 6px; + @DIAGRAM_TOOLBOX_INPUT_V_PADDING: 4px; + @DIAGRAM_TOOLBOX_INPUT_IMAGE_SIZE: 10px; +} + .dx-diagram { border-color: @diagram-border-color; // stylelint-disable selector-class-pattern @@ -49,56 +68,132 @@ border-bottom: 1px solid @diagram-toolbar-border-color; } - .dx-diagram-left-panel, .dx-diagram-right-panel { - background: @overlay-content-bg; + border-left-color: @diagram-toolbar-border-color; + } - .dx-accordion { - .dx-accordion-item { - border-left: none; - border-right: none; + &.dx-diagram-fullscreen { + background-color: @base-bg; + } +} - .dx-diagram-right-panel-begin-group { - padding-top: 24px; - } - } +.dx-diagram-toolbox-panel, +.dx-diagram-right-panel { + background: @overlay-content-bg; + + .dx-accordion { + .dx-accordion-item { + border-left: none; + border-right: none; - .dx-accordion-item:first-of-type { - border-top: none; + .dx-diagram-right-panel-begin-group { + padding-top: 24px; } + } - .dx-state-focused { - &.dx-accordion-item { - border-color: @accordion-item-border-color; - } + .dx-state-focused { + &.dx-accordion-item { + border-color: @accordion-item-border-color; + } - &.dx-accordion-item-closed:not(:last-of-type) { - border-bottom-color: transparent; - } + &.dx-accordion-item-closed:not(:last-of-type) { + border-bottom-color: transparent; } } } +} - .dx-diagram-left-panel { - border-right-color: @diagram-toolbar-border-color; - - .dxdi-toolbox .dxdi-canvas .dxdi-shape-text { // stylelint-disable-line selector-class-pattern - opacity: @diagram-toolbox-shape-text-opacity; +.dx-diagram-right-panel { + .dx-accordion { + .dx-accordion-item:first-of-type { + border-top: none; } } +} - .dx-diagram-right-panel { - border-left-color: @diagram-toolbar-border-color; +.dx-diagram-floating-toolbar-container { + border: 1px solid @overlay-border-color; + background: @overlay-content-bg; + box-shadow: 0 6px 12px @overlay-content-shadow-color; + border-radius: @popup-border-radius; + padding: 2px; + + .dx-toolbar-item { + padding: 0 2px 0 0; } +} - &.dx-diagram-fullscreen { - background-color: @base-bg; +.dx-diagram-toolbox-popup { + .dx-popup-title.dx-toolbar { + font-size: 0.5em; + min-height: @DIAGRAM_TOOLBOX_TITLE_SIZE; + } + + .dx-popup-title.dx-toolbar .dx-toolbar-items-container { + height: @DIAGRAM_TOOLBOX_TITLE_SIZE; + } + + .dx-popup-title .dx-button.dx-button-has-icon:not(.dx-button-has-text), + .dx-popup-title .dx-button-content { + width: @DIAGRAM_TOOLBOX_TITLE_SIZE; + height: @DIAGRAM_TOOLBOX_TITLE_SIZE; + } + + .dx-diagram-toolbox-input .dx-button .dx-button-content { + padding: 2px; + } + + .dx-diagram-toolbox-input .dx-button .dx-icon { + font-size: @DIAGRAM_TOOLBOX_INPUT_IMAGE_SIZE; + } + + .dx-popup-title .dx-closebutton { + width: @DIAGRAM_TOOLBOX_TITLE_SIZE; + height: @DIAGRAM_TOOLBOX_TITLE_SIZE; + margin: 1px 0 0; + } + + .dx-popup-title .dx-closebutton .dx-icon { + width: 10px; + height: 10px; + padding: 1px; + font-size: 8px; + line-height: 8px; + background-position: 1px 1px; + background-size: 8px 8px; + } + + .dx-diagram-toolbox-input .dx-texteditor-input, + .dx-diagram-toolbox-input .dx-placeholder:before { + padding: @DIAGRAM_TOOLBOX_INPUT_V_PADDING @DIAGRAM_TOOLBOX_INPUT_H_PADDING; } } -.dx-diagram-toolbar { - background-color: transparent; +.dx-diagram-toolbox-panel { + .dxdi-toolbox .dxdi-canvas .dxdi-shape-text { // stylelint-disable-line selector-class-pattern + opacity: @diagram-toolbox-shape-text-opacity; + } + + .dx-item-content.dx-accordion-item-title { + padding: @DIAGRAM_TOOLBOX_ACCORDION_V_PADDING @DIAGRAM_TOOLBOX_ACCORDION_H_PADDING; + + .dx-accordion-item-title-caption { + font-size: 0.7em; + font-weight: bold; + } + + &::before { + font-size: 0.7em; + line-height: 1.5em; + } + } + .dx-item-content.dx-accordion-item-body { + padding: @DIAGRAM_TOOLBOX_ACCORDION_V_PADDING @DIAGRAM_TOOLBOX_ACCORDION_H_PADDING; + } +} + +.dx-diagram-toolbar { .dx-format-active:not(.dx-color-format):not(.dx-background-format) { background-color: @diagram-normal-format-active-bg; @@ -175,4 +270,11 @@ } } -.diagram-icons-mixin(@base-icon-color, @menu-color, @GENERIC_DIAGRAM_TOOLBAR_ICON_SIZE); +.diagram-action-icons-mixin(@base-icon-color, @menu-color, @GENERIC_DIAGRAM_TOOLBAR_ICON_SIZE); + +.dx-diagram-toolbox-popup .dx-button-has-icon .dx-icon.dx-icon-diagram-toolbox-drag { + .diagram-icon-colored(data-uri('image/svg+xml;charset=UTF-8', 'images/widgets/common/diagram/toolbox-drag.svg'), @popup-title-color, @DIAGRAM_TOOLBOX_TITLE_SIZE, @DIAGRAM_TOOLBOX_TITLE_SIZE); + + line-height: @DIAGRAM_TOOLBOX_TITLE_SIZE; + background-size: @DIAGRAM_TOOLBOX_TITLE_SIZE @DIAGRAM_TOOLBOX_TITLE_SIZE; +} diff --git a/styles/widgets/generic/dropDownEditor.generic.less b/styles/widgets/generic/dropDownEditor.generic.less index 88bee5ab76e2..899604cb40b6 100644 --- a/styles/widgets/generic/dropDownEditor.generic.less +++ b/styles/widgets/generic/dropDownEditor.generic.less @@ -58,7 +58,7 @@ .dx-dropdowneditor-icon { border: @GENERIC_BASE_BORDER_WIDTH solid transparent; color: @dropdowneditor-icon-color; - .dx-icon-spindown; + .dx-icon(spindown); .dx-dropdowneditor-button-icon(); } @@ -76,16 +76,21 @@ .dx-dropdowneditor-button-visible { .dx-texteditor-input { padding-right: 0; + } +} - .dx-rtl &, - .dx-rtl& { +.dx-rtl { + .dx-dropdowneditor-button-visible, + &.dx-dropdowneditor-button-visible { + .dx-texteditor-input { padding-right: @GENERIC_BASE_INLINE_BORDEREDWIDGET_HORIZONTAL_PADDING; padding-left: 0; } - .dx-rtl.dx-editor-underlined&, - .dx-rtl .dx-editor-underlined& { - padding-right: 0; + &.dx-editor-underlined { + .dx-texteditor-input { + padding-right: 0; + } } } } @@ -143,8 +148,8 @@ &:after { right: @GENERIC_DROPDOWNEDITOR_INVALID_BADGE_OFFSET; - .dx-rtl &, - .dx-rtl& { + .dx-rtl&, + .dx-rtl & { right: auto; left: @GENERIC_DROPDOWNEDITOR_INVALID_BADGE_OFFSET; } @@ -156,8 +161,8 @@ &:after { right: @GENERIC_DROPDOWNEDITOR_INVALID_BADGE_WITH_CLEAR_OFFSET; - .dx-rtl &, - .dx-rtl& { + .dx-rtl&, + .dx-rtl & { right: auto; left: @GENERIC_DROPDOWNEDITOR_INVALID_BADGE_WITH_CLEAR_OFFSET; } diff --git a/styles/widgets/generic/fieldset.generic.less b/styles/widgets/generic/fieldset.generic.less index 505f82202568..dad159d206ba 100644 --- a/styles/widgets/generic/fieldset.generic.less +++ b/styles/widgets/generic/fieldset.generic.less @@ -127,7 +127,7 @@ .dx-fieldset-header { margin: 0 0 @header-vertical-margin 0; - .dx-theme-generic-typography.dx-font-s; + .dx-s-font-mixin(); } .dx-field { diff --git a/styles/widgets/generic/fileManager.generic.less b/styles/widgets/generic/fileManager.generic.less index 9b4e7855e351..bf7dbad04414 100644 --- a/styles/widgets/generic/fileManager.generic.less +++ b/styles/widgets/generic/fileManager.generic.less @@ -18,18 +18,15 @@ .dx-filemanager-notification-common { border-color: @filemanager-border-color; + color: @base-danger; } .dx-filemanager-progress-panel { background-color: @base-bg; + } - .dx-filemanager-progress-panel-details { - border-color: @filemanager-border-color; - - & > .dx-filemanager-progress-box { - box-shadow: 0 4px 8px 0 @filemanager-progressbox-shadow-color; - } - } + .dx-filemanager-progress-box-image { + font-size: @GENERIC_BASE_ICON_SIZE * 2; } .dx-filemanager-progress-box-error { @@ -37,6 +34,10 @@ background: @base-danger; } + .dx-filemanager-progress-box .dx-filemanager-progress-box-close-button { + margin-top: @FILEMANAGER_PROGRESS_BOX_BUTTON_CLOSE_MARGIN_TOP; + } + .dx-filemanager-toolbar { background: @base-bg; @@ -165,7 +166,7 @@ max-width: @FILEMANAGER_DETAILS_VIEW_CHECKBOX_COLUMN_WIDTH; } - .dx-row-focused .dx-filemanager-file-actions-button .dx-button { + .dx-row-focused .dx-filemanager-file-actions-button .dx-button .dx-icon { color: @filemanager-item-focused-color; } } @@ -209,10 +210,19 @@ } } +.dx-filemanager-dirs-tree.dx-treeview .dx-filemanager-file-actions-button { + margin-top: 1px; + margin-bottom: -1px; + + .dx-button .dx-button-content { + padding: 0; + } +} + .dx-filemanager-file-actions-button { .dx-button { - min-width: @FILEMANAGER_FILE_ACTIONS_BUTTON_WIDTH; - height: @FILEMANAGER_FILE_ACTIONS_BUTTON_HEIGHT; + min-width: @FILEMANAGER_FILE_ACTIONS_BUTTON_SIZE; + height: @FILEMANAGER_FILE_ACTIONS_BUTTON_SIZE; .dx-button-content { padding-top: @FILEMANAGER_FILE_ACTIONS_BUTTON_TOP_BOTTOM_PADDING; diff --git a/styles/widgets/generic/gallery.generic.less b/styles/widgets/generic/gallery.generic.less index ee1835499987..731ed02ffe7d 100644 --- a/styles/widgets/generic/gallery.generic.less +++ b/styles/widgets/generic/gallery.generic.less @@ -47,7 +47,7 @@ } .dx-gallery-nav-button-prev { - .dx-icon-chevronleft; + .dx-icon(chevronleft); &:after { left: 0; @@ -61,7 +61,7 @@ } .dx-gallery-nav-button-next { - .dx-icon-chevronright; + .dx-icon(chevronright); &:after { right: 0; diff --git a/styles/widgets/generic/gantt.generic.less b/styles/widgets/generic/gantt.generic.less index ce37a6d5fd48..e3eb96730cfa 100644 --- a/styles/widgets/generic/gantt.generic.less +++ b/styles/widgets/generic/gantt.generic.less @@ -206,6 +206,11 @@ .dx-gantt-tm { border-left: 1px dashed @base-accent; + + &.dx-gantt-ti { + border-right: 1px dashed @base-accent; + background-color: fade(@base-accent, 15%); + } } .dx-gantt-altRow, diff --git a/styles/widgets/generic/gridBase.generic.less b/styles/widgets/generic/gridBase.generic.less index 4ea82d31ffe7..2f60d4bfd933 100644 --- a/styles/widgets/generic/gridBase.generic.less +++ b/styles/widgets/generic/gridBase.generic.less @@ -87,64 +87,64 @@ &.dx-context-menu { .dx-menu-items-container { .dx-icon-context-menu-sort-asc { - .dx-icon-sortuptext; + .dx-icon(sortuptext); .dx-icon-sizing(16px); } .dx-icon-context-menu-sort-desc { - .dx-icon-sortdowntext; + .dx-icon(sortdowntext); .dx-icon-sizing(16px); } } } .dx-icon-filter-operation-equals { - .dx-icon-equal; + .dx-icon(equal); } .dx-icon-filter-operation-default { - .dx-icon-find; + .dx-icon(find); .dx-icon-sizing(12px); } .dx-icon-filter-operation-not-equals { - .dx-icon-notequal; + .dx-icon(notequal); } .dx-icon-filter-operation-less { - .dx-icon-less; + .dx-icon(less); } .dx-icon-filter-operation-less-equal { - .dx-icon-lessorequal; + .dx-icon(lessorequal); } .dx-icon-filter-operation-greater { - .dx-icon-greater; + .dx-icon(greater); } .dx-icon-filter-operation-greater-equal { - .dx-icon-greaterorequal; + .dx-icon(greaterorequal); } .dx-icon-filter-operation-contains { - .dx-icon-contains; + .dx-icon(contains); } .dx-icon-filter-operation-not-contains { - .dx-icon-doesnotcontain; + .dx-icon(doesnotcontain); } .dx-icon-filter-operation-starts-with { - .dx-icon-startswith; + .dx-icon(startswith); } .dx-icon-filter-operation-ends-with { - .dx-icon-endswith; + .dx-icon(endswith); } .dx-icon-filter-operation-between { - .dx-icon-range; + .dx-icon(range); } } @@ -182,7 +182,7 @@ .dx-closebutton { float: right; margin: @GENERIC_GRID_BASE_CELL_PADDING + 2px; - .dx-icon-close; + .dx-icon(close); .dx-icon-sizing(14px); } @@ -258,8 +258,8 @@ .dx-placeholder:before { padding-left: @GENERIC_TEXTEDITOR_ICON_CONTAINER_SIZE; - .dx-rtl &, - .dx-rtl& { + .dx-rtl&, + .dx-rtl & { padding-right: @GENERIC_TEXTEDITOR_ICON_CONTAINER_SIZE; } } @@ -600,46 +600,46 @@ } .dx-icon-column-chooser { - .dx-icon-columnchooser; + .dx-icon(columnchooser); .dx-icon-sizing(@GENERIC_BASE_ICON_SIZE); } .dx-@{widgetName}-addrow-button { .dx-icon-edit-button-addrow { - .dx-icon-add; + .dx-icon(add); .dx-icon-sizing(@GENERIC_BASE_ICON_SIZE); } } .dx-@{widgetName}-cancel-button { .dx-icon-edit-button-cancel { - .dx-icon-revert; + .dx-icon(revert); .dx-icon-sizing(@GENERIC_BASE_ICON_SIZE); } } .dx-@{widgetName}-save-button { .dx-icon-edit-button-save { - .dx-icon-save; + .dx-icon(save); .dx-icon-sizing(@GENERIC_BASE_ICON_SIZE); } } .dx-apply-button { .dx-icon-apply-filter { - .dx-icon-filter; + .dx-icon(filter); .dx-icon-sizing(@GENERIC_BASE_ICON_SIZE); } } .dx-@{widgetName}-export-button { .dx-icon-export-to { - .dx-icon-export; + .dx-icon(export); .dx-icon-sizing(@GENERIC_BASE_ICON_SIZE); } .dx-icon-export-excel-button { - .dx-icon-xlsxfile; + .dx-icon(xlsxfile); .dx-icon-sizing(@GENERIC_BASE_ICON_SIZE); } } @@ -860,7 +860,7 @@ } } - &.dx-scrollable-scrollbars-alwaysvisible.dx-scrollable-both .dx-scrollable-content { + &.dx-scrollable-scrollbars-alwaysvisible.dx-scrollable-both .dx-scrollable-wrapper .dx-scrollable-container .dx-scrollable-content { padding-right: 0; } } @@ -1000,7 +1000,7 @@ } } - &.dx-scrollable-scrollbars-alwaysvisible.dx-scrollable-both .dx-scrollable-content { + &.dx-scrollable-scrollbars-alwaysvisible.dx-scrollable-both .dx-scrollable-wrapper .dx-scrollable-container .dx-scrollable-content { padding-left: 0; } } diff --git a/styles/widgets/generic/list.generic.less b/styles/widgets/generic/list.generic.less index 5493189eef58..e80c03ba0d55 100644 --- a/styles/widgets/generic/list.generic.less +++ b/styles/widgets/generic/list.generic.less @@ -52,7 +52,7 @@ transform: rotate(0); } - .dx-icon-chevronnext; + .dx-icon(chevronnext); .dx-icon-sizing(@GENERIC_BASE_ICON_SIZE); margin-left: -5px; @@ -319,7 +319,7 @@ } .dx-list-reorder-handle { - .dx-icon-dragvertical; + .dx-icon(dragvertical); .dx-icon-sizing(@GENERIC_BASE_ICON_SIZE, @GENERIC_BASE_ICON_SIZE * 1.6); } } diff --git a/styles/widgets/generic/lookup.generic.less b/styles/widgets/generic/lookup.generic.less index 6f8f08dde780..2a279f82d45f 100644 --- a/styles/widgets/generic/lookup.generic.less +++ b/styles/widgets/generic/lookup.generic.less @@ -22,7 +22,7 @@ @GENERIC_LOOKUP_HEIGHT: 26px; @GENERIC_LOOKUP_POPUP_CONTENT_TOP: 36px; @GENERIC_LOOKUP_POPUP_CONTENT_PADDING: 10px; - @GENERIC_LOOKUP_LIST_TOP: 45px; + @GENERIC_LOOKUP_LIST_TOP: 40px; @GENERIC_LOOKUP_ARROW_MARGIN: -5px; @GENERIC_LOOKUP_ARROW_RIGHT: 5px; @@ -66,7 +66,7 @@ } .dx-lookup-arrow { - .dx-icon-spinnext; + .dx-icon(spinnext); width: @GENERIC_BASE_INLINE_BORDEREDWIDGET_INNER_SIZE; color: @lookup-icon-color; @@ -110,8 +110,8 @@ .lookup-badge-offset() { right: @GENERIC_DROPDOWNEDITOR_INVALID_BADGE_OFFSET; - .dx-rtl &, - .dx-rtl& { + .dx-rtl&, + .dx-rtl & { right: auto; left: @GENERIC_DROPDOWNEDITOR_INVALID_BADGE_OFFSET; } diff --git a/styles/widgets/generic/menu.generic.less b/styles/widgets/generic/menu.generic.less index 92e3854e80a3..b05f5ad61d31 100644 --- a/styles/widgets/generic/menu.generic.less +++ b/styles/widgets/generic/menu.generic.less @@ -46,14 +46,14 @@ .dx-menu-horizontal { .dx-menu-item-popout { - .dx-icon-spindown; + .dx-icon(spindown); .dx-icon-font-centered-sizing(@GENERIC_BASE_ICON_SIZE); } } .dx-menu-vertical { .dx-menu-item-popout { - .dx-icon-spinright; + .dx-icon(spinright); .dx-icon-font-centered-sizing(@GENERIC_BASE_ICON_SIZE); } } diff --git a/styles/widgets/generic/numberBox.generic.less b/styles/widgets/generic/numberBox.generic.less index c2a99ba00527..2c662fc3cbff 100644 --- a/styles/widgets/generic/numberBox.generic.less +++ b/styles/widgets/generic/numberBox.generic.less @@ -21,13 +21,13 @@ } .dx-numberbox-spin-up-icon { - .dx-icon-spinup; + .dx-icon(spinup); color: @numberbox-spin-icon-color; } .dx-numberbox-spin-down-icon { - .dx-icon-spindown; + .dx-icon(spindown); color: @numberbox-spin-icon-color; } diff --git a/styles/widgets/generic/pager.generic.less b/styles/widgets/generic/pager.generic.less index f6e573fc068e..16533a1b87ba 100644 --- a/styles/widgets/generic/pager.generic.less +++ b/styles/widgets/generic/pager.generic.less @@ -60,11 +60,11 @@ } .dx-prev-button { - .dx-icon-chevronleft; + .dx-icon(chevronleft); } .dx-next-button { - .dx-icon-chevronright; + .dx-icon(chevronright); } .dx-prev-button, diff --git a/styles/widgets/generic/pivotGrid.generic.less b/styles/widgets/generic/pivotGrid.generic.less index 5c8770c78382..cefadd2a6c8f 100644 --- a/styles/widgets/generic/pivotGrid.generic.less +++ b/styles/widgets/generic/pivotGrid.generic.less @@ -28,7 +28,7 @@ } .dx-expand-icon-container { - .dx-icon-spinright; + .dx-icon(spinright); &:before { visibility: hidden; @@ -36,14 +36,14 @@ } .dx-pivotgrid-collapsed .dx-expand { - .dx-icon-spinright; + .dx-icon(spinright); .dx-icon-font-centered-sizing(@GENERIC_BASE_ICON_SIZE); color: @pivotgrid-spin-icon-color; } .dx-pivotgrid-expanded .dx-expand { - .dx-icon-spindown; + .dx-icon(spindown); .dx-icon-font-centered-sizing(@GENERIC_BASE_ICON_SIZE); color: @pivotgrid-spin-icon-color; diff --git a/styles/widgets/generic/radioGroup.generic.less b/styles/widgets/generic/radioGroup.generic.less index e0b6090ae53c..58ebcd1d787f 100644 --- a/styles/widgets/generic/radioGroup.generic.less +++ b/styles/widgets/generic/radioGroup.generic.less @@ -22,8 +22,8 @@ .dx-radiobutton { margin-right: 17px; - .dx-rtl &, - .dx-rtl& { + .dx-rtl&, + .dx-rtl & { margin-right: 0; margin-left: 17px; } diff --git a/styles/widgets/generic/size-schemes/compact.less b/styles/widgets/generic/size-schemes/compact.less index 3789dc336ffe..9496c06b1489 100644 --- a/styles/widgets/generic/size-schemes/compact.less +++ b/styles/widgets/generic/size-schemes/compact.less @@ -49,12 +49,12 @@ @FILEMANAGER_BREADCRUMBS_ITEM_PADDING_TOP: 3px; @FILEMANAGER_BREADCRUMBS_ITEM_PADDING_BOTTOM: 7px; @FILEMANAGER_DETAILS_VIEW_CHECKBOX_COLUMN_WIDTH: 39px; -@FILEMANAGER_FILE_ACTIONS_BUTTON_WIDTH: 32px; -@FILEMANAGER_FILE_ACTIONS_BUTTON_HEIGHT: 18px; +@FILEMANAGER_FILE_ACTIONS_BUTTON_SIZE: 18px; @FILEMANAGER_FILE_ACTIONS_BUTTON_TOP_BOTTOM_PADDING: 9px; @FILEMANAGER_DIRS_TREE_ICON_MARGIN_BOTTOM: 1px; @FILEMANAGER_LARGE_ICON_SIZE: 18px; @FILEMANAGER_LARGE_ICON_BUTTON_CONTENT_PADDING: 3px; +@FILEMANAGER_PROGRESS_BOX_BUTTON_CLOSE_MARGIN_TOP: 6px; @GANTT_HEADER_ITEM_HEIGHT: 45px; @GANTT_TASK_WRAPPER_PADDING_TOP: 5px; diff --git a/styles/widgets/generic/size-schemes/default.less b/styles/widgets/generic/size-schemes/default.less index 0314dd6e3ab4..fff96fed2ad7 100644 --- a/styles/widgets/generic/size-schemes/default.less +++ b/styles/widgets/generic/size-schemes/default.less @@ -50,12 +50,12 @@ @FILEMANAGER_BREADCRUMBS_ITEM_PADDING_TOP: 5px; @FILEMANAGER_BREADCRUMBS_ITEM_PADDING_BOTTOM: 8px; @FILEMANAGER_DETAILS_VIEW_CHECKBOX_COLUMN_WIDTH: 43px; -@FILEMANAGER_FILE_ACTIONS_BUTTON_WIDTH: 32px; -@FILEMANAGER_FILE_ACTIONS_BUTTON_HEIGHT: 21px; +@FILEMANAGER_FILE_ACTIONS_BUTTON_SIZE: 21px; @FILEMANAGER_FILE_ACTIONS_BUTTON_TOP_BOTTOM_PADDING: 10px; @FILEMANAGER_DIRS_TREE_ICON_MARGIN_BOTTOM: 0; @FILEMANAGER_LARGE_ICON_SIZE: 22px; @FILEMANAGER_LARGE_ICON_BUTTON_CONTENT_PADDING: 4px; +@FILEMANAGER_PROGRESS_BOX_BUTTON_CLOSE_MARGIN_TOP: 9px; @GANTT_HEADER_ITEM_HEIGHT: 45px; @GANTT_TASK_WRAPPER_PADDING_TOP: 7px; diff --git a/styles/widgets/generic/tagBox.generic.less b/styles/widgets/generic/tagBox.generic.less index d44bbc57ec67..3e2f7d4c079f 100644 --- a/styles/widgets/generic/tagBox.generic.less +++ b/styles/widgets/generic/tagBox.generic.less @@ -30,8 +30,8 @@ padding-left: 0; margin-left: @GENERIC_TAGBOX_INPUT_MARGIN_LEFT; - .dx-rtl &, - .dx-rtl& { + .dx-rtl&, + .dx-rtl & { padding-right: 0; padding-left: 0; margin-right: 0; @@ -122,8 +122,8 @@ .tagbox-badge-offset() { right: @GENERIC_INVALID_BADGE_HORIZONTAL_PADDING; - .dx-rtl &, - .dx-rtl& { + .dx-rtl&, + .dx-rtl & { left: @GENERIC_INVALID_BADGE_HORIZONTAL_PADDING; } } diff --git a/styles/widgets/generic/textBox.generic.less b/styles/widgets/generic/textBox.generic.less index cb74d403bebd..c6d0f14d4866 100644 --- a/styles/widgets/generic/textBox.generic.less +++ b/styles/widgets/generic/textBox.generic.less @@ -2,7 +2,7 @@ .dx-searchbox { .dx-icon-search { - .dx-icon-search; + .dx-icon(search); .dx-texteditor-icon(); font-size: @GENERIC_TEXTEDITOR_ICON_SIZE - 1; @@ -20,14 +20,19 @@ .dx-placeholder:before { padding-left: @GENERIC_TEXTEDITOR_ICON_CONTAINER_SIZE; - .dx-rtl &, - .dx-rtl& { + .dx-rtl&, + .dx-rtl & { padding-right: @GENERIC_TEXTEDITOR_ICON_CONTAINER_SIZE; } + } - .dx-rtl.dx-editor-underlined&, - .dx-rtl .dx-editor-underlined& { - padding-right: 0; + &.dx-editor-underlined { + .dx-texteditor-input, + .dx-placeholder:before { + .dx-rtl&, + .dx-rtl & { + padding-right: 0; + } } } } diff --git a/styles/widgets/generic/textEditor.generic.less b/styles/widgets/generic/textEditor.generic.less index 08ee8f54c190..633d81e28dd0 100644 --- a/styles/widgets/generic/textEditor.generic.less +++ b/styles/widgets/generic/textEditor.generic.less @@ -41,8 +41,8 @@ .texteditor-validation-icon-offset() { right: @GENERIC_INVALID_BADGE_HALFHORIZONTAL_PADDING; - .dx-rtl &, - .dx-rtl& { + .dx-rtl&, + .dx-rtl & { left: @GENERIC_INVALID_BADGE_HALFHORIZONTAL_PADDING; right: auto; } diff --git a/styles/widgets/generic/treeList.generic.less b/styles/widgets/generic/treeList.generic.less index 552710c92acc..d5f4c9b22ffb 100644 --- a/styles/widgets/generic/treeList.generic.less +++ b/styles/widgets/generic/treeList.generic.less @@ -15,7 +15,7 @@ position: relative; display: inline-block; width: @TREELIST_EMPTY_SPACE_WIDTH; - .dx-icon-spinright; + .dx-icon(spinright); &:before { visibility: hidden; @@ -27,7 +27,7 @@ } .dx-treelist-expanded span { - .dx-icon-spindown; + .dx-icon(spindown); .dx-icon-font-centered-sizing(@GENERIC_BASE_ICON_SIZE); cursor: pointer; @@ -40,7 +40,7 @@ } .dx-treelist-collapsed span { - .dx-icon-spinright; + .dx-icon(spinright); .dx-icon-font-centered-sizing(@GENERIC_BASE_ICON_SIZE); cursor: pointer; diff --git a/styles/widgets/generic/treeView.generic.less b/styles/widgets/generic/treeView.generic.less index 021819fad416..90f153a38533 100644 --- a/styles/widgets/generic/treeView.generic.less +++ b/styles/widgets/generic/treeView.generic.less @@ -201,7 +201,7 @@ } .dx-treeview-toggle-item-visibility { - .dx-icon-spinright; + .dx-icon(spinright); .dx-icon-font-centered-sizing(@GENERIC_TREEVIEW_ARROW_ICON_SIZE); color: @treeview-spin-icon-color; @@ -211,7 +211,7 @@ left: @GENERIC_TREEVIEW_TOGGLE_ITEM_VISIBILITY_OFFSET; &.dx-treeview-toggle-item-visibility-opened { - .dx-icon-spindown; + .dx-icon(spindown); .dx-icon-font-centered-sizing(@GENERIC_TREEVIEW_ARROW_ICON_SIZE); } } diff --git a/styles/widgets/generic/typography.generic.less b/styles/widgets/generic/typography.generic.less index f119feee9e30..d744deab7edf 100644 --- a/styles/widgets/generic/typography.generic.less +++ b/styles/widgets/generic/typography.generic.less @@ -1,3 +1,8 @@ +.dx-s-font-mixin() { + font-weight: 500; + font-size: @GENERIC_S_FONT_SIZE; +} + .dx-theme-generic-typography { background-color: @typography-bg; .dx-base-typography(); @@ -26,8 +31,7 @@ h4, .dx-font-s { - font-weight: 500; - font-size: @GENERIC_S_FONT_SIZE; + .dx-s-font-mixin(); } h5 { diff --git a/styles/widgets/generic/validation.generic.less b/styles/widgets/generic/validation.generic.less index 947c9f714aed..965ba390f0b9 100644 --- a/styles/widgets/generic/validation.generic.less +++ b/styles/widgets/generic/validation.generic.less @@ -1,6 +1,8 @@ @import (once) "../base/validation.less"; @import (once) "./overlay.generic.less"; +.dx-base-validation(@VALIDATION_SUMMARY_COLOR, @VALIDATION_MESSAGE_COLOR, @VALIDATION_MESSAGE_BACKGROUND_COLOR); + .dx-invalid-message > .dx-overlay-content { border-radius: @validation-overlay-border-radius; diff --git a/styles/widgets/ios7/checkBox.ios7.less b/styles/widgets/ios7/checkBox.ios7.less index e1b7c6caf3f6..aec6c4d2e090 100644 --- a/styles/widgets/ios7/checkBox.ios7.less +++ b/styles/widgets/ios7/checkBox.ios7.less @@ -33,7 +33,7 @@ border-radius: @IOS7_CHECKBOX_BORDER_RADIUS_ICON_SIZE; .dx-checkbox-checked & { - .dx-icon-check; + .dx-icon(check); color: @IOS7_CHECKBOX_BACKGROUND_COLOR; .dx-icon-font-centered-sizing(@IOS7_CHECKBOX_CHECKED_ICON_SIZE); diff --git a/styles/widgets/ios7/contextMenu.ios7.less b/styles/widgets/ios7/contextMenu.ios7.less index 9635f76a09cc..5eee71035431 100644 --- a/styles/widgets/ios7/contextMenu.ios7.less +++ b/styles/widgets/ios7/contextMenu.ios7.less @@ -61,7 +61,7 @@ } .dx-menu-item-popout { - .dx-icon-chevronright; + .dx-icon(chevronright); .dx-icon-font-centered-sizing(@IOS7_MENU_ARROW_ICON_SIZE); .dx-rtl &, diff --git a/styles/widgets/ios7/dataGrid.ios7.less b/styles/widgets/ios7/dataGrid.ios7.less index fa4055a7f907..aad917f01575 100644 --- a/styles/widgets/ios7/dataGrid.ios7.less +++ b/styles/widgets/ios7/dataGrid.ios7.less @@ -50,12 +50,12 @@ } .dx-datagrid-group-opened { - .dx-icon-chevrondown; + .dx-icon(chevrondown); .dx-icon-sizing(@GRID_BASE_GROUP_COLUMN_ICONS_SIZE); } .dx-datagrid-group-closed { - .dx-icon-chevronright; + .dx-icon(chevronright); .dx-icon-sizing(@GRID_BASE_GROUP_COLUMN_ICONS_SIZE); } diff --git a/styles/widgets/ios7/diagram.ios7.less b/styles/widgets/ios7/diagram.ios7.less index 58855510430a..e69de29bb2d1 100644 --- a/styles/widgets/ios7/diagram.ios7.less +++ b/styles/widgets/ios7/diagram.ios7.less @@ -1,52 +0,0 @@ -@import (once) "../base/diagram.less"; -@import (once) "./drawer.ios7.less"; -@import (once) "./loadIndicator.ios7.less"; -@import (once) "./tooltip.ios7.less"; -@import (once) "./accordion.ios7.less"; -@import (once) "./scrollView.ios7.less"; -@import (once) "./form.ios7.less"; -@import (once) "./toolbar.ios7.less"; -@import (once) "./contextMenu.ios7.less"; -@import (once) "./fileUploader.ios7.less"; -@import (once) "./popup.ios7.less"; - -@IOS7_DIAGRAM_TOOLBAR_ICON_SIZE: 18px; -@DIAGRAM_TOOLBAR_COLORBUTTON_BORDER_WIDTH: 3px; -@DIAGRAM_TOUCHBAR_ITEM_PADDING: 6px; - -.dx-diagram { - .dx-diagram-toolbar-wrapper { - border-bottom: 1px solid @IOS7_BORDER; - } - - &.dx-diagram-fullscreen { - background-color: @IOS7_BACKGROUND; - } -} - -.dx-diagram-toolbar, -.dx-dropdownmenu-popup { - .dx-diagram-select-b, - .dx-diagram-color-b { - .dx-dropdowneditor-field-template-wrapper { - .dx-icon { - font-size: @IOS7_DIAGRAM_TOOLBAR_ICON_SIZE; - color: @IOS7_BUTTON_TEXT; - } - } - } -} - -.dx-diagram-touchbar { - .dx-menu-item .dx-menu-item-content { - padding: @DIAGRAM_TOUCHBAR_ITEM_PADDING; - } - - .dx-menu-separator { - width: 1px; - height: @IOS7_DIAGRAM_TOOLBAR_ICON_SIZE + @DIAGRAM_TOUCHBAR_ITEM_PADDING + @DIAGRAM_TOUCHBAR_ITEM_PADDING + 2; - margin: 0; - } -} - -.diagram-icons-mixin(@IOS7_BUTTON_TEXT, @IOS7_CONTEXT_MENU_TEXT_COLOR, @IOS7_DIAGRAM_TOOLBAR_ICON_SIZE); diff --git a/styles/widgets/ios7/dropDownEditor.ios7.less b/styles/widgets/ios7/dropDownEditor.ios7.less index f20c725fa7eb..e2bb40f098f6 100644 --- a/styles/widgets/ios7/dropDownEditor.ios7.less +++ b/styles/widgets/ios7/dropDownEditor.ios7.less @@ -42,7 +42,7 @@ } .dx-dropdowneditor-icon { - .dx-icon-chevrondown; + .dx-icon(chevrondown); .dx-icon-font-centered-sizing(16px); diff --git a/styles/widgets/ios7/gallery.ios7.less b/styles/widgets/ios7/gallery.ios7.less index 8d7ef5358346..59bc7c19467b 100644 --- a/styles/widgets/ios7/gallery.ios7.less +++ b/styles/widgets/ios7/gallery.ios7.less @@ -7,11 +7,11 @@ } .dx-gallery-nav-button-prev { - .dx-icon-chevronleft; + .dx-icon(chevronleft); } .dx-gallery-nav-button-next { - .dx-icon-chevronright; + .dx-icon(chevronright); } // stylelint-disable-next-line no-duplicate-selectors diff --git a/styles/widgets/ios7/gantt.ios7.less b/styles/widgets/ios7/gantt.ios7.less index d50ed4dd867b..e69de29bb2d1 100644 --- a/styles/widgets/ios7/gantt.ios7.less +++ b/styles/widgets/ios7/gantt.ios7.less @@ -1,2 +0,0 @@ -@import (once) "./scrollView.ios7.less"; -@import (once) "./treeList.ios7.less"; diff --git a/styles/widgets/ios7/gridBase.ios7.less b/styles/widgets/ios7/gridBase.ios7.less index 5b32de483123..57a6fd982665 100644 --- a/styles/widgets/ios7/gridBase.ios7.less +++ b/styles/widgets/ios7/gridBase.ios7.less @@ -52,12 +52,12 @@ .dx-menu-items-container { .dx-menu-item { .dx-icon-context-menu-sort-asc { - .dx-icon-sortuptext; + .dx-icon(sortuptext); .dx-icon-sizing(@GRID_BASE_CONTEXT_MENU_SORT_ICON_SIZE); } .dx-icon-context-menu-sort-desc { - .dx-icon-sortdowntext; + .dx-icon(sortdowntext); .dx-icon-sizing(@GRID_BASE_CONTEXT_MENU_SORT_ICON_SIZE); } } @@ -68,51 +68,51 @@ } .dx-icon-filter-operation-equals { - .dx-icon-equal; + .dx-icon(equal); } .dx-icon-filter-operation-default { - .dx-icon-find; + .dx-icon(find); } .dx-icon-filter-operation-not-equals { - .dx-icon-notequal; + .dx-icon(notequal); } .dx-icon-filter-operation-less { - .dx-icon-less; + .dx-icon(less); } .dx-icon-filter-operation-less-equal { - .dx-icon-lessorequal; + .dx-icon(lessorequal); } .dx-icon-filter-operation-greater { - .dx-icon-greater; + .dx-icon(greater); } .dx-icon-filter-operation-greater-equal { - .dx-icon-greaterorequal; + .dx-icon(greaterorequal); } .dx-icon-filter-operation-contains { - .dx-icon-contains; + .dx-icon(contains); } .dx-icon-filter-operation-not-contains { - .dx-icon-doesnotcontain; + .dx-icon(doesnotcontain); } .dx-icon-filter-operation-starts-with { - .dx-icon-startswith; + .dx-icon(startswith); } .dx-icon-filter-operation-ends-with { - .dx-icon-endswith; + .dx-icon(endswith); } .dx-icon-filter-operation-between { - .dx-icon-range; + .dx-icon(range); } } @@ -184,7 +184,7 @@ .dx-closebutton { float: right; margin: @GRID_BASE_CELL_PADDING + 1px; - .dx-icon-close; + .dx-icon(close); .dx-icon-sizing(24px); } @@ -503,32 +503,32 @@ .dx-@{widgetName}-toolbar-button { .dx-icon-column-chooser { - .dx-icon-columnchooser; + .dx-icon(columnchooser); } .dx-icon-edit-button-addrow { - .dx-icon-add; + .dx-icon(add); } .dx-icon-edit-button-cancel { - .dx-icon-revert; + .dx-icon(revert); } .dx-icon-edit-button-save { - .dx-icon-save; + .dx-icon(save); } .dx-icon-apply-filter { - .dx-icon-filter; + .dx-icon(filter); } .dx-icon-export-to { - .dx-icon-export; + .dx-icon(export); } .dx-icon-export-excel-button { - .dx-icon-xlsxfile; + .dx-icon(xlsxfile); } .dx-icon { diff --git a/styles/widgets/ios7/list.ios7.less b/styles/widgets/ios7/list.ios7.less index 9c5ed24295e0..fa8f1cfcffcc 100644 --- a/styles/widgets/ios7/list.ios7.less +++ b/styles/widgets/ios7/list.ios7.less @@ -242,7 +242,7 @@ } .dx-list-reorder-handle { - .dx-icon-dragvertical; + .dx-icon(dragvertical); .dx-icon-font-centered-sizing(25px); position: relative; diff --git a/styles/widgets/ios7/lookup.ios7.less b/styles/widgets/ios7/lookup.ios7.less index 9fa022ea5377..1de693bdc654 100644 --- a/styles/widgets/ios7/lookup.ios7.less +++ b/styles/widgets/ios7/lookup.ios7.less @@ -30,7 +30,7 @@ } .dx-lookup-arrow { - .dx-icon-chevronnext; + .dx-icon(chevronnext); .dx-icon-font-centered-sizing(16px); font-weight: 600; diff --git a/styles/widgets/ios7/numberBox.ios7.less b/styles/widgets/ios7/numberBox.ios7.less index 98296b5113d7..ee791bf96c51 100644 --- a/styles/widgets/ios7/numberBox.ios7.less +++ b/styles/widgets/ios7/numberBox.ios7.less @@ -16,11 +16,11 @@ } .dx-numberbox-spin-up-icon { - .dx-icon-spinup; + .dx-icon(spinup); } .dx-numberbox-spin-down-icon { - .dx-icon-spindown; + .dx-icon(spindown); } .dx-numberbox-spin-up-icon, diff --git a/styles/widgets/ios7/pager.ios7.less b/styles/widgets/ios7/pager.ios7.less index 27c9050afd24..8c829eca84a9 100644 --- a/styles/widgets/ios7/pager.ios7.less +++ b/styles/widgets/ios7/pager.ios7.less @@ -14,11 +14,11 @@ .dx-pages { .dx-prev-button { - .dx-icon-chevronleft; + .dx-icon(chevronleft); } .dx-next-button { - .dx-icon-chevronright; + .dx-icon(chevronright); } .dx-prev-button, diff --git a/styles/widgets/ios7/pivotGrid.ios7.less b/styles/widgets/ios7/pivotGrid.ios7.less index 3fb91ecdea9a..cd5e6f5b4778 100644 --- a/styles/widgets/ios7/pivotGrid.ios7.less +++ b/styles/widgets/ios7/pivotGrid.ios7.less @@ -12,10 +12,15 @@ } .dx-pivotgrid-collapsed .dx-expand { - .dx-icon-chevronright; + .dx-icon(chevronright); } .dx-pivotgrid-expanded .dx-expand { - .dx-icon-chevrondown; + .dx-icon(chevrondown); +} + +.dx-pivotgrid .dx-area-tree-view td.dx-white-space-column { + width: 24px; + min-width: 24px; } diff --git a/styles/widgets/ios7/treeList.ios7.less b/styles/widgets/ios7/treeList.ios7.less index 7c8e993131c0..16a2cd6c0bc9 100644 --- a/styles/widgets/ios7/treeList.ios7.less +++ b/styles/widgets/ios7/treeList.ios7.less @@ -16,7 +16,7 @@ .dx-treelist-rowsview { .dx-treelist-empty-space { - .dx-icon-spinright; + .dx-icon(spinright); position: relative; display: inline-block; @@ -29,7 +29,7 @@ } .dx-treelist-expanded span { - .dx-icon-chevrondown; + .dx-icon(chevrondown); .dx-icon-font-centered-sizing(@GRID_BASE_GROUP_COLUMN_ICONS_SIZE); font-size: 0; @@ -47,7 +47,7 @@ } .dx-treelist-collapsed span { - .dx-icon-chevronright; + .dx-icon(chevronright); .dx-icon-font-centered-sizing(@GRID_BASE_GROUP_COLUMN_ICONS_SIZE); font-size: 0; diff --git a/styles/widgets/ios7/treeView.ios7.less b/styles/widgets/ios7/treeView.ios7.less index fa6d3df1f673..aa6d7cf2ae44 100644 --- a/styles/widgets/ios7/treeView.ios7.less +++ b/styles/widgets/ios7/treeView.ios7.less @@ -97,7 +97,7 @@ } .dx-treeview-toggle-item-visibility { - .dx-icon-chevronright; + .dx-icon(chevronright); .dx-icon-font-centered-sizing(@IOS7_TREEVIEW_ARROW_ICON_SIZE); width: 21px; @@ -106,7 +106,7 @@ left: 0; &.dx-treeview-toggle-item-visibility-opened { - .dx-icon-chevrondown; + .dx-icon(chevrondown); } } diff --git a/styles/widgets/material/autocomplete.material.less b/styles/widgets/material/autocomplete.material.less index 82deb2e51531..97662e747b9b 100644 --- a/styles/widgets/material/autocomplete.material.less +++ b/styles/widgets/material/autocomplete.material.less @@ -3,8 +3,8 @@ .autocomplete-editor-container-offset() { right: @MATERIAL_INVALID_BADGE_HORIZONTAL_PADDING; - .dx-rtl &, - .dx-rtl& { + .dx-rtl&, + .dx-rtl & { left: @MATERIAL_INVALID_BADGE_HORIZONTAL_PADDING; } } diff --git a/styles/widgets/material/checkBox.material.less b/styles/widgets/material/checkBox.material.less index 49e5f85fb135..200c754ba2cb 100644 --- a/styles/widgets/material/checkBox.material.less +++ b/styles/widgets/material/checkBox.material.less @@ -97,7 +97,7 @@ background-color: @checkbox-bg; border: none; - .dx-icon-check; + .dx-icon(check); .dx-icon-font-centered-sizing(@MATERIAL_CHECKBOX_ARROW_ICON_SIZE); } @@ -115,8 +115,8 @@ margin-left: -@MATERIAL_CHECKBOX_SIZE; padding-left: @MATERIAL_CHECKBOX_SIZE + 5px; - .dx-rtl &, - .dx-rtl& { + .dx-rtl&, + .dx-rtl & { margin-right: -@MATERIAL_CHECKBOX_SIZE; padding-right: @MATERIAL_CHECKBOX_SIZE + 5px; } diff --git a/styles/widgets/material/color-schemes/material.dark.less b/styles/widgets/material/color-schemes/material.dark.less index 196c74d839ed..b12281124737 100644 --- a/styles/widgets/material/color-schemes/material.dark.less +++ b/styles/widgets/material/color-schemes/material.dark.less @@ -6,6 +6,12 @@ */ @base-font-family: "Roboto", "RobotoFallback", "Helvetica", "Arial", sans-serif; +/** +* @name 20. Text color +* @type color +*/ +@base-text-color: #fff; + /** * @name 20. Label color * @type color @@ -30,12 +36,6 @@ */ @base-spin-icon-color: fade(@base-text-color, 54%); -/** -* @name 20. Text color -* @type color -*/ -@base-text-color: #fff; - /** * @name 30. Background color * @type color @@ -104,14 +104,15 @@ @base-inverted-icon-color: @base-inverted-text-color; @base-disabled-opacity: 0.38; @base-dropdown-shadow-color: fade(@base-shadow-color, 40%); +@base-invalid-color: @base-danger; +@base-invalid-faded-border-color: fade(@base-invalid-color, 40%); // Validation -@base-invalid-color: @base-danger; + @VALIDATION_MESSAGE_COLOR: @base-inverted-text-color; @VALIDATION_MESSAGE_BACKGROUND_COLOR: @base-invalid-color; @VALIDATION_SUMMARY_COLOR: @base-invalid-color; -@base-invalid-faded-border-color: fade(@base-invalid-color, 40%); // Badges @@ -126,7 +127,6 @@ * @type color */ @badge-bg: @base-accent; -@badge-invalid-bg: @base-invalid-color; // TextEditor @@ -417,7 +417,7 @@ // ButtonGroup -// Normal Button +// Normal Button (ButtonGroup) /** * @name 10. Selected item text color @@ -438,7 +438,7 @@ @button-group-normal-selected-bg-hover: fade(@button-group-normal-selected-bg, 12%); @button-group-normal-selected-bg-focused: fade(@button-group-normal-selected-bg, 12%); -// Default Button +// Default Button (ButtonGroup) /** * @name 10. Selected item text color @@ -458,7 +458,7 @@ @button-group-default-contained-hover-bg: mix(@button-normal-bg, @button-default-bg, 92%); @button-group-default-contained-focused-bg: mix(@button-normal-bg, @button-default-bg, 92%); -// Danger Button +// Danger Button (ButtonGroup) /** * @name 10. Selected item text color @@ -478,7 +478,7 @@ @button-group-danger-contained-hover-bg: mix(@button-normal-bg, @button-danger-bg, 92%); @button-group-danger-contained-focused-bg: mix(@button-normal-bg, @button-danger-bg, 92%); -// Success Button +// Success Button (ButtonGroup) /** * @name 10. Selected item text color diff --git a/styles/widgets/material/color-schemes/material.light.less b/styles/widgets/material/color-schemes/material.light.less index 098069902ecd..6afe5774b9de 100644 --- a/styles/widgets/material/color-schemes/material.light.less +++ b/styles/widgets/material/color-schemes/material.light.less @@ -6,6 +6,12 @@ */ @base-font-family: "Roboto", "RobotoFallback", "Helvetica", "Arial", sans-serif; +/** +* @name 20. Text color +* @type color +*/ +@base-text-color: rgba(0,0,0, 0.87); + /** * @name 20. Label color * @type color @@ -30,12 +36,6 @@ */ @base-spin-icon-color: fade(@base-text-color, 54%); -/** -* @name 20. Text color -* @type color -*/ -@base-text-color: rgba(0,0,0, 0.87); - /** * @name 30. Background color * @type color @@ -105,15 +105,15 @@ @base-inverted-icon-color: @base-inverted-text-color; @base-disabled-opacity: 0.38; @base-dropdown-shadow-color: fade(@base-shadow-color, 20%); +@base-invalid-color: @base-danger; +@base-invalid-faded-border-color: fade(@base-invalid-color, 40%); // Validation -@base-invalid-color: @base-danger; @VALIDATION_MESSAGE_COLOR: @base-inverted-text-color; @VALIDATION_MESSAGE_BACKGROUND_COLOR: @base-invalid-color; - @VALIDATION_SUMMARY_COLOR: @base-invalid-color; -@base-invalid-faded-border-color: fade(@base-invalid-color, 40%); + // Badges @@ -128,7 +128,6 @@ * @type color */ @badge-bg: @base-accent; -@badge-invalid-bg: @base-invalid-color; // TextEditor @@ -408,7 +407,7 @@ // ButtonGroup -// Normal Button +// Normal Button (ButtonGroup) /** * @name 10. Selected item text color @@ -429,7 +428,7 @@ @button-group-normal-selected-bg-hover: fade(@button-group-normal-selected-bg, 12%); @button-group-normal-selected-bg-focused: fade(@button-group-normal-selected-bg, 12%); -// Default Button +// Default Button (ButtonGroup) /** * @name 10. Selected item text color @@ -449,7 +448,7 @@ @button-group-default-contained-hover-bg: lighten(@button-default-bg, 43.5%); @button-group-default-contained-focused-bg: lighten(@button-default-bg, 43.5%); -// Danger Button +// Danger Button (ButtonGroup) /** * @name 10. Selected item text color @@ -469,7 +468,7 @@ @button-group-danger-contained-hover-bg: lighten(@button-danger-bg, 38.3%); @button-group-danger-contained-focused-bg: lighten(@button-danger-bg, 38.3%); -// Success Button +// Success Button (ButtonGroup) /** * @name 10. Selected item text color diff --git a/styles/widgets/material/colorView.material.less b/styles/widgets/material/colorView.material.less index f5a702516b50..8ae3d75e15e4 100644 --- a/styles/widgets/material/colorView.material.less +++ b/styles/widgets/material/colorView.material.less @@ -2,6 +2,8 @@ @import (once) "./numberBox.material.less"; @import (once) "./textBox.material.less"; +.dx-base-colorview-styles(@COLORVIEW_HANDLE_COLOR, @COLORVIEW_HANDLE_BORDER_COLOR); + .dx-size-default() { @MATERIAL_COLORVIEW_CONTAINER_WIDTH: 450px; @MATERIAL_COLORVIEW_PALETTE_WIDTH: 288px; diff --git a/styles/widgets/material/common.material.less b/styles/widgets/material/common.material.less index ee094aea69be..3f9108fcb488 100644 --- a/styles/widgets/material/common.material.less +++ b/styles/widgets/material/common.material.less @@ -88,6 +88,7 @@ @MATERIAL_INVALID_BADGE_HALFHORIZONTAL_PADDING: @MATERIAL_INVALID_BADGE_HORIZONTAL_PADDING / 2; @MATERIAL_VALID_BADGE_FONT_SIZE: @MATERIAL_BASE_FONT_SIZE + 6px; +@badge-invalid-bg: @base-invalid-color; .badge-settings() { pointer-events: none; diff --git a/styles/widgets/material/contextMenu.material.less b/styles/widgets/material/contextMenu.material.less index ea9424c0d9fd..3a9b51b20578 100644 --- a/styles/widgets/material/contextMenu.material.less +++ b/styles/widgets/material/contextMenu.material.less @@ -27,7 +27,7 @@ .dx-menu-item-popout { color: @base-icon-color; - .dx-icon-spinright; + .dx-icon(spinright); .dx-icon-font-centered-sizing(@MATERIAL_BASE_ICON_SIZE); } } diff --git a/styles/widgets/material/dataGrid.material.less b/styles/widgets/material/dataGrid.material.less index 823ac9f47e2c..cf59d46f735e 100644 --- a/styles/widgets/material/dataGrid.material.less +++ b/styles/widgets/material/dataGrid.material.less @@ -62,14 +62,14 @@ } .dx-datagrid-group-opened { - .dx-icon-chevrondown; + .dx-icon(chevrondown); .dx-icon-sizing(@MATERIAL_BASE_ICON_SIZE); color: @datagrid-chevron-icon-color; } .dx-datagrid-group-closed { - .dx-icon-chevronright; + .dx-icon(chevronright); .dx-icon-sizing(@MATERIAL_BASE_ICON_SIZE); color: @datagrid-chevron-icon-color; diff --git a/styles/widgets/material/dateBox.material.less b/styles/widgets/material/dateBox.material.less index b90609024524..9be39f4bb4b6 100644 --- a/styles/widgets/material/dateBox.material.less +++ b/styles/widgets/material/dateBox.material.less @@ -55,7 +55,7 @@ .dx-datebox-calendar { .dx-dropdowneditor-icon { - .dx-icon-spindown; + .dx-icon(spindown); .dx-dropdowneditor-button-icon(); } @@ -145,7 +145,7 @@ .dx-datebox-list { .dx-dropdowneditor-icon { - .dx-icon-spindown; + .dx-icon(spindown); .dx-dropdowneditor-button-icon(); } } diff --git a/styles/widgets/material/diagram.material.less b/styles/widgets/material/diagram.material.less index f9a4cec5103a..ef5f1cb8f39f 100644 --- a/styles/widgets/material/diagram.material.less +++ b/styles/widgets/material/diagram.material.less @@ -7,17 +7,34 @@ @import (once) "./form.material.less"; @import (once) "./toolbar.material.less"; @import (once) "./contextMenu.material.less"; +@import (once) "./overlay.material.less"; @import (once) "./fileUploader.material.less"; @import (once) "./popup.material.less"; @MATERIAL_DIAGRAM_TOOLBAR_ICON_SIZE: @MATERIAL_BASE_ICON_SIZE; @DIAGRAM_TOOLBAR_COLORBUTTON_BORDER_WIDTH: 3px; +@DIAGRAM_TOOLBOX_TITLE_SIZE: 18px; + .dx-size-default() { + @DIAGRAM_TOOLBOX_ACCORDION_H_PADDING: 10px; + @DIAGRAM_TOOLBOX_ACCORDION_V_PADDING: 8px; + @DIAGRAM_TOOLBOX_INPUT_H_PADDING: 10px; + @DIAGRAM_TOOLBOX_INPUT_V_PADDING: 8px; + @DIAGRAM_TOOLBOX_INPUT_IMAGE_SIZE: 18px; + @DIAGRAM_TOOLBOX_INPUT_IMAGE_PADDING: 8px 0 4px 4px; + @DIAGRAM_TOUCHBAR_ITEM_PADDING: 10px; } .dx-size-compact() { + @DIAGRAM_TOOLBOX_ACCORDION_H_PADDING: 8px; + @DIAGRAM_TOOLBOX_ACCORDION_V_PADDING: 6px; + @DIAGRAM_TOOLBOX_INPUT_H_PADDING: 8px; + @DIAGRAM_TOOLBOX_INPUT_V_PADDING: 6px; + @DIAGRAM_TOOLBOX_INPUT_IMAGE_SIZE: 14px; + @DIAGRAM_TOOLBOX_INPUT_IMAGE_PADDING: 4px 0 4px 4px; + @DIAGRAM_TOUCHBAR_ITEM_PADDING: 7px; } @@ -58,56 +75,150 @@ border-bottom: 1px solid @diagram-toolbar-border-color; } - .dx-diagram-left-panel, + .dx-diagram-right-panel { - background: @overlay-content-bg; + border-left-color: @diagram-toolbar-border-color; + } + + &.dx-diagram-fullscreen { + background-color: @base-bg; + } +} - .dx-accordion { - .dx-accordion-item { - border-left: none; - border-right: none; +.dx-diagram-toolbox-panel, +.dx-diagram-right-panel { + background: @overlay-content-bg; - .dx-diagram-right-panel-begin-group { - padding-top: 24px; - } - } + .dx-accordion { + .dx-accordion-item { + border-left: none; + border-right: none; + box-shadow: none; - .dx-accordion-item:first-of-type { - border-top: none; + .dx-diagram-right-panel-begin-group { + padding-top: 24px; } + } - .dx-state-focused { - &.dx-accordion-item { - border-color: @accordion-item-border-color; - } + .dx-state-focused { + &.dx-accordion-item { + border-color: @accordion-item-border-color; + } - &.dx-accordion-item-closed:not(:last-of-type) { - border-bottom-color: transparent; - } + &.dx-accordion-item-closed:not(:last-of-type) { + border-bottom-color: transparent; } } } +} - .dx-diagram-left-panel { - border-right-color: @diagram-toolbar-border-color; - - .dxdi-toolbox .dxdi-canvas .dxdi-shape-text { // stylelint-disable-line selector-class-pattern - opacity: @diagram-toolbox-shape-text-opacity; +.dx-diagram-right-panel { + .dx-accordion { + .dx-accordion-item:first-of-type { + border-top: none; } } +} - .dx-diagram-right-panel { - border-left-color: @diagram-toolbar-border-color; +.dx-diagram-floating-toolbar-container { + background: @overlay-content-bg; + box-shadow: 0 11px 15px -7px fade(@base-shadow-color, 20%), 0 24px 38px 3px fade(@base-shadow-color, 14%), 0 9px 46px 8px fade(@base-shadow-color, 12%); + border-radius: @popup-border-radius; + padding: 4px; + + .dx-toolbar-item { + padding: 0 4px 0 0; + } +} + +.dx-diagram-toolbox-popup { + .dx-popup-title.dx-toolbar { + font-size: 0.8em; + min-height: @DIAGRAM_TOOLBOX_TITLE_SIZE; } - &.dx-diagram-fullscreen { - background-color: @base-bg; + .dx-popup-title.dx-toolbar .dx-toolbar-items-container { + height: @DIAGRAM_TOOLBOX_TITLE_SIZE; + } + + .dx-popup-title .dx-button.dx-button-has-icon:not(.dx-button-has-text), + .dx-popup-title .dx-button-content { + width: @DIAGRAM_TOOLBOX_TITLE_SIZE; + height: @DIAGRAM_TOOLBOX_TITLE_SIZE; + } + + .dx-diagram-toolbox-input .dx-button .dx-button-content { + padding: @DIAGRAM_TOOLBOX_INPUT_IMAGE_PADDING; + } + + .dx-diagram-toolbox-input .dx-button .dx-icon { + font-size: @DIAGRAM_TOOLBOX_INPUT_IMAGE_SIZE; + } + + .dx-popup-title .dx-closebutton { + width: @DIAGRAM_TOOLBOX_TITLE_SIZE; + height: @DIAGRAM_TOOLBOX_TITLE_SIZE; + margin: 1px 0 0; + } + + .dx-popup-title .dx-closebutton .dx-icon { + width: 14px; + height: 14px; + padding: 2px; + font-size: 12px; + line-height: 12px; + background-position: 2px 2px; + background-size: 12px 12px; + } + + .dx-diagram-toolbox-input .dx-texteditor-input, + .dx-diagram-toolbox-input .dx-placeholder:before { + padding: @DIAGRAM_TOOLBOX_INPUT_V_PADDING + 4px @DIAGRAM_TOOLBOX_INPUT_H_PADDING @DIAGRAM_TOOLBOX_INPUT_V_PADDING; } } -.dx-diagram-toolbar { - background-color: transparent; +.dx-diagram-toolbox-panel { + .dx-accordion { + margin: 0; + } + + .dx-accordion-item { + border-bottom: 1px solid @accordion-item-border-color; + border-top: none; + } + + .dx-accordion-item-opened { + margin: 0; + } + .dxdi-toolbox .dxdi-canvas .dxdi-shape-text { // stylelint-disable-line selector-class-pattern + opacity: @diagram-toolbox-shape-text-opacity; + } + + .dx-item-content.dx-accordion-item-title { + height: 32px; + + .dx-accordion-item-title-caption { + font-size: 0.8em; + left: @DIAGRAM_TOOLBOX_ACCORDION_H_PADDING; + top: @DIAGRAM_TOOLBOX_ACCORDION_V_PADDING; + right: 32px; + } + + &::before { + font-size: 1em; + line-height: 0.8em; + right: 0; + top: @DIAGRAM_TOOLBOX_ACCORDION_V_PADDING; + } + } + + .dx-item-content.dx-accordion-item-body { + padding: @DIAGRAM_TOOLBOX_ACCORDION_V_PADDING @DIAGRAM_TOOLBOX_ACCORDION_H_PADDING; + } +} + +.dx-diagram-toolbar { .dx-format-active:not(.dx-color-format):not(.dx-background-format) { background-color: @diagram-normal-format-active-bg; @@ -191,4 +302,11 @@ } } -.diagram-icons-mixin(@base-text-color, @base-text-color, @MATERIAL_DIAGRAM_TOOLBAR_ICON_SIZE); +.diagram-action-icons-mixin(@base-text-color, @base-text-color, @MATERIAL_DIAGRAM_TOOLBAR_ICON_SIZE); + +.dx-diagram-toolbox-popup .dx-button-has-icon .dx-icon.dx-icon-diagram-toolbox-drag { + .diagram-icon-colored(data-uri('image/svg+xml;charset=UTF-8', 'images/widgets/common/diagram/toolbox-drag.svg'), @popup-title-color, @DIAGRAM_TOOLBOX_TITLE_SIZE, @DIAGRAM_TOOLBOX_TITLE_SIZE); + + line-height: @DIAGRAM_TOOLBOX_TITLE_SIZE; + background-size: @DIAGRAM_TOOLBOX_TITLE_SIZE @DIAGRAM_TOOLBOX_TITLE_SIZE; +} diff --git a/styles/widgets/material/dropDownEditor.material.less b/styles/widgets/material/dropDownEditor.material.less index 9fb7cb532f16..84cd322848fe 100644 --- a/styles/widgets/material/dropDownEditor.material.less +++ b/styles/widgets/material/dropDownEditor.material.less @@ -41,7 +41,7 @@ .dx-dropdowneditor-icon { color: @dropdowneditor-icon-color; - .dx-icon-spindown; + .dx-icon(spindown); .dx-dropdowneditor-button-icon(); } @@ -102,7 +102,7 @@ .dx-dropdowneditor-icon { color: @dropdowneditor-icon-active-color; opacity: 1; - .dx-icon-spinup; + .dx-icon(spinup); .dx-dropdowneditor-button-icon(); } } @@ -113,8 +113,8 @@ &:after { right: @MATERIAL_DROPDOWNEDITOR_INVALID_BADGE_OFFSET; - .dx-rtl &, - .dx-rtl& { + .dx-rtl&, + .dx-rtl & { right: auto; left: @MATERIAL_DROPDOWNEDITOR_INVALID_BADGE_OFFSET; } @@ -126,8 +126,8 @@ &:after { right: @MATERIAL_DROPDOWNEDITOR_INVALID_BADGE_WITH_CLEAR_OFFSET; - .dx-rtl &, - .dx-rtl& { + .dx-rtl&, + .dx-rtl & { right: auto; left: @MATERIAL_DROPDOWNEDITOR_INVALID_BADGE_WITH_CLEAR_OFFSET; } diff --git a/styles/widgets/material/fieldset.material.less b/styles/widgets/material/fieldset.material.less index 7b05bcd42e8c..84047a8ccc09 100644 --- a/styles/widgets/material/fieldset.material.less +++ b/styles/widgets/material/fieldset.material.less @@ -133,7 +133,7 @@ .dx-fieldset-header { margin: 0 0 @header-vertical-margin 0; - .dx-theme-material-typography.dx-font-s; + .dx-s-font-mixin(); } .dx-field { diff --git a/styles/widgets/material/fileManager.material.less b/styles/widgets/material/fileManager.material.less index 60346bc64823..d344785da030 100644 --- a/styles/widgets/material/fileManager.material.less +++ b/styles/widgets/material/fileManager.material.less @@ -18,18 +18,15 @@ .dx-filemanager-notification-common { border-color: @filemanager-border-color; + color: @base-danger; } .dx-filemanager-progress-panel { background-color: @base-bg; + } - .dx-filemanager-progress-panel-details { - border-color: @filemanager-border-color; - - & > .dx-filemanager-progress-box { - box-shadow: 0 4px 8px 0 @filemanager-progressbox-shadow-color; - } - } + .dx-filemanager-progress-box-image { + font-size: @MATERIAL_BASE_ICON_SIZE; } .dx-filemanager-progress-box-error { @@ -37,6 +34,10 @@ background: @base-danger; } + .dx-filemanager-progress-box .dx-filemanager-progress-box-close-button { + margin-top: @FILEMANAGER_PROGRESS_BOX_BUTTON_CLOSE_MARGIN_TOP; + } + .dx-filemanager-toolbar { background: @base-bg; @@ -169,7 +170,7 @@ } } - .dx-row-focused .dx-filemanager-file-actions-button .dx-button { + .dx-row-focused .dx-filemanager-file-actions-button .dx-button .dx-icon { color: @filemanager-item-focused-color; } } @@ -183,6 +184,11 @@ } .dx-filemanager-dirs-tree.dx-treeview { + .dx-treeview-item { + padding-top: @FILEMANAGER_TREEVIEW_ITEM_TOP_BOTTOM_PADDING; + padding-bottom: @FILEMANAGER_TREEVIEW_ITEM_TOP_BOTTOM_PADDING; + } + .dx-state-focused > .dx-treeview-item { background: transparent; @@ -214,10 +220,14 @@ } } +.dx-filemanager-dirs-tree.dx-treeview .dx-filemanager-file-actions-button .dx-button .dx-button-content { + padding: 0; +} + .dx-filemanager-file-actions-button { .dx-button { - min-width: @FILEMANAGER_FILE_ACTIONS_BUTTON_WIDTH; - height: @FILEMANAGER_FILE_ACTIONS_BUTTON_HEIGHT; + min-width: @FILEMANAGER_FILE_ACTIONS_BUTTON_SIZE; + height: @FILEMANAGER_FILE_ACTIONS_BUTTON_SIZE; .dx-button-content { padding: @FILEMANAGER_FILE_ACTIONS_BUTTON_TOP_BOTTOM_PADDING 6px; diff --git a/styles/widgets/material/gallery.material.less b/styles/widgets/material/gallery.material.less index 03687b12d646..b85bc2a00f98 100644 --- a/styles/widgets/material/gallery.material.less +++ b/styles/widgets/material/gallery.material.less @@ -51,7 +51,7 @@ } .dx-gallery-nav-button-prev { - .dx-icon-chevronleft; + .dx-icon(chevronleft); &:after { left: @MATERIAL_GALLERY_BUTTON_PADDING; @@ -65,7 +65,7 @@ } .dx-gallery-nav-button-next { - .dx-icon-chevronright; + .dx-icon(chevronright); &:after { right: @MATERIAL_GALLERY_BUTTON_PADDING; diff --git a/styles/widgets/material/gantt.material.less b/styles/widgets/material/gantt.material.less index cb9d93dcb926..cd2b9d627e7b 100644 --- a/styles/widgets/material/gantt.material.less +++ b/styles/widgets/material/gantt.material.less @@ -169,6 +169,11 @@ .dx-gantt-tm { border-left: 1px dashed @base-accent; + + &.dx-gantt-ti { + border-right: 1px dashed @base-accent; + background-color: fade(@base-accent, 15%); + } } .dx-gantt-altRow, diff --git a/styles/widgets/material/gridBase.material.less b/styles/widgets/material/gridBase.material.less index bc394b298e8d..853fa779efb7 100644 --- a/styles/widgets/material/gridBase.material.less +++ b/styles/widgets/material/gridBase.material.less @@ -154,12 +154,12 @@ &.dx-context-menu { .dx-menu-items-container { .dx-icon-context-menu-sort-asc { - .dx-icon-sortuptext; + .dx-icon(sortuptext); .dx-icon-sizing(@MATERIAL_GRID_BASE_FILTER_ICON_SIZE - 4); } .dx-icon-context-menu-sort-desc { - .dx-icon-sortdowntext; + .dx-icon(sortdowntext); .dx-icon-sizing(@MATERIAL_GRID_BASE_FILTER_ICON_SIZE - 4); } @@ -180,51 +180,51 @@ } .dx-icon-filter-operation-equals { - .dx-icon-equal; + .dx-icon(equal); } .dx-icon-filter-operation-default { - .dx-icon-find; + .dx-icon(find); } .dx-icon-filter-operation-not-equals { - .dx-icon-notequal; + .dx-icon(notequal); } .dx-icon-filter-operation-less { - .dx-icon-less; + .dx-icon(less); } .dx-icon-filter-operation-less-equal { - .dx-icon-lessorequal; + .dx-icon(lessorequal); } .dx-icon-filter-operation-greater { - .dx-icon-greater; + .dx-icon(greater); } .dx-icon-filter-operation-greater-equal { - .dx-icon-greaterorequal; + .dx-icon(greaterorequal); } .dx-icon-filter-operation-contains { - .dx-icon-contains; + .dx-icon(contains); } .dx-icon-filter-operation-not-contains { - .dx-icon-doesnotcontain; + .dx-icon(doesnotcontain); } .dx-icon-filter-operation-starts-with { - .dx-icon-startswith; + .dx-icon(startswith); } .dx-icon-filter-operation-ends-with { - .dx-icon-endswith; + .dx-icon(endswith); } .dx-icon-filter-operation-between { - .dx-icon-range; + .dx-icon(range); } .dx-column-indicators { @@ -281,7 +281,7 @@ .dx-closebutton { float: right; margin: @MATERIAL_GRID_BASE_CELL_VERTICAL_PADDING + 2px; - .dx-icon-close; + .dx-icon(close); .dx-icon-sizing(14px); } @@ -425,8 +425,8 @@ .dx-placeholder:before { padding-left: @MATERIAL_TEXTEDITOR_ICON_CONTAINER_SIZE; - .dx-rtl &, - .dx-rtl& { + .dx-rtl&, + .dx-rtl & { padding-right: @MATERIAL_TEXTEDITOR_ICON_CONTAINER_SIZE; } } @@ -780,45 +780,45 @@ } .dx-icon-column-chooser { - .dx-icon-columnchooser; + .dx-icon(columnchooser); } .dx-@{widgetName}-addrow-button { .dx-icon-edit-button-addrow { - .dx-icon-add; + .dx-icon(add); .dx-icon-sizing(@MATERIAL_BASE_ICON_SIZE); } } .dx-@{widgetName}-cancel-button { .dx-icon-edit-button-cancel { - .dx-icon-revert; + .dx-icon(revert); .dx-icon-sizing(@MATERIAL_BASE_ICON_SIZE); } } .dx-@{widgetName}-save-button { .dx-icon-edit-button-save { - .dx-icon-save; + .dx-icon(save); .dx-icon-sizing(@MATERIAL_BASE_ICON_SIZE); } } .dx-apply-button { .dx-icon-apply-filter { - .dx-icon-filter; + .dx-icon(filter); .dx-icon-sizing(@MATERIAL_BASE_ICON_SIZE); } } .dx-@{widgetName}-export-button { .dx-icon-export-to { - .dx-icon-export; + .dx-icon(export); .dx-icon-sizing(@MATERIAL_BASE_ICON_SIZE); } .dx-icon-export-excel-button { - .dx-icon-xlsxfile; + .dx-icon(xlsxfile); .dx-icon-sizing(@MATERIAL_BASE_ICON_SIZE); } } @@ -1031,7 +1031,7 @@ } } - &.dx-scrollable-scrollbars-alwaysvisible.dx-scrollable-both .dx-scrollable-content { + &.dx-scrollable-scrollbars-alwaysvisible.dx-scrollable-both .dx-scrollable-wrapper .dx-scrollable-container .dx-scrollable-content { padding-right: 0; } } @@ -1158,7 +1158,7 @@ } } - &.dx-scrollable-scrollbars-alwaysvisible.dx-scrollable-both .dx-scrollable-content { + &.dx-scrollable-scrollbars-alwaysvisible.dx-scrollable-both .dx-scrollable-wrapper .dx-scrollable-container .dx-scrollable-content { padding-left: 0; } } diff --git a/styles/widgets/material/list.material.less b/styles/widgets/material/list.material.less index 0afe9cdeedc0..116d6e819d33 100644 --- a/styles/widgets/material/list.material.less +++ b/styles/widgets/material/list.material.less @@ -59,7 +59,7 @@ transform: rotate(0); } - .dx-icon-chevronnext; + .dx-icon(chevronnext); .dx-icon-sizing(@MATERIAL_BASE_ICON_SIZE); margin-left: -5px; @@ -204,7 +204,7 @@ &.dx-list-group-collapsed { .dx-list-group-header-indicator { .dx-list-collapsible-groups & { - .dx-icon-chevrondown; + .dx-icon(chevrondown); font-size: @MATERIAL_BASE_ICON_SIZE; } @@ -239,7 +239,7 @@ color: @list-header-indicator-color; .dx-list-collapsible-groups & { - .dx-icon-chevronup; + .dx-icon(chevronup); font-size: @MATERIAL_BASE_ICON_SIZE; float: right; @@ -420,7 +420,7 @@ } .dx-list-reorder-handle { - .dx-icon-dragvertical; + .dx-icon(dragvertical); color: fade(@base-icon-color, 27%); .dx-icon-sizing(@MATERIAL_BASE_ICON_SIZE, @MATERIAL_BASE_ICON_SIZE * 1.6); @@ -432,7 +432,7 @@ } .dx-list-slide-menu-button-delete { - .dx-icon-trash; + .dx-icon(trash); color: @base-inverted-text-color; border: 1px solid @list-button-delete-shadow-color; diff --git a/styles/widgets/material/lookup.material.less b/styles/widgets/material/lookup.material.less index 95eaed0b9660..82c97868956b 100644 --- a/styles/widgets/material/lookup.material.less +++ b/styles/widgets/material/lookup.material.less @@ -46,18 +46,37 @@ .dx-lookup-field { padding: @MATERIAL_FILLED_TEXTEDITOR_INPUT_PADDING; + padding-right: @MATERIAL_FILLED_TEXTEDITOR_INPUT_HORIZONTAL_PADDING + @MATERIAL_BASE_ICON_SIZE; } .dx-lookup-arrow { right: @MATERIAL_BASE_ICON_SIZE / 2; } + &.dx-invalid { + .dx-lookup-field { + padding-right: @MATERIAL_FILLED_TEXTEDITOR_INPUT_HORIZONTAL_PADDING + @MATERIAL_BASE_ICON_SIZE * 2; + } + + &.dx-rtl { + .dx-lookup-field { + padding-left: @MATERIAL_FILLED_TEXTEDITOR_INPUT_HORIZONTAL_PADDING + @MATERIAL_BASE_ICON_SIZE * 2; + padding-right: @MATERIAL_FILLED_TEXTEDITOR_INPUT_HORIZONTAL_PADDING; + } + } + } + &.dx-rtl, .dx-rtl & { .dx-lookup-arrow { left: @MATERIAL_BASE_ICON_SIZE / 2; right: auto; } + + .dx-lookup-field { + padding-left: @MATERIAL_FILLED_TEXTEDITOR_INPUT_HORIZONTAL_PADDING + @MATERIAL_BASE_ICON_SIZE; + padding-right: @MATERIAL_FILLED_TEXTEDITOR_INPUT_HORIZONTAL_PADDING; + } } } @@ -66,6 +85,28 @@ .dx-lookup-field { padding: @MATERIAL_STANDARD_TEXTEDITOR_INPUT_PADDING; + padding-right: @MATERIAL_STANDARD_TEXTEDITOR_INPUT_HORIZONTAL_PADDING + @MATERIAL_BASE_ICON_SIZE; + } + + &.dx-invalid { + .dx-lookup-field { + padding-right: @MATERIAL_STANDARD_TEXTEDITOR_INPUT_HORIZONTAL_PADDING + @MATERIAL_BASE_ICON_SIZE * 2; + } + + &.dx-rtl { + .dx-lookup-field { + padding-left: @MATERIAL_STANDARD_TEXTEDITOR_INPUT_HORIZONTAL_PADDING + @MATERIAL_BASE_ICON_SIZE * 2; + padding-right: @MATERIAL_STANDARD_TEXTEDITOR_INPUT_HORIZONTAL_PADDING; + } + } + } + + &.dx-rtl, + .dx-rtl & { + .dx-lookup-field { + padding-left: @MATERIAL_STANDARD_TEXTEDITOR_INPUT_HORIZONTAL_PADDING + @MATERIAL_BASE_ICON_SIZE; + padding-right: @MATERIAL_STANDARD_TEXTEDITOR_INPUT_HORIZONTAL_PADDING; + } } } @@ -148,7 +189,7 @@ } .dx-lookup-arrow { - .dx-icon-spindown; + .dx-icon(spindown); width: @MATERIAL_BASE_ICON_SIZE; color: @lookup-icon-color; diff --git a/styles/widgets/material/numberBox.material.less b/styles/widgets/material/numberBox.material.less index 22e801dd09dd..d28987bf00d8 100644 --- a/styles/widgets/material/numberBox.material.less +++ b/styles/widgets/material/numberBox.material.less @@ -24,13 +24,13 @@ } .dx-numberbox-spin-up-icon { - .dx-icon-spinup; + .dx-icon(spinup); color: @numberbox-spin-icon-color; } .dx-numberbox-spin-down-icon { - .dx-icon-spindown; + .dx-icon(spindown); color: @numberbox-spin-icon-color; } diff --git a/styles/widgets/material/pager.material.less b/styles/widgets/material/pager.material.less index d4c25d56856c..be97467f6dca 100644 --- a/styles/widgets/material/pager.material.less +++ b/styles/widgets/material/pager.material.less @@ -60,11 +60,11 @@ } .dx-prev-button { - .dx-icon-chevronleft; + .dx-icon(chevronleft); } .dx-next-button { - .dx-icon-chevronright; + .dx-icon(chevronright); } .dx-prev-button, diff --git a/styles/widgets/material/pivotGrid.material.less b/styles/widgets/material/pivotGrid.material.less index d3af0ffd63ce..7c073b4842a0 100644 --- a/styles/widgets/material/pivotGrid.material.less +++ b/styles/widgets/material/pivotGrid.material.less @@ -102,7 +102,7 @@ .dx-expand-icon-container { margin: 0 10px 0 5px; - .dx-icon-chevronright; + .dx-icon(chevronright); font-size: @MATERIAL_PIVOTGRID_HEADERS_FONT_SIZE; @@ -112,14 +112,14 @@ } .dx-pivotgrid-collapsed .dx-expand { - .dx-icon-chevronright; + .dx-icon(chevronright); .dx-icon-font-centered-sizing(@MATERIAL_PIVOTGRID_CHEVRON_ICON_SIZE); color: @pivotgrid-chevron-icon-color; } .dx-pivotgrid-expanded .dx-expand { - .dx-icon-chevrondown; + .dx-icon(chevrondown); .dx-icon-font-centered-sizing(@MATERIAL_PIVOTGRID_CHEVRON_ICON_SIZE); color: @pivotgrid-chevron-icon-color; @@ -139,7 +139,7 @@ .dx-area { .dx-area-icon-filter { background: none; - .dx-icon-filter; + .dx-icon(filter); width: 14px; height: 14px; diff --git a/styles/widgets/material/radioGroup.material.less b/styles/widgets/material/radioGroup.material.less index d2362d1acefe..9cbca8588715 100644 --- a/styles/widgets/material/radioGroup.material.less +++ b/styles/widgets/material/radioGroup.material.less @@ -14,8 +14,8 @@ .dx-radiobutton { margin-right: 17px; - .dx-rtl &, - .dx-rtl& { + .dx-rtl&, + .dx-rtl & { margin-right: 0; margin-left: 17px; } diff --git a/styles/widgets/material/size-schemes/compact.less b/styles/widgets/material/size-schemes/compact.less index 702ec945aa93..babc23561b38 100644 --- a/styles/widgets/material/size-schemes/compact.less +++ b/styles/widgets/material/size-schemes/compact.less @@ -54,11 +54,12 @@ @FILEMANAGER_BREADCRUMBS_ITEM_PADDING_TOP: 8px; @FILEMANAGER_BREADCRUMBS_ITEM_PADDING_BOTTOM: 9px; @FILEMANAGER_DETAILS_VIEW_CHECKBOX_COLUMN_WIDTH: 43px; -@FILEMANAGER_FILE_ACTIONS_BUTTON_WIDTH: 26px; -@FILEMANAGER_FILE_ACTIONS_BUTTON_HEIGHT: 18px; +@FILEMANAGER_FILE_ACTIONS_BUTTON_SIZE: 22px; +@FILEMANAGER_TREEVIEW_ITEM_TOP_BOTTOM_PADDING: 8px; @FILEMANAGER_FILE_ACTIONS_BUTTON_TOP_BOTTOM_PADDING: 9px; @FILEMANAGER_CONTEXTMENU_TEXT_ITEM_LEFT_MARGIN: 30px; @FILEMANAGER_LARGE_ICON_SIZE: 16px; +@FILEMANAGER_PROGRESS_BOX_BUTTON_CLOSE_MARGIN_TOP: 5px; @GANTT_HEADER_ITEM_HEIGHT: 51px; @GANTT_TASK_WRAPPER_PADDING_TOP: 9px; diff --git a/styles/widgets/material/size-schemes/default.less b/styles/widgets/material/size-schemes/default.less index 4be54a66fb59..67f9860c9e96 100644 --- a/styles/widgets/material/size-schemes/default.less +++ b/styles/widgets/material/size-schemes/default.less @@ -53,11 +53,12 @@ @FILEMANAGER_BREADCRUMBS_ITEM_PADDING_TOP: 7px; @FILEMANAGER_BREADCRUMBS_ITEM_PADDING_BOTTOM: 8px; @FILEMANAGER_DETAILS_VIEW_CHECKBOX_COLUMN_WIDTH: 49px; -@FILEMANAGER_FILE_ACTIONS_BUTTON_WIDTH: 32px; -@FILEMANAGER_FILE_ACTIONS_BUTTON_HEIGHT: 24px; +@FILEMANAGER_FILE_ACTIONS_BUTTON_SIZE: 28px; +@FILEMANAGER_TREEVIEW_ITEM_TOP_BOTTOM_PADDING: 11px; @FILEMANAGER_FILE_ACTIONS_BUTTON_TOP_BOTTOM_PADDING: 2px; @FILEMANAGER_CONTEXTMENU_TEXT_ITEM_LEFT_MARGIN: 48px; @FILEMANAGER_LARGE_ICON_SIZE: 22px; +@FILEMANAGER_PROGRESS_BOX_BUTTON_CLOSE_MARGIN_TOP: 6px; @GANTT_HEADER_ITEM_HEIGHT: 57px; @GANTT_TASK_WRAPPER_PADDING_TOP: 11px; diff --git a/styles/widgets/material/size-schemes/shared/base.less b/styles/widgets/material/size-schemes/shared/base.less index 00fe73747f01..c16edf79752c 100644 --- a/styles/widgets/material/size-schemes/shared/base.less +++ b/styles/widgets/material/size-schemes/shared/base.less @@ -19,3 +19,5 @@ * @type text */ @base-border-radius: @MATERIAL_BASE_BORDER_RADIUS; + +@MATERIAL_STANDARD_TEXTEDITOR_INPUT_HORIZONTAL_PADDING: 0; diff --git a/styles/widgets/material/switch.material.less b/styles/widgets/material/switch.material.less index a12c8c6578af..a7e296387d83 100644 --- a/styles/widgets/material/switch.material.less +++ b/styles/widgets/material/switch.material.less @@ -182,19 +182,21 @@ } .dx-invalid { - .dx-switch-container { - .dx-switch&:before { + &.dx-switch { + .dx-switch-container:before { background-color: @switch-invalid-container-bg; } + } - .dx-switch-handle:before { - .dx-switch-on-value:not(.dx-state-readonly):not(.dx-state-disabled)& { - background-color: @switch-invalid-handle-bg; + &.dx-switch-on-value:not(.dx-state-readonly):not(.dx-state-disabled) { + .dx-switch-container .dx-switch-handle:before { + background-color: @switch-invalid-handle-bg; + } - .dx-state-active&, - .dx-state-focused& { - box-shadow: @MATERIAL_INVALID_SWITCH_SHADOW; - } + &.dx-state-active, + &.dx-state-focused { + .dx-switch-container .dx-switch-handle:before { + box-shadow: @MATERIAL_INVALID_SWITCH_SHADOW; } } } diff --git a/styles/widgets/material/tagBox.material.less b/styles/widgets/material/tagBox.material.less index 6acea929199b..9255bbcd410f 100644 --- a/styles/widgets/material/tagBox.material.less +++ b/styles/widgets/material/tagBox.material.less @@ -61,8 +61,8 @@ padding-left: 0; margin-top: @MATERIAL_TAGBOX_TAG_MARGIN; - .dx-rtl &, - .dx-rtl& { + .dx-rtl&, + .dx-rtl & { padding-right: 0; padding-left: 0; margin-right: 0; @@ -106,7 +106,7 @@ height: 100%; right: @MATERIAL_TAGBOX_REMOVE_BUTTON_RIGHT; - .dx-icon-clear; + .dx-icon(clear); font-size: 10px; @@ -148,8 +148,8 @@ .tagbox-editor-container-offset() { right: @MATERIAL_INVALID_BADGE_HORIZONTAL_PADDING; - .dx-rtl &, - .dx-rtl& { + .dx-rtl&, + .dx-rtl & { left: @MATERIAL_INVALID_BADGE_HORIZONTAL_PADDING; } } diff --git a/styles/widgets/material/textArea.material.less b/styles/widgets/material/textArea.material.less index 9aaea0cff8dd..c79897e7f0be 100644 --- a/styles/widgets/material/textArea.material.less +++ b/styles/widgets/material/textArea.material.less @@ -1,11 +1,11 @@ @import (once) "./textBox.material.less"; -.dx-size-default { +.dx-size-default() { @TEXTAREA_CONTENT_PADDING: 10px; @TEXTAREA_CONTENT_LINE_HEIGHT: 24px; } -.dx-size-compact { +.dx-size-compact() { @TEXTAREA_CONTENT_PADDING: 8px; @TEXTAREA_CONTENT_LINE_HEIGHT: 20px; } diff --git a/styles/widgets/material/textBox.material.less b/styles/widgets/material/textBox.material.less index 98d4490c2de0..315fba88503f 100644 --- a/styles/widgets/material/textBox.material.less +++ b/styles/widgets/material/textBox.material.less @@ -2,7 +2,7 @@ .dx-searchbox { .dx-icon-search { - .dx-icon-search; + .dx-icon(search); .dx-texteditor-icon(); &:before { @@ -18,8 +18,8 @@ .dx-icon-search { left: @MATERIAL_STANDARD_TEXTEDITOR_INPUT_HORIZONTAL_PADDING; - .dx-rtl &, - .dx-rtl& { + .dx-rtl&, + .dx-rtl & { left: initial; right: @MATERIAL_STANDARD_TEXTEDITOR_INPUT_HORIZONTAL_PADDING; } @@ -29,8 +29,8 @@ .dx-placeholder:before { padding-left: @MATERIAL_TEXTEDITOR_ICON_CONTAINER_SIZE + @MATERIAL_STANDARD_TEXTEDITOR_INPUT_HORIZONTAL_PADDING; - .dx-rtl &, - .dx-rtl& { + .dx-rtl&, + .dx-rtl & { padding-left: @MATERIAL_STANDARD_TEXTEDITOR_INPUT_HORIZONTAL_PADDING; padding-right: @MATERIAL_TEXTEDITOR_ICON_CONTAINER_SIZE + @MATERIAL_STANDARD_TEXTEDITOR_INPUT_HORIZONTAL_PADDING; } @@ -42,8 +42,8 @@ .dx-icon-search { left: @MATERIAL_FILLED_TEXTEDITOR_INPUT_HORIZONTAL_PADDING; - .dx-rtl &, - .dx-rtl& { + .dx-rtl&, + .dx-rtl & { left: initial; right: @MATERIAL_FILLED_TEXTEDITOR_INPUT_HORIZONTAL_PADDING; } @@ -53,8 +53,8 @@ .dx-placeholder:before { padding-left: @MATERIAL_TEXTEDITOR_ICON_CONTAINER_SIZE + @MATERIAL_FILLED_TEXTEDITOR_INPUT_HORIZONTAL_PADDING; - .dx-rtl &, - .dx-rtl& { + .dx-rtl&, + .dx-rtl & { padding-left: @MATERIAL_FILLED_TEXTEDITOR_INPUT_HORIZONTAL_PADDING; padding-right: @MATERIAL_TEXTEDITOR_ICON_CONTAINER_SIZE + @MATERIAL_FILLED_TEXTEDITOR_INPUT_HORIZONTAL_PADDING; } diff --git a/styles/widgets/material/textEditor.material.less b/styles/widgets/material/textEditor.material.less index 1116e1e29bd0..f1848eced73b 100644 --- a/styles/widgets/material/textEditor.material.less +++ b/styles/widgets/material/textEditor.material.less @@ -56,8 +56,8 @@ .texteditor-validation-icon-offset() { right: @MATERIAL_INVALID_BADGE_HALFHORIZONTAL_PADDING; - .dx-rtl &, - .dx-rtl& { + .dx-rtl&, + .dx-rtl & { left: @MATERIAL_INVALID_BADGE_HALFHORIZONTAL_PADDING; right: auto; } @@ -66,8 +66,8 @@ .texteditor-validation-icon-offset-filled() { right: @MATERIAL_FILLED_TEXTEDITOR_INPUT_HORIZONTAL_PADDING + 1px; - .dx-rtl &, - .dx-rtl& { + .dx-rtl&, + .dx-rtl & { left: @MATERIAL_FILLED_TEXTEDITOR_INPUT_HORIZONTAL_PADDING + 1px; right: auto; } @@ -175,8 +175,8 @@ .dx-texteditor-input { padding-right: @MATERIAL_FILLED_TEXTEDITOR_INPUT_HORIZONTAL_PADDING; - .dx-rtl &, - .dx-rtl& { + .dx-rtl&, + .dx-rtl & { padding: @MATERIAL_FILLED_TEXTEDITOR_INPUT_PADDING; padding-left: @MATERIAL_FILLED_TEXTEDITOR_INPUT_HORIZONTAL_PADDING; } diff --git a/styles/widgets/material/timeView.material.less b/styles/widgets/material/timeView.material.less index f8caeb0895d8..100b78c6962a 100644 --- a/styles/widgets/material/timeView.material.less +++ b/styles/widgets/material/timeView.material.less @@ -58,29 +58,35 @@ margin-right: @MATERIAL_TIMEVIEW_TIME_SEPARATOR_MARGIN; } - &.dx-dropdowneditor-button-visible .dx-texteditor-container { - .dx-texteditor-input { - padding-right: 0; + &.dx-dropdowneditor-button-visible { + .dx-texteditor-container { + .dx-texteditor-input { + padding-right: 0; - .dx-rtl & { - padding-left: 0; + .dx-rtl & { + padding-left: 0; + } } - .dx-editor-filled&, - .dx-editor-outlined& { - .dx-rtl&, + .dx-texteditor-buttons-container .dx-dropdowneditor-button { + margin-right: 0; + + &.dx-rtl, .dx-rtl & { - padding-right: @MATERIAL_FILLED_TEXTEDITOR_INPUT_HORIZONTAL_PADDING; + margin-left: 0; } } } - .dx-texteditor-buttons-container .dx-dropdowneditor-button { - margin-right: 0; - - &.dx-rtl, - .dx-rtl & { - margin-left: 0; + &.dx-editor-filled, + &.dx-editor-outlined { + .dx-texteditor-container { + .dx-texteditor-input { + .dx-rtl&, + .dx-rtl & { + padding-right: @MATERIAL_FILLED_TEXTEDITOR_INPUT_HORIZONTAL_PADDING; + } + } } } } diff --git a/styles/widgets/material/tooltip.material.less b/styles/widgets/material/tooltip.material.less index 6580e41a224f..64602c3e47b7 100644 --- a/styles/widgets/material/tooltip.material.less +++ b/styles/widgets/material/tooltip.material.less @@ -1,10 +1,10 @@ @import (once) "./popover.material.less"; -.dx-size-default { +.dx-size-default() { @MATERIAL_TOOLTIP_PADDING: 6px 8px; } -.dx-size-compact { +.dx-size-compact() { @MATERIAL_TOOLTIP_PADDING: 4px 6px; } diff --git a/styles/widgets/material/treeList.material.less b/styles/widgets/material/treeList.material.less index 4b308bd3fc5d..bca212a38997 100644 --- a/styles/widgets/material/treeList.material.less +++ b/styles/widgets/material/treeList.material.less @@ -14,7 +14,7 @@ position: relative; top: -2px; display: inline-block; - .dx-icon-chevronup; + .dx-icon(chevronup); width: @TREELIST_EMPTY_SPACE_WIDTH; @@ -28,7 +28,7 @@ } .dx-treelist-expanded span { - .dx-icon-chevrondown; + .dx-icon(chevrondown); .dx-icon-font-centered-sizing(@MATERIAL_BASE_ICON_SIZE); cursor: pointer; @@ -41,7 +41,7 @@ } .dx-treelist-collapsed span { - .dx-icon-chevronright; + .dx-icon(chevronright); .dx-icon-font-centered-sizing(@MATERIAL_BASE_ICON_SIZE); cursor: pointer; diff --git a/styles/widgets/material/treeView.material.less b/styles/widgets/material/treeView.material.less index a98bd861a05d..a407d4c6a27f 100644 --- a/styles/widgets/material/treeView.material.less +++ b/styles/widgets/material/treeView.material.less @@ -21,6 +21,7 @@ @MATERIAL_SELECT_ALL_TEXT_OFFSET: 31px; @MATERIAL_TREEVIEW_SEARCHBOX_MARGIN_BOTTOM: 8px; + @MATERIAL_SELECT_ALL_ITEM_OFFSET: @MATERIAL_TREEVIEW_CHECKBOX_OFFSET; } .dx-size-compact() { @@ -39,6 +40,7 @@ @MATERIAL_SELECT_ALL_TEXT_OFFSET: 20px; @MATERIAL_TREEVIEW_SEARCHBOX_MARGIN_BOTTOM: 4px; + @MATERIAL_SELECT_ALL_ITEM_OFFSET: @MATERIAL_TREEVIEW_CHECKBOX_OFFSET; } @MATERIAL_TREEVIEW_CONTAINER_WITH_BORDER_OFFSET: 8px; @MATERIAL_TREEVIEW_BORDER_PADDING: 1px; @@ -51,7 +53,6 @@ @MATERIAL_TREEVIEW_SEARCH_EDITOR_HEIGHT: 33px; @MATERIAL_SELECT_ALL_ITEM_LEFT_PADDING: 26px; @MATERIAL_TREEVIEW_NODE_OFFSET: @MATERIAL_TREEVIEW_TOGGLE_ITEM_WIDTH; -@MATERIAL_SELECT_ALL_ITEM_OFFSET: @MATERIAL_TREEVIEW_CHECKBOX_OFFSET; @MATERIAL_TREEVIEW_ITEM_WITH_CHECKBOX_OFFSET: @MATERIAL_TREEVIEW_CHECKBOX_OFFSET + 5; .dx-treeview-node-loadindicator { @@ -162,7 +163,7 @@ } .dx-treeview-toggle-item-visibility { - .dx-icon-chevronright; + .dx-icon(chevronright); .dx-icon-font-centered-sizing(@MATERIAL_BASE_ICON_SIZE); color: @treeview-spin-icon-color; @@ -172,7 +173,7 @@ left: 0; &.dx-treeview-toggle-item-visibility-opened { - .dx-icon-chevrondown; + .dx-icon(chevrondown); .dx-icon-font-centered-sizing(@MATERIAL_BASE_ICON_SIZE); } } diff --git a/styles/widgets/material/typography.material.less b/styles/widgets/material/typography.material.less index 84f61abdc08c..7bb8fd2c3dfa 100644 --- a/styles/widgets/material/typography.material.less +++ b/styles/widgets/material/typography.material.less @@ -48,6 +48,10 @@ url(~"fonts/Roboto-700.ttf") format('truetype'); } +.dx-s-font-mixin() { + font-size: @MATERIAL_S_FONT_SIZE; +} + .dx-theme-material-typography { background-color: @typography-bg; .dx-base-typography(); @@ -99,7 +103,7 @@ } .dx-font-s { - font-size: @MATERIAL_S_FONT_SIZE; + .dx-s-font-mixin(); } small, diff --git a/styles/widgets/material/validation.material.less b/styles/widgets/material/validation.material.less index ed7f3a276293..8e867d96213a 100644 --- a/styles/widgets/material/validation.material.less +++ b/styles/widgets/material/validation.material.less @@ -11,6 +11,8 @@ @MATERIAL_VALIDATIONSUMMARY_ITEM_MARGIN: 6px; } +.dx-base-validation(@VALIDATION_SUMMARY_COLOR, @VALIDATION_MESSAGE_COLOR, @VALIDATION_MESSAGE_BACKGROUND_COLOR); + .dx-invalid-message > .dx-overlay-content { background-color: transparent; color: @VALIDATION_MESSAGE_BACKGROUND_COLOR; diff --git a/testing/.eslintrc b/testing/.eslintrc index 93bed3c1c1e6..6fb94a226029 100644 --- a/testing/.eslintrc +++ b/testing/.eslintrc @@ -20,7 +20,7 @@ "qunit/no-async-in-loops": "error", "qunit/no-commented-tests": "warn", "qunit/no-identical-names": "warn", - "qunit/no-ok-equality": "warn", + "qunit/no-ok-equality": "error", "qunit/no-only": "error", "qunit/no-setup-teardown": "error" } diff --git a/testing/functional/helpers/testHelper.ts b/testing/functional/helpers/testHelper.ts index 07f77e54c966..3b1b6e84f320 100644 --- a/testing/functional/helpers/testHelper.ts +++ b/testing/functional/helpers/testHelper.ts @@ -1,8 +1,14 @@ import { ClientFunction } from 'testcafe'; -export async function createWidget(widgetName: string, options: any, disableAnimation = false, selector = "#container") { +export async function createWidget( + widgetName: string, + options: any, + disableAnimation = false, + selector = "#container") +{ await ClientFunction(() => { - (window as any).widget = $(`${selector}`)[widgetName](options)[widgetName]("instance"); + const widgetoptions = typeof options === 'function' ? options() : options; + (window as any).widget = $(`${selector}`)[widgetName](widgetoptions)[widgetName]("instance"); }, { dependencies: diff --git a/testing/functional/model/dataGrid.ts b/testing/functional/model/dataGrid.ts index 93a0fbd34dda..2d0958418bdd 100644 --- a/testing/functional/model/dataGrid.ts +++ b/testing/functional/model/dataGrid.ts @@ -1,4 +1,4 @@ -import { ClientFunction } from "testcafe"; +import { ClientFunction, Selector } from "testcafe"; import Widget from "./internal/widget"; const CLASS = { @@ -25,7 +25,14 @@ const CLASS = { pagerPrevNavButton: 'dx-prev-button', pagerNextNavButton: 'dx-next-button', pagerPage: 'dx-page', - selection: 'dx-selection' + selection: 'dx-selection', + form: 'dx-form', + textEditor: 'dx-texteditor', + textEditorInput: 'dx-texteditor-input', + invalid: 'dx-invalid', + editFormRow: 'dx-datagrid-edit-form', + button: 'dx-button', + formButtonsContainer: 'dx-datagrid-form-buttons-container' }; class DxElement { @@ -196,6 +203,31 @@ class Pager extends DxElement { } } +export class EditForm extends DxElement { + selector: string; + form: Selector; + saveButton: Selector; + cancelButton: Selector; + + constructor(parentSelector: Selector) { + const selector = parentSelector ? parentSelector.find(`.${CLASS.editFormRow}`) : Selector(`.${CLASS.editFormRow}`); + super(selector); + this.form = this.element.find(`.${CLASS.form}`); + + const buttons = this.element.find(`.${CLASS.formButtonsContainer} .${CLASS.button}`); + this.saveButton = buttons.nth(0); + this.cancelButton = buttons.nth(1); + } + + getItem(id): Selector { + return this.form.find(`.${CLASS.textEditorInput}[id*=_${id}]`) + } + + getInvalids(): Selector { + return this.form.find(`.${CLASS.textEditor}.${CLASS.invalid}`); + } +} + export default class DataGrid extends Widget { dataRows: Selector; getGridInstance: ClientFunction; @@ -269,4 +301,37 @@ export default class DataGrid extends Widget { { dependencies: { getGridInstance, isHorizontal } } )(); } + + getEditForm() { + return new EditForm(this.element); + } + + api_option(name: any, value = 'undefined') : Promise { + const getGridInstance: any = this.getGridInstance; + + return ClientFunction( + () => { + const dataGrid = getGridInstance(); + return value !== 'undefined' ? dataGrid.option(name, value) : dataGrid.option(name); + }, + { dependencies: { getGridInstance, name, value } } + )(); + } + + api_editRow(rowIndex: number) : Promise { + const getGridInstance: any = this.getGridInstance; + + return ClientFunction( + () => getGridInstance().editRow(rowIndex), + { dependencies: { getGridInstance, rowIndex } } + )(); + } + + api_cancelEditData() : Promise { + const getGridInstance: any = this.getGridInstance; + return ClientFunction( + () => getGridInstance().cancelEditData(), + { dependencies: { getGridInstance } } + )(); + } } diff --git a/testing/functional/runner.js b/testing/functional/runner.js index a6917672f257..82fa311ac44f 100644 --- a/testing/functional/runner.js +++ b/testing/functional/runner.js @@ -23,7 +23,7 @@ createTestCafe('localhost', 1437, 1438) } return runner.run({ - quarantineMode: false + quarantineMode: args.quarantineMode }); }) .then(failedCount => { @@ -38,7 +38,8 @@ function getArgs() { default: { browsers: 'chrome', test: '', - componentFolder: '' + componentFolder: '', + quarantineMode: false } }); } diff --git a/testing/functional/tests/dataGrid/focusedRow.ts b/testing/functional/tests/dataGrid/focusedRow.ts index 632ee8af02ea..33ae4e937785 100644 --- a/testing/functional/tests/dataGrid/focusedRow.ts +++ b/testing/functional/tests/dataGrid/focusedRow.ts @@ -3,26 +3,26 @@ import { createWidget } from '../../helpers/testHelper'; import { ClientFunction } from 'testcafe'; import DataGrid from '../../model/dataGrid'; -fixture `Editing` +fixture`Focused row` .page(url(__dirname, '../container.html')); -test("onFocusedRowChanged event should fire once after changing focusedRowKey if paging.enabled = false (T755722)", async t => { - const dataGrid = new DataGrid("#container"); +test('onFocusedRowChanged event should fire once after changing focusedRowKey if paging.enabled = false (T755722)', async t => { + const dataGrid = new DataGrid('#container'); await t.expect(ClientFunction(() => (window as any).onFocusedRowChangedCounter)()).eql(1); - await ClientFunction(() => (window as any).widget.option("focusedRowKey", "Ben"))(); + await ClientFunction(() => (window as any).widget.option('focusedRowKey', 'Ben'))(); await t .expect(dataGrid.getFocusedRow().exists).ok() .expect(ClientFunction(() => (window as any).onFocusedRowChangedCounter)()).eql(2); -}).before(() => createWidget("dxDataGrid", { +}).before(() => createWidget('dxDataGrid', { dataSource: [ - { name: "Alex", phone: "111111", room: 6 }, - { name: "Dan", phone: "2222222", room: 5 }, - { name: "Ben", phone: "333333", room: 4 } + { name: 'Alex', phone: '111111', room: 6 }, + { name: 'Dan', phone: '2222222', room: 5 }, + { name: 'Ben', phone: '333333', room: 4 } ], - keyExpr: "name", + keyExpr: 'name', focusedRowEnabled: true, focusedRowIndex: 1, paging: { @@ -30,9 +30,163 @@ test("onFocusedRowChanged event should fire once after changing focusedRowKey if }, onFocusedRowChanged: () => { const global = window as any; - if(!global.onFocusedRowChangedCounter) { + if (!global.onFocusedRowChangedCounter) { global.onFocusedRowChangedCounter = 0; } global.onFocusedRowChangedCounter++; } })); + +test('Focused row should not being reseted after begin edit row if form editing mode (T851400)', async t => { + const dataGrid = new DataGrid('#container'); + const dataRow0 = dataGrid.getDataRow(0); + const dataRow1 = dataGrid.getDataRow(1); + const editForm = dataGrid.getEditForm(); + + await t + .expect(dataRow1.isFocusedRow).ok() + .click(dataRow1.getCommandCell(2).getButton(0)) + .expect(editForm.element.exists).ok() + .click(editForm.cancelButton) + .expect(dataRow1.isFocusedRow).ok(); + + await t + .click(dataRow0.getCommandCell(2).getButton(0)) + .expect(editForm.element.exists).ok() + .click(editForm.cancelButton) + .expect(dataRow1.isFocusedRow).ok() + .expect(dataRow0.isFocusedRow).notOk(); +}).before(() => createWidget('dxDataGrid', { + dataSource: [ + { id: 5, c0: 'c0_0' }, + { id: 6, c0: 'c0_1' } + ], + keyExpr: 'id', + focusedRowEnabled: true, + focusedRowKey: 6, + editing: { + mode: 'form', + allowUpdating: true + } +})); + +test('Focused row should not being reseted after begin edit row by API if form edit mode (T851400)', async t => { + const dataGrid = new DataGrid('#container'); + const dataRow1 = dataGrid.getDataRow(1); + + await t + .expect(dataGrid.api_option('focusedRowKey')).eql(6) + .expect(dataRow1.isFocusedRow).ok(); + + await dataGrid.api_editRow(1); + + await t.expect(dataGrid.api_option('focusedRowKey')).eql(6); + + await dataGrid.api_cancelEditData(); + + await t.expect(dataGrid.option('focusedRowKey')).eql(6); + +}).before(() => createWidget('dxDataGrid', { + dataSource: [ + { id: 5, c0: 'c0_0' }, + { id: 6, c0: 'c0_1' } + ], + keyExpr: 'id', + focusedRowEnabled: true, + focusedRowKey: 6, + editing: { + mode: 'form', + allowUpdating: true + } +})); + +test('Focused row should not fire onFocusedRowChanging, onFocusedRowChanged events on scrolling if scrolling.mode and rowRenderingMode are virtual', async t => { + const dataGrid = new DataGrid('#container'); + + await t.expect(dataGrid.getFocusedRow().exists).ok(); + + await ClientFunction(() => { + const widget = (window as any).widget; + const scrollable = widget.getScrollable(); + scrollable.scrollTo({ top: 2000 }); + })(); + await t.wait(500); + + await t.expect(ClientFunction(() => (window as any).focusedRowChanging_Counter)()).eql(undefined); + await t.expect(ClientFunction(() => (window as any).focusedRowChanged_Counter)()).eql(1); + + await ClientFunction(() => { + const widget = (window as any).widget; + const scrollable = widget.getScrollable(); + scrollable.scrollTo({ top: 0 }); + })(); + await t.wait(500); + + await t.expect(ClientFunction(() => (window as any).focusedRowChanging_Counter)()).eql(undefined); + await t.expect(ClientFunction(() => (window as any).focusedRowChanged_Counter)()).eql(1); +}).before(() => createWidget('dxDataGrid', () => { + const data = function() { + let data = []; + + for(let i = 0; i < 200; i++) { + data.push({ id: i, c0: `c0`, c1: `c1_${i % 20}` }); + } + + return data; + }(); + + return { + height: 300, + keyExpr: "id", + dataSource: data, + focusedRowEnabled: true, + focusedRowKey: 1, + editing: { + allowAdding: true, + allowUpdating: true, + mode: 'form' + }, + masterDetail: { + enabled: true, + template: container => { + container.append($("
")['dxDataGrid']({ + height: 500, + keyExpr: "id", + dataSource: data, + editing: { + allowAdding: true, + allowUpdating: true, + mode: 'batch' + } + })); + } + }, + columns: [ + 'id', + 'c0', + { + dataField: 'c1', + groupIndex: 0 + } + ], + paging: { + pageSize: 5 + }, + scrolling: { + mode: 'virtual', + rowRenderingMode: 'virtual' + }, + onFocusedRowChanging: () => { + if(!(window as any).focusedRowChanging_Counter) { + (window as any).focusedRowChanging_Counter = 0; + } + (window as any).focusedRowChanging_Counter++; + }, + onFocusedRowChanged: () => { + if(!(window as any).focusedRowChanged_Counter) { + (window as any).focusedRowChanged_Counter = 0; + } + (window as any).focusedRowChanged_Counter++; + } + }; +})); diff --git a/testing/functional/tests/dataGrid/keyboardNavigation.ts b/testing/functional/tests/dataGrid/keyboardNavigation.ts index 182d6f10b859..25277200ce49 100644 --- a/testing/functional/tests/dataGrid/keyboardNavigation.ts +++ b/testing/functional/tests/dataGrid/keyboardNavigation.ts @@ -6,7 +6,7 @@ import { Selector } from 'testcafe'; fixture `Keyboard Navigation` .page(url(__dirname, '../container.html')); -test("Cell should not highlighted after editing another cell when startEditAction is 'dblClick' and 'batch' edit mode", async t => { +test("Cell should not highlighted after editing another cell when startEditAction: dblClick and editing.mode: batch", async t => { const dataGrid = new DataGrid("#container"); await t @@ -569,18 +569,47 @@ test("Row should not be focused by 'focusedRowIndex' after change 'pageIndex' by .click(pager.getNavPage(1).element) .expect(pager.getNavPage(1).isSelected).ok() .expect(dataGrid.getFocusedRow().exists).notOk(); - }).before(() => createWidget("dxDataGrid", { - dataSource: [ - { id: 0, c0: "c0_0" }, - { id: 1, c0: "c0_1" }, - { id: 2, c0: "c0_2" }, - { id: 3, c0: "c0_3" } - ], - keyExpr: "id", - focusedRowEnabled: true, - autoNavigateToFocusedRow: false, - focusedRowIndex: 1, - paging: { - pageSize: 2 - } - })); +}).before(() => createWidget("dxDataGrid", { + dataSource: [ + { id: 0, c0: "c0_0" }, + { id: 1, c0: "c0_1" }, + { id: 2, c0: "c0_2" }, + { id: 3, c0: "c0_3" } + ], + keyExpr: "id", + focusedRowEnabled: true, + autoNavigateToFocusedRow: false, + focusedRowIndex: 1, + paging: { + pageSize: 2 + } +})); + +test("Cell should be highlighted after editing another cell when startEditAction is 'dblClick' and 'batch' edit mode if isHighlighted is set to true in onFocusedCellChanging (T836391)", async t => { + const dataGrid = new DataGrid("#container"); + + await t + .expect(dataGrid.getDataCell(0, 0).isFocused).notOk() + .expect(dataGrid.getDataCell(0, 1).isFocused).notOk() + + .doubleClick(dataGrid.getDataCell(0, 0).element) + .expect(dataGrid.getDataCell(0, 0).isFocused).ok() + .expect(dataGrid.getDataCell(0, 0).isEditCell).ok() + + .click(dataGrid.getDataCell(0, 1).element) + .expect(dataGrid.getDataCell(0, 1).isFocused).ok() + .expect(dataGrid.getDataCell(0, 0).isFocused).notOk() + .expect(dataGrid.getDataCell(0, 0).isEditCell).notOk(); +}).before(() => createWidget("dxDataGrid", { + dataSource: [ + { name: "Alex", phone: "555555", room: 1 }, + { name: "Dan", phone: "553355", room: 2 } + ], + columns:["name","phone","room"], + editing: { + mode: "batch", + allowUpdating: true, + startEditAction: "dblClick" + }, + onFocusedCellChanging: (e) => e.isHighlighted = true +})); diff --git a/testing/functional/tests/scheduler/appointmentForm.ts b/testing/functional/tests/scheduler/appointmentForm.ts index 862d318af3f5..526cc30c849f 100644 --- a/testing/functional/tests/scheduler/appointmentForm.ts +++ b/testing/functional/tests/scheduler/appointmentForm.ts @@ -49,7 +49,10 @@ test("Custom form shouldn't throw exception, after second show appointment form( const scheduler = new Scheduler("#container"); - await t.doubleClick(scheduler.getAppointment(APPOINTMENT_TEXT).element) + await t + .doubleClick(scheduler.getAppointment(APPOINTMENT_TEXT).element, { + speed: 0.1 + }) .click(CHECKBOX_CLASS) .expect(Selector(TEXT_EDITOR_CLASS).value) diff --git a/testing/functional/tests/scheduler/deleteAppointments.ts b/testing/functional/tests/scheduler/deleteAppointments.ts index 4a584458d7e4..278163efbb82 100644 --- a/testing/functional/tests/scheduler/deleteAppointments.ts +++ b/testing/functional/tests/scheduler/deleteAppointments.ts @@ -29,6 +29,7 @@ test(`Recurrence appointments should be deleted by click on 'delete' button`, as test(`Recurrence appointments should be deleted by press 'delete' key`, async t => { await t + .setTestSpeed(0.5) .expect(scheduler.getAppointmentCount()).eql(6) .click(scheduler.getAppointment("Text", 3).element) diff --git a/testing/functional/tests/scheduler/grouping/groupingByDate.ts b/testing/functional/tests/scheduler/grouping/groupingByDate.ts index 3ac19d40d237..be86d762b0b1 100644 --- a/testing/functional/tests/scheduler/grouping/groupingByDate.ts +++ b/testing/functional/tests/scheduler/grouping/groupingByDate.ts @@ -11,8 +11,10 @@ test("Drag-n-drop between dateTable and allDay panel, groupByDate=true", async t const draggableAppointment = scheduler.getAppointment("Website Re-Design Plan"); await t - .dragToElement(draggableAppointment.element, scheduler.getAllDayTableCell(1)) - .expect(draggableAppointment.size.width).eql("111px") + .dragToElement(draggableAppointment.element, scheduler.getAllDayTableCell(1), { + speed: 0.1 + }) + .expect(draggableAppointment.element.exists).ok() .expect(draggableAppointment.isAllDay).ok(); }).before(() => createScheduler({ diff --git a/testing/helpers/fileManager/file_provider.test.js b/testing/helpers/fileManager/file_provider.test.js index 9b741e9f3524..8e7fd4b3b542 100644 --- a/testing/helpers/fileManager/file_provider.test.js +++ b/testing/helpers/fileManager/file_provider.test.js @@ -1,11 +1,11 @@ import { Deferred } from 'core/utils/deferred'; -import { FileProvider } from 'ui/file_manager/file_provider/file_provider'; -import { ErrorCode } from 'ui/file_manager/ui.file_manager.common'; +import FileSystemProviderBase from 'file_management/provider_base'; +import ErrorCode from 'file_management/errors'; const DEFAULT_DELAY = 2000; -export default class TestFileProvider extends FileProvider { +export default class TestFileSystemProvider extends FileSystemProviderBase { constructor(options) { super(options); @@ -30,13 +30,13 @@ export default class TestFileProvider extends FileProvider { this._provider.renameItem(item, name); } - createFolder(parentDir, name) { - return this._doDelay(() => this._createFolderCore(parentDir, name)); + createDirectory(parentDir, name) { + return this._doDelay(() => this._createDirectoryCore(parentDir, name)); } - _createFolderCore(parentDir, name) { + _createDirectoryCore(parentDir, name) { this._raiseError(); - this._provider.createFolder(parentDir, name); + this._provider.createDirectory(parentDir, name); } deleteItems(items) { diff --git a/testing/helpers/fileManagerHelpers.js b/testing/helpers/fileManagerHelpers.js index 3fa7fcb7ecc1..b82492d97f73 100644 --- a/testing/helpers/fileManagerHelpers.js +++ b/testing/helpers/fileManagerHelpers.js @@ -1,6 +1,6 @@ import $ from 'jquery'; import { deserializeDate } from 'core/utils/date_serialization'; -import { FileManagerItem } from 'ui/file_manager/file_provider/file_provider'; +import FileSystemItem from 'file_management/file_system_item'; import FileReaderMock from './fileManager/file_reader.mock.js'; @@ -648,19 +648,19 @@ export const createSampleFileItems = () => { { id: 'Root\\Files\\Article.txt', name: 'Article.txt', dateModified: '2017-02-09T09:38:46.3772529Z', isDirectory: false, size: 1, pathInfo: filesPathInfo } ]; - const fileManagerItems = [ - createFileManagerItem(filesPathInfo, itemData[0]), - createFileManagerItem(filesPathInfo, itemData[1]), - createFileManagerItem(filesPathInfo, itemData[2]), - createFileManagerItem(filesPathInfo, itemData[3]), - createFileManagerItem(filesPathInfo, itemData[4]) + const fileSystemItems = [ + createFileSystemItem(filesPathInfo, itemData[0]), + createFileSystemItem(filesPathInfo, itemData[1]), + createFileSystemItem(filesPathInfo, itemData[2]), + createFileSystemItem(filesPathInfo, itemData[3]), + createFileSystemItem(filesPathInfo, itemData[4]) ]; - return { filesPathInfo, itemData, fileManagerItems }; + return { filesPathInfo, itemData, fileSystemItems }; }; -const createFileManagerItem = (parentPath, dataObj) => { - const item = new FileManagerItem(parentPath, dataObj.name, dataObj.isDirectory); +const createFileSystemItem = (parentPath, dataObj) => { + const item = new FileSystemItem(parentPath, dataObj.name, dataObj.isDirectory); item.dateModified = deserializeDate(dataObj.dateModified); item.size = dataObj.size; item.dataItem = dataObj; diff --git a/testing/helpers/grid/keyboardNavigationHelper.js b/testing/helpers/grid/keyboardNavigationHelper.js index f6d009a1067a..3b492393432d 100644 --- a/testing/helpers/grid/keyboardNavigationHelper.js +++ b/testing/helpers/grid/keyboardNavigationHelper.js @@ -84,7 +84,7 @@ export function setupModules(that, modulesOptions, gridModules) { }); } -export const CLICK_EVENT = eventUtils.addNamespace(pointerEvents.up, 'dxDataGridKeyboardNavigation'); +export const CLICK_EVENT = eventUtils.addNamespace(pointerEvents.down, 'dxDataGridKeyboardNavigation'); const device = devices.real(); const KEYS = { 'tab': 'Tab', @@ -152,9 +152,8 @@ export function fireKeyDown($target, key, ctrlKey) { } export function focusCell(columnIndex, rowIndex) { - const $element0 = this.rowsView.element(); - const $row = $($element0.find('.dx-row')[rowIndex]); - $($row.find('td')[columnIndex]).trigger(CLICK_EVENT); + const $cell = $(this.rowsView.getCellElement(rowIndex, columnIndex)); + $cell.trigger(CLICK_EVENT); } export function getTextSelection(element) { diff --git a/testing/helpers/ignoreAngularTimers.js b/testing/helpers/ignoreAngularTimers.js new file mode 100644 index 000000000000..e45ac443308d --- /dev/null +++ b/testing/helpers/ignoreAngularTimers.js @@ -0,0 +1,22 @@ +QUnit.timersDetector.ignoreRules.register(function(args) { + const timerType = args.timerType; + const callback = String(args.callback).replace(/\s|"use strict";/g, ''); + + // NOTE: + // 1. Implementation: https://github.com/angular/angular.js/blob/v1.5.x/src/ng/raf.js#L29 + // 2. Usage: https://github.com/angular/angular.js/blob/v1.5.x/src/ng/animateRunner.js#L10 + if(timerType === 'animationFrames' && [ + 'function(){for(vara=0;a -1) { + return true; + } + + if( + timerType === 'timeouts' && + (callback.indexOf('delete pendingDeferIds[timeoutId];') > -1 || + callback.indexOf('delete F[c];e(a)}') > -1) + ) { + return true; + } +}); diff --git a/testing/helpers/ignoreQuillTimers.js b/testing/helpers/ignoreQuillTimers.js new file mode 100644 index 000000000000..3f02f9928715 --- /dev/null +++ b/testing/helpers/ignoreQuillTimers.js @@ -0,0 +1,14 @@ +QUnit.timersDetector.ignoreRules.register(function(args) { + const timerType = args.timerType; + const callback = String(args.callback).replace(/\s/g, ''); + const stack = args.stack; + + if( + timerType === 'timeouts' && + /handleDOM.*quill.js/.test(stack) && + callback.indexOf('function(){[nativecode]}') > -1 + ) { + return true; + } + +}); diff --git a/testing/helpers/qunitExtensions.js b/testing/helpers/qunitExtensions.js index db534cb56bfa..641b27230d78 100644 --- a/testing/helpers/qunitExtensions.js +++ b/testing/helpers/qunitExtensions.js @@ -94,11 +94,9 @@ container.setAttribute('id', uniqueName); if(css) { - for(const prop in css) { - if(Object.prototype.hasOwnProperty.call(css, prop)) { - container.style[prop] = css[prop]; - } - } + Object.keys(css).forEach(function(prop) { + container.style[prop] = css[prop]; + }); } const parent = document.querySelector(parentSelector); @@ -137,13 +135,30 @@ }); }; + const beforeTestDoneCallbacks = []; + + QUnit.beforeTestDone = function(callback) { + beforeTestDoneCallbacks.push(callback); + }; + + QUnit.testStart(function() { + const after = QUnit.config.current.after; + + QUnit.config.current.after = function() { + beforeTestDoneCallbacks.forEach(function(callback) { + callback(); + }); + return after.apply(this, arguments); + }; + }); + }(); (function clearQUnitFixtureByJQuery() { const isMsEdge = 'CollectGarbage' in window && !('ActiveXObject' in window); - QUnit.testDone(function(options) { + QUnit.beforeTestDone(function(options) { if(!jQuery) { return; } @@ -164,47 +179,29 @@ tooltip: 'Enabling this will test if any test introduces timers (setTimeout, setInterval, ....) and does not cleared them on test finalization. Stored as query-strings.' }); - QUnit.timerIgnoringCheckers = (function() { - const noop = function() { }; - - return { - register: noop, - unregister: noop, - applyUnregister: noop, - clear: noop, - needSkip: noop - }; - })(); - const createMethodWrapper = function(method, callbacks) { - const originalMethod = method; - const beforeCall = callbacks['beforeCall']; - const afterCall = callbacks['afterCall']; - const info = { - originalMethod: originalMethod - }; - - const wrapper = function() { - info['context'] = this; - info['args'] = Array.prototype.slice.call(arguments); + const beforeCall = callbacks.beforeCall; + const afterCall = callbacks.afterCall; + + return function() { + const info = { + method: method, + context: this, + args: Array.prototype.slice.call(arguments) + }; if(typeof beforeCall === 'function') { beforeCall(info); } - info['result'] = originalMethod.apply(info.context, info.args); + info.returnValue = method.apply(info.context, info.args); if(typeof afterCall === 'function') { afterCall(info); } - return info['result']; + return info.returnValue; }; - - info['wrapper'] = wrapper; - wrapper['info'] = info; - - return wrapper; }; const getStack = function() { @@ -213,13 +210,12 @@ return stack; }; - const saveTimerInfo = function(logObject, id, info) { + const saveTimerInfo = function(logObject, info) { info.stack = getStack(); info.callback = info.callback.toString(); - logObject[id] = info; + logObject[info.timerId] = info; }; - const spyWindowMethods = function(windowObj) { let log; let logEnabled; @@ -236,13 +232,13 @@ return; } - info.originalCallback = info.args[0]; - const callbackWrapper = info.args[0] = createMethodWrapper(info.originalCallback, { + info.callback = info.args[0]; + info.args[0] = createMethodWrapper(info.callback, { afterCall: function() { if(!logEnabled) { return; } - delete timeouts[callbackWrapper.timerID]; + delete timeouts[info.returnValue]; } }); }, @@ -252,9 +248,10 @@ return; } - info.args[0]['timerID'] = info.result; - saveTimerInfo(timeouts, info.result, { - callback: info.originalCallback, + saveTimerInfo(timeouts, { + timerType: 'timeouts', + timerId: info.returnValue, + callback: info.callback, timeout: info.args[1] }); } @@ -274,7 +271,10 @@ if(!logEnabled) { return; } - saveTimerInfo(intervals, info.result, { + const timerId = info.returnValue; + saveTimerInfo(intervals, { + timerType: 'intervals', + timerId: timerId, callback: info.args[0], timeout: info.args[1] }); @@ -296,13 +296,13 @@ return; } - info.originalCallback = info.args[0]; - const callBackWrapper = info.args[0] = createMethodWrapper(info.originalCallback, { + info.callback = info.args[0]; + info.args[0] = createMethodWrapper(info.callback, { afterCall: function() { if(!logEnabled) { return; } - delete animationFrames[callBackWrapper.timerID]; + delete animationFrames[info.returnValue]; } }); }, @@ -311,9 +311,10 @@ return; } - info.args[0]['timerID'] = info.result; - saveTimerInfo(animationFrames, info.result, { - callback: info.originalCallback + saveTimerInfo(animationFrames, { + timerType: 'animationFrames', + timerId: info.returnValue, + callback: info.callback }); } }, @@ -329,15 +330,14 @@ } }; - let name; - for(name in methodHooks) { + Object.keys(methodHooks).forEach(function(name) { windowObj[name] = createMethodWrapper(windowObj[name], methodHooks[name]); - } + }); const initLog = function() { log = {}; - timeouts = log['timeouts'] = {}, - intervals = log['intervals'] = {}, + timeouts = log['timeouts'] = {}; + intervals = log['intervals'] = {}; animationFrames = log['animationFrames'] = {}; }; @@ -363,130 +363,92 @@ }; }; + const ignoreRules = (function() { + let rules = []; + + return { + register: function() { + Array.prototype.push.apply(rules, arguments); + }, + unregister: function() { + Array.prototype.forEach.call(arguments, function(rule) { + const index = rules.indexOf(rule); + rules.splice(index, 1); + }); + }, + clear: function() { + rules = []; + }, + shouldIgnore: function(timerInfo) { + let skip = false; + + rules.forEach(function(rule) { + if(rule(timerInfo)) { + skip = true; + return false; + } + }); + + return skip; + } + }; + })(); + QUnit.timersDetector = { - spyWindowMethods: spyWindowMethods + spyWindowMethods: spyWindowMethods, + ignoreRules: ignoreRules }; if(!QUnit.urlParams['notimers']) { return; } - const suppressLogOnTest = function() { - return /Not cleared timers detected/.test(QUnit.config.current.testName); - }; - const log = spyWindowMethods(); - QUnit.timerIgnoringCheckers = (function() { - let checkers = []; - let checkersToUnregister = []; - - const register = function() { - Array.prototype.push.apply(checkers, arguments); - }; - - const unregister = function() { - Array.prototype.push.apply(checkersToUnregister, arguments); - }; - - const unregisterSingle = function(checker) { - const index = checkers.indexOf(checker); - - checkers.splice(index, 1); - }; + ignoreRules.register(function isThirdPartyLibraryTimer(timerInfo) { + const callback = String(timerInfo.callback).replace(/\s/g, ''); + const timerType = timerInfo.timerType; - const applyUnregister = function() { - checkersToUnregister.forEach(unregisterSingle); - checkersToUnregister = []; - }; + if(timerType === 'timeouts') { + if( + callback.indexOf('.Deferred.exceptionHook') > -1 || // NOTE: jQuery.Deferred are now asynchronous + callback.indexOf('e._drain()') > -1 // NOTE: SystemJS Promise polyfill + ) { + return true; + } - const clear = function() { - checkers = []; - checkersToUnregister = []; - }; + if( + window.navigator.userAgent.indexOf('Edge/') > -1 && // NOTE: Native Promise in Edge + callback.indexOf('function(){[nativecode]}') > -1 + ) { + return true; + } + } - const needSkip = function(timerInfo) { - let skip = false; + if(callback.indexOf('function(){clearTimeout(u),cancelAnimationFrame(t),setTimeout(n)}') > -1) return true; // NOTE: Preact + if(callback.indexOf('.__H.u.forEach(') > -1) return true; // NOTE: Preact hooks + }); - checkers.forEach(function(checker) { - if(checker(timerInfo)) { - skip = true; - return false; - } - }); + const logTestFailure = function(timerInfo) { + const timeoutString = timerInfo.timeout ? '\nTimeout: ' + timerInfo.timeout : ''; - return skip; - }; + const message = [ + 'Not cleared timer detected.\n', + '\n', + 'Timer type: ', timerInfo.timerType, '\n', + 'Id: ', timerInfo.timerId, '\n', + 'Callback:\n', timerInfo.callback, '\n', + timeoutString + ].join(''); - return { - register: register, - unregister: unregister, - applyUnregister: applyUnregister, - clear: clear, - needSkip: needSkip - }; - })(); + QUnit.pushFailure(message, timerInfo.stack); + }; QUnit.testStart(function() { - if(suppressLogOnTest()) { - return; - } log.start(); }); - QUnit.testDone(function(args) { - if(suppressLogOnTest()) { - return; - } - - const logGlobalFailure = function(details) { - const timerInfo = details.timerInfo; - const timeoutString = timerInfo.timeout ? ', timeout: ' + timerInfo.timeout : ''; - const message = ['Timer type: ', timerInfo.timerType, ', Id: ', timerInfo.timerId, timeoutString, '\nCallback:\n', timerInfo.callback].join(''); - - const testCallback = function() { - QUnit.pushFailure(message, timerInfo.stack || '1 timer'); - }; - - testCallback.validTest = true; - - QUnit.module('Not cleared timers detected! ' + details.moduleName); - QUnit.test(details.testName, testCallback); - }; - - const isThirdPartyLibraryTimer = function(timerInfo) { - if(!timerInfo || !timerInfo.callback) { - return false; - } - const callback = String(timerInfo.callback).replace(/\s|"use strict";/g, ''); - - if(callback.indexOf('function(){clearTimeout(u),cancelAnimationFrame(t),setTimeout(n)}') > -1) return true; // NOTE: Preact - if(callback.indexOf('.__H.u.forEach(') > -1) return true; // NOTE: Preact hooks - if(timerInfo.timerType === 'animationFrames' && - [ - 'function(){for(vara=0;a -1) { - // NOTE: Special thanks for Angular team - // 1. Implementation: https://github.com/angular/angular.js/blob/v1.5.x/src/ng/raf.js#L29 - // 2. Usage: https://github.com/angular/angular.js/blob/v1.5.x/src/ng/animateRunner.js#L10 - - return true; - } - - if(timerInfo.timerType === 'timeouts' && - (callback.indexOf('.Deferred.exceptionHook') > -1 || // NOTE: jQuery.Deferred are now asynchronous - callback.indexOf('e._drain()') > -1)) { // NOTE: SystemJS Promise polyfill - return true; - } - - if(timerInfo.timerType === 'timeouts' && - window.navigator.userAgent.indexOf('Edge/') > -1 && // NOTE: Only in Edge - callback.indexOf('function(){[nativecode]}') > -1) { // NOTE: Native Promise - return true; - } - }; - + QUnit.beforeTestDone(function() { log.stop(); ['timeouts', 'intervals', 'animationFrames'].forEach(function(type) { @@ -494,47 +456,31 @@ if(Object.keys(currentInfo).length) { const timerId = Object.keys(currentInfo)[0]; + const timerInfo = currentInfo[timerId]; - const normalizedTimerInfo = { - timerType: type, - timerId: timerId, - callback: currentInfo[timerId].callback || currentInfo.callback, - timeout: currentInfo[timerId].timeout || currentInfo.timeout, - stack: currentInfo[timerId].stack || currentInfo.stack - }; - - if(isThirdPartyLibraryTimer(normalizedTimerInfo)) { - return; - } - - if(QUnit.timerIgnoringCheckers.needSkip(normalizedTimerInfo)) { + if(ignoreRules.shouldIgnore(timerInfo)) { return; } - logGlobalFailure({ - moduleName: args.module, - testName: args.name, - timerInfo: normalizedTimerInfo - }); + logTestFailure(timerInfo); } }); - QUnit.timerIgnoringCheckers.applyUnregister(); log.clear(); }); })(); (function checkSinonFakeTimers() { + let dateOnTestStart; QUnit.testStart(function() { - const dateOnTestStart = Date; const after = QUnit.config.current.after; + dateOnTestStart = Date; + }); - QUnit.config.current.after = function() { - if(dateOnTestStart !== Date) { - QUnit.pushFailure('Not restored Sinon timers detected!', this.stack); - } - return after.apply(this, arguments); - }; + QUnit.beforeTestDone(function() { + if(dateOnTestStart !== Date) { + QUnit.pushFailure('Not restored Sinon timers detected!', this.stack); + } }); })(); diff --git a/testing/helpers/ssrEmulator.js b/testing/helpers/ssrEmulator.js index 1bc10017a754..b4e882c0554f 100644 --- a/testing/helpers/ssrEmulator.js +++ b/testing/helpers/ssrEmulator.js @@ -217,12 +217,10 @@ for(const field in window) { } const makeWindowEmpty = function() { - windowUtils.hasWindow = function() { - return false; - }; - windowUtils.getWindow = function() { - return windowMock; - }; + windowUtils.hasWindow = () => false; + windowUtils.getWindow = () => windowMock; + windowUtils.getNavigator = () => ({ userAgent: '' }); + windowUtils.hasProperty = () => false; }; // Ensure domAdapter is not used on scripts loading stage (until the integration is not injected) diff --git a/testing/helpers/wrappers/dataGridWrappers.js b/testing/helpers/wrappers/dataGridWrappers.js index c34b45bdf6a4..588c15c346ea 100644 --- a/testing/helpers/wrappers/dataGridWrappers.js +++ b/testing/helpers/wrappers/dataGridWrappers.js @@ -23,6 +23,8 @@ const HEADER_COLUMN_INDICATORS_CLASS = 'dx-column-indicators'; const GRID_TABLE_CLASS = 'dx-datagrid-table'; const FREE_SPACE_ROW = 'dx-freespace-row'; const ROW_CLASS = 'dx-row'; +const COMMAND_EDIT_CLASS = 'dx-command-edit'; +const COMMAND_BUTTON_CLASS = 'dx-link'; class GridWrapper extends WrapperBase { constructor(containerSelector, widgetPrefix) { @@ -123,6 +125,17 @@ export class RowsViewWrapper extends GridTableElement { return this.getDataRowElement(rowIndex).find('td').eq(columnIndex); } + getCommandButton(rowIndex, commandColumnIndex, buttonIndex) { + const $dataRow = this.getDataRowElement(rowIndex); + const $commandCell = $dataRow + .find(`.${COMMAND_EDIT_CLASS}`) + .eq(commandColumnIndex); + + return $commandCell + .find(`.${COMMAND_BUTTON_CLASS}`) + .eq(buttonIndex); + } + getFixedDataCellElement(rowIndex, columnIndex) { return this.getFixedDataRowElement(rowIndex).find('td').eq(columnIndex); } diff --git a/testing/runner/Controllers/MainController.cs b/testing/runner/Controllers/MainController.cs index 37e7070101ef..a2df5afe05f2 100644 --- a/testing/runner/Controllers/MainController.cs +++ b/testing/runner/Controllers/MainController.cs @@ -112,6 +112,9 @@ public void NotifySuiteFinalized(string name, bool passed) } Console.ResetColor(); Console.WriteLine("] " + name); + + if (_runFlags.IsContinuousIntegration) + IOFile.WriteAllText(Path.Combine(_env.ContentRootPath, "testing/LastSuiteTime.txt"), DateTime.Now.ToString("s")); } } diff --git a/testing/runner/Program.cs b/testing/runner/Program.cs index a9a863092ad6..47424a8f4ab7 100644 --- a/testing/runner/Program.cs +++ b/testing/runner/Program.cs @@ -32,7 +32,10 @@ public static int Main(string[] argv) .ConfigureServices(services => { services - .AddMvc() + .AddMvcCore() + .AddViews() + .AddRazorViewEngine() + .AddJsonFormatters() .AddJsonOptions(options => options.SerializerSettings.ContractResolver = new DefaultContractResolver()); services.AddWebEncoders(); diff --git a/testing/runner/Views/Main/RunSuite.cshtml b/testing/runner/Views/Main/RunSuite.cshtml index e0296e4e73f8..94bc98d52391 100644 --- a/testing/runner/Views/Main/RunSuite.cshtml +++ b/testing/runner/Views/Main/RunSuite.cshtml @@ -6,7 +6,6 @@ || Model.ScriptVirtualPath.Contains("Bundles") || Model.ScriptVirtualPath.Contains("DevExpress.angular") || Model.ScriptVirtualPath.Contains("DevExpress.jquery"); - var isIntlTest = Model.ScriptVirtualPath.Contains("intl.tests"); string GetJQueryUrl() { if(isNoJQueryTest) @@ -35,9 +34,6 @@ } yield return Url.Content("~/testing/helpers/noIntl.js"); - if(isIntlTest) { - yield return Url.Content("~/node_modules/intl/index.js"); - } } } @@ -167,6 +163,7 @@ map: { // Deps 'globalize': '@Url.Content("~/artifacts/js/globalize")', + 'intl': '@Url.Content("~/node_modules/intl/index.js")', 'cldr': '@Url.Content("~/artifacts/js/cldr")', 'jquery': '@GetJQueryUrl()', 'knockout': '@Url.Content("~/node_modules/knockout/build/output/knockout-latest.debug.js")', diff --git a/testing/runner/runner.csproj b/testing/runner/runner.csproj index ae363495fe41..7c9c18660cf5 100644 --- a/testing/runner/runner.csproj +++ b/testing/runner/runner.csproj @@ -2,11 +2,10 @@ - - - + + diff --git a/testing/tests/DevExpress.angular/componentRegistration.tests.js b/testing/tests/DevExpress.angular/componentRegistration.tests.js index 70c81910520f..99317bb37eb4 100644 --- a/testing/tests/DevExpress.angular/componentRegistration.tests.js +++ b/testing/tests/DevExpress.angular/componentRegistration.tests.js @@ -15,9 +15,9 @@ import 'integration/angular'; import 'ui/list'; import 'ui/button'; -const FIXTURE_ELEMENT = () => $('#qunit-fixture'); +import '../../helpers/ignoreAngularTimers.js'; -const ignoreAngularBrowserDeferTimer = args => args.timerType === 'timeouts' && (args.callback.toString().indexOf('delete pendingDeferIds[timeoutId];') > -1 || args.callback.toString().indexOf('delete F[c];e(a)}') > -1); +const FIXTURE_ELEMENT = () => $('#qunit-fixture'); QUnit.module('simple component tests', { beforeEach() { @@ -46,11 +46,6 @@ QUnit.module('simple component tests', { .appendTo(this.$container); registerComponent('dxTest', TestComponent); - - QUnit.timerIgnoringCheckers.register(ignoreAngularBrowserDeferTimer); - }, - afterEach() { - QUnit.timerIgnoringCheckers.unregister(ignoreAngularBrowserDeferTimer); } }); @@ -1421,11 +1416,6 @@ QUnit.module('nested Widget with templates enabled', { registerComponent('dxTestContainer', TestContainer); registerComponent('dxTestWidget', TestWidget); - - QUnit.timerIgnoringCheckers.register(ignoreAngularBrowserDeferTimer); - }, - afterEach() { - QUnit.timerIgnoringCheckers.unregister(ignoreAngularBrowserDeferTimer); } }); @@ -1638,11 +1628,6 @@ QUnit.test('Multi-slot transclusion should work with dx temapltes', function(ass QUnit.module('Widget & CollectionWidget with templates enabled', { beforeEach() { this.testApp = angular.module('testApp', ['dx']); - - QUnit.timerIgnoringCheckers.register(ignoreAngularBrowserDeferTimer); - }, - afterEach() { - QUnit.timerIgnoringCheckers.unregister(ignoreAngularBrowserDeferTimer); } }); @@ -1970,14 +1955,7 @@ QUnit.test('Widget options does not override scope properties', function(assert) assert.equal($.trim($markup.text()), 'Controller model'); }); -QUnit.module('ui.collectionWidget', { - beforeEach() { - QUnit.timerIgnoringCheckers.register(ignoreAngularBrowserDeferTimer); - }, - afterEach() { - QUnit.timerIgnoringCheckers.unregister(ignoreAngularBrowserDeferTimer); - } -}); +QUnit.module('ui.collectionWidget'); const initMarkup = ($markup, controller) => { const TestCollectionContainer = CollectionWidget.inherit({ @@ -2350,10 +2328,6 @@ QUnit.test('$id in item model not caused exception', function(assert) { QUnit.module('misc and regressions', { beforeEach() { this.testApp = angular.module('testApp', ['dx']); - QUnit.timerIgnoringCheckers.register(ignoreAngularBrowserDeferTimer); - }, - afterEach() { - QUnit.timerIgnoringCheckers.unregister(ignoreAngularBrowserDeferTimer); } }); @@ -2738,11 +2712,6 @@ QUnit.module('component action context', { .appendTo(this.$container); registerComponent('dxActionTest', TestComponent); - - QUnit.timerIgnoringCheckers.register(ignoreAngularBrowserDeferTimer); - }, - afterEach() { - QUnit.timerIgnoringCheckers.unregister(ignoreAngularBrowserDeferTimer); } }); @@ -2899,11 +2868,6 @@ QUnit.module('dxComponent as a template', { this.$container = $('
').appendTo(FIXTURE_ELEMENT()); registerComponent('dxTemplateComponent', TemplateComponent); - - QUnit.timerIgnoringCheckers.register(ignoreAngularBrowserDeferTimer); - }, - afterEach() { - QUnit.timerIgnoringCheckers.unregister(ignoreAngularBrowserDeferTimer); } }); diff --git a/testing/tests/DevExpress.angular/modelIntegration.tests.js b/testing/tests/DevExpress.angular/modelIntegration.tests.js index 214d57ff2606..98efb7e1ddf1 100644 --- a/testing/tests/DevExpress.angular/modelIntegration.tests.js +++ b/testing/tests/DevExpress.angular/modelIntegration.tests.js @@ -9,9 +9,7 @@ import inflector from 'core/utils/inflector'; import 'ui/tag_box'; import 'integration/angular'; -const ignoreAngularBrowserDeferTimer = args => { - return args.timerType === 'timeouts' && (args.callback.toString().indexOf('delete pendingDeferIds[timeoutId];') > -1 || args.callback.toString().indexOf('delete F[c];e(a)}') > -1); -}; +import '../../helpers/ignoreAngularTimers.js'; QUnit.module('ngmodel editor integration', { beforeEach() { @@ -42,13 +40,9 @@ QUnit.module('ngmodel editor integration', { registerComponent('dxMultiEditor', MultiEditor); registerComponent('dxWidget', Widget); - - QUnit.timerIgnoringCheckers.register(ignoreAngularBrowserDeferTimer); }, afterEach() { this.$fixtureElement.remove(); - - QUnit.timerIgnoringCheckers.unregister(ignoreAngularBrowserDeferTimer); } }); diff --git a/testing/tests/DevExpress.angular/widgets.tests.js b/testing/tests/DevExpress.angular/widgets.tests.js index 8d3c9f40f814..cb6637bdeb32 100644 --- a/testing/tests/DevExpress.angular/widgets.tests.js +++ b/testing/tests/DevExpress.angular/widgets.tests.js @@ -27,12 +27,11 @@ require('ui/tabs'); require('ui/text_box'); require('ui/toolbar'); +require('../../helpers/ignoreAngularTimers.js'); + const FILTERING_TIMEOUT = 700; fx.off = true; -const ignoreAngularBrowserDeferTimer = function(args) { - return args.timerType === 'timeouts' && (args.callback.toString().indexOf('delete pendingDeferIds[timeoutId];') > -1 || args.callback.toString().indexOf('delete F[c];e(a)}') > -1); -}; const initMarkup = function($markup, controller, context) { context.testApp = angular.module('testApp', ['dx']); @@ -372,11 +371,9 @@ QUnit.test('dxTabs - navigation buttons should show/hide after showing/hiding it QUnit.module('dxDataGrid', { beforeEach: function() { - QUnit.timerIgnoringCheckers.register(ignoreAngularBrowserDeferTimer); this.clock = sinon.useFakeTimers(); }, afterEach: function() { - QUnit.timerIgnoringCheckers.unregister(ignoreAngularBrowserDeferTimer); this.clock.restore(); } }); @@ -625,14 +622,7 @@ QUnit.test('Scope refreshing count on init', function(assert) { assert.equal(refreshingCount, 4); }); -QUnit.module('Adaptive menu', { - beforeEach: function() { - QUnit.timerIgnoringCheckers.register(ignoreAngularBrowserDeferTimer); - }, - afterEach: function() { - QUnit.timerIgnoringCheckers.unregister(ignoreAngularBrowserDeferTimer); - } -}); +QUnit.module('Adaptive menu'); QUnit.test('Adaptive menu should support angular integration', function(assert) { const $markup = $('\ @@ -730,14 +720,7 @@ QUnit.test('The hamburger button should be visible on small screen (T377800)', f }); -QUnit.module('toolbar', { - beforeEach: function() { - QUnit.timerIgnoringCheckers.register(ignoreAngularBrowserDeferTimer); - }, - afterEach: function() { - QUnit.timerIgnoringCheckers.unregister(ignoreAngularBrowserDeferTimer); - } -}); +QUnit.module('toolbar'); QUnit.test('polymorph widget correctly renders nested widgets', function(assert) { const $markup = $('\ @@ -898,14 +881,7 @@ QUnit.test('not cleared timers not detected', function(assert) { }); -QUnit.module('box', { - beforeEach: function() { - QUnit.timerIgnoringCheckers.register(ignoreAngularBrowserDeferTimer); - }, - afterEach: function() { - QUnit.timerIgnoringCheckers.unregister(ignoreAngularBrowserDeferTimer); - } -}); +QUnit.module('box'); QUnit.test('innerBox with nested box item', function(assert) { const $markup = $('\ @@ -953,14 +929,7 @@ QUnit.test('dxDateBox with list strategy automatically scrolls to selected item assert.ok($popupContent.offset().top + $popupContent.height() > $selectedItem.offset().top, 'selected item is visible'); }); -QUnit.module('tree view', { - beforeEach: function() { - QUnit.timerIgnoringCheckers.register(ignoreAngularBrowserDeferTimer); - }, - afterEach: function() { - QUnit.timerIgnoringCheckers.unregister(ignoreAngularBrowserDeferTimer); - } -}); +QUnit.module('tree view'); QUnit.test('tree view should not crash with complex ids', function(assert) { assert.expect(0); @@ -994,11 +963,9 @@ QUnit.test('tree view should not crash with complex ids', function(assert) { QUnit.module('dxScheduler', { beforeEach: function() { - QUnit.timerIgnoringCheckers.register(ignoreAngularBrowserDeferTimer); this.clock = sinon.useFakeTimers(); }, afterEach: function() { - QUnit.timerIgnoringCheckers.unregister(ignoreAngularBrowserDeferTimer); this.clock.restore(); } }); @@ -1040,11 +1007,9 @@ QUnit.test('Custom store with ISO8601 dates', function(assert) { QUnit.module('Widgets without model for template', { beforeEach: function() { this.clock = sinon.useFakeTimers(); - QUnit.timerIgnoringCheckers.register(ignoreAngularBrowserDeferTimer); }, afterEach: function() { this.clock.restore(); - QUnit.timerIgnoringCheckers.unregister(ignoreAngularBrowserDeferTimer); } }); @@ -1160,10 +1125,6 @@ QUnit.test('Scope for template with \'noModel\' option is not destroyed after cl QUnit.module('dxValidator', { beforeEach: function() { this.testApp = angular.module('testApp', ['dx']); - QUnit.timerIgnoringCheckers.register(ignoreAngularBrowserDeferTimer); - }, - afterEach: function() { - QUnit.timerIgnoringCheckers.unregister(ignoreAngularBrowserDeferTimer); } }); diff --git a/testing/tests/DevExpress.aspnet/aspnet.tests.js b/testing/tests/DevExpress.aspnet/aspnet.tests.js index 8d51c56ed216..c0012b70d84a 100644 --- a/testing/tests/DevExpress.aspnet/aspnet.tests.js +++ b/testing/tests/DevExpress.aspnet/aspnet.tests.js @@ -18,7 +18,8 @@ require('core/templates/template_engine_registry').setTemplateEngine, aspnet, function() { return require('ui/widget/ui.errors'); }, - function() { return require('../../helpers/ajaxMock.js'); } + function() { return require('../../helpers/ajaxMock.js'); }, + require('core/utils/console') ); }); } else { @@ -27,10 +28,11 @@ DevExpress.setTemplateEngine, DevExpress.aspnet, function() { return window.DevExpress_ui_widget_errors; }, - function() { return window.ajaxMock; } + function() { return window.ajaxMock; }, + DevExpress.utils.console ); } -}(function($, setTemplateEngine, aspnet, errorsAccessor, ajaxMockAccessor) { +}(function($, setTemplateEngine, aspnet, errorsAccessor, ajaxMockAccessor, console) { if(QUnit.urlParams['nojquery']) { return; @@ -399,7 +401,7 @@ aspnet.setTemplateEngine(); const errors = errorsAccessor(); - sinon.spy(errors, 'log'); + const spy = sinon.spy(errors, 'log'); try { const formID = 'bd859c15-674f-49bf-a6d0-9368508e8d11'; @@ -460,6 +462,7 @@ } finally { setTemplateEngine('default'); + spy.restore(); delete window.__createForm; delete window.__createTextBox; } @@ -521,6 +524,28 @@ } }); + QUnit.test('Warn https://github.com/dotnet/aspnetcore/issues/17028', function(assert) { + aspnet.setTemplateEngine(); + const spy = sinon.spy(console.logger, 'warn'); + try { + aspnet.warnBug17028(); + + $('#qunit-fixture').html(` +
+
+ + `); + + [1, 2].forEach(i => $('#widget' + i).dxButton({ template: $('#template1') })); + + assert.equal(spy.callCount, 1); + assert.ok(spy.args[0][0].indexOf('alternative template syntax') > -1); + } finally { + setTemplateEngine('default'); + spy.restore(); + } + }); + QUnit.module('Remote validation', { beforeEach: function() { this.ajaxMock = ajaxMockAccessor(); diff --git a/testing/tests/DevExpress.core/utils.ajax.tests.js b/testing/tests/DevExpress.core/utils.ajax.tests.js index 45b5879c6b64..fbfb68bb0c84 100644 --- a/testing/tests/DevExpress.core/utils.ajax.tests.js +++ b/testing/tests/DevExpress.core/utils.ajax.tests.js @@ -717,7 +717,7 @@ QUnit.test('Script request (cross domain)', function(assert) { const addedScript = appendChild.firstCall.args[0]; - assert.ok(addedScript.src.indexOf('http://somefakedomain1221.com/json-url?_=') === 0, 'url: ' + addedScript.src); + assert.strictEqual(addedScript.src.indexOf('http://somefakedomain1221.com/json-url?_='), 0, 'url: ' + addedScript.src); appendChild.restore(); createElement.restore(); diff --git a/testing/tests/DevExpress.core/utils.position.tests.js b/testing/tests/DevExpress.core/utils.position.tests.js new file mode 100644 index 000000000000..2502f44821d4 --- /dev/null +++ b/testing/tests/DevExpress.core/utils.position.tests.js @@ -0,0 +1,31 @@ +import config from 'core/config'; +import { getDefaultAlignment } from 'core/utils/position.js'; + +const { module: testModule, test } = QUnit; + +testModule('getDefaultAlignment', function() { + test('getDefaultAlignment should return an alignment depending on the global "rtlEnabled" config or passed value', function(assert) { + const originalConfig = config(); + + try { + config({ + rtlEnabled: false + }); + + assert.strictEqual(getDefaultAlignment(), 'left', '"isRtlEnabled" argument is undefined, global "rtlEnabled" config is false'); + assert.strictEqual(getDefaultAlignment(true), 'right', '"isRtlEnabled" argument is true, global "rtlEnabled" config is false'); + assert.strictEqual(getDefaultAlignment(false), 'left', '"isRtlEnabled" argument is false, global "rtlEnabled" config is false'); + + config({ + rtlEnabled: true + }); + + assert.strictEqual(getDefaultAlignment(), 'right', '"isRtlEnabled" argument is undefined, global "rtlEnabled" config is true'); + assert.strictEqual(getDefaultAlignment(true), 'right', '"isRtlEnabled" argument is true, global "rtlEnabled" config is true'); + assert.strictEqual(getDefaultAlignment(false), 'left', '"isRtlEnabled" argument is false, global "rtlEnabled" config is true'); + + } finally { + config(originalConfig); + } + }); +}); diff --git a/testing/tests/DevExpress.data/dataSourceCreating.tests.js b/testing/tests/DevExpress.data/dataSourceCreating.tests.js index 034f7d109b27..9ed045351c19 100644 --- a/testing/tests/DevExpress.data/dataSourceCreating.tests.js +++ b/testing/tests/DevExpress.data/dataSourceCreating.tests.js @@ -86,7 +86,7 @@ QUnit.test('options.store is ODataStore config', function(assert) { }); assert.ok(source.store() instanceof ODataStore); - assert.equal(source.store()._url, url); + assert.equal(source.store()._requestDispatcher.url, url); }); QUnit.test('options.store is LocalStore config', function(assert) { diff --git a/testing/tests/DevExpress.data/odataStore.tests.js b/testing/tests/DevExpress.data/odataStore.tests.js index 681131975802..94689c558474 100644 --- a/testing/tests/DevExpress.data/odataStore.tests.js +++ b/testing/tests/DevExpress.data/odataStore.tests.js @@ -690,7 +690,7 @@ QUnit.test('Guid as key', function(assert) { new ODataStore({ version: 4, url: 'odata2.org' }) .byKey(new Guid(guid)) .done(function(r) { - assert.ok(r.url.indexOf('(guid\'' + guid + '\')') === -1); + assert.strictEqual(r.url.indexOf('(guid\'' + guid + '\')'), -1); assert.ok(r.url.indexOf(guid) > 1); }) ]; @@ -1489,7 +1489,7 @@ QUnit.test('works', function(assert) { }); const handleBeforeSend = function(request) { - assert.ok(request.url.indexOf('DataSet(1)') === 11); + assert.strictEqual(request.url.indexOf('DataSet(1)'), 11); assert.equal(request.method.toLowerCase(), 'delete'); }; @@ -1737,12 +1737,12 @@ QUnit.test('Dates, disableable, ODataStore', function(assert) { const promises = [ store.load() .done(function(r) { - assert.ok(typeof r[0].dateProperty === 'string'); + assert.strictEqual(typeof r[0].dateProperty, 'string'); }), store.byKey(1) .done(function(r) { - assert.ok(typeof r.dateProperty === 'string'); + assert.strictEqual(typeof r.dateProperty, 'string'); }) ]; @@ -1784,22 +1784,22 @@ QUnit.test('Dates, disableable, ODataContext', function(assert) { const promises = [ ctx.get('function') .done(function(r) { - assert.ok(typeof r.dateProperty === 'string'); + assert.strictEqual(typeof r.dateProperty, 'string'); }), ctx.invoke('action') .done(function(r) { - assert.ok(typeof r.dateProperty === 'string'); + assert.strictEqual(typeof r.dateProperty, 'string'); }), ctx.X.load() .done(function(r) { - assert.ok(typeof r[0].dateProperty === 'string'); + assert.strictEqual(typeof r[0].dateProperty, 'string'); }), ctx.Y.load() .done(function(r) { - assert.ok($.type(r[0].dateProperty) === 'date'); + assert.strictEqual($.type(r[0].dateProperty), 'date'); }) ]; diff --git a/testing/tests/DevExpress.data/storeArray.tests.js b/testing/tests/DevExpress.data/storeArray.tests.js index 772e9435d1f0..31102b9710c0 100644 --- a/testing/tests/DevExpress.data/storeArray.tests.js +++ b/testing/tests/DevExpress.data/storeArray.tests.js @@ -899,20 +899,20 @@ QUnit.test('modification operations without key use instance as key', function(a store.insert(insertValues).done((data, key) => { insertedObj = store._array[0]; - assert.ok(typeof insertedObj === 'object'); - assert.ok(data === insertedObj); - assert.ok(data === key); - assert.ok(key === insertedObj); - assert.equal(insertedObj.a, 1); + assert.strictEqual(typeof insertedObj, 'object'); + assert.strictEqual(data, insertedObj); + assert.strictEqual(data, key); + assert.strictEqual(key, insertedObj); + assert.strictEqual(insertedObj.a, 1); store.update(insertedObj, { a: 2 }).done((key, data) => { - assert.ok(key === insertedObj); - assert.ok(data === insertedObj); - assert.equal(insertedObj.a, 2); + assert.strictEqual(key, insertedObj); + assert.strictEqual(data, insertedObj); + assert.strictEqual(insertedObj.a, 2); store.remove(insertedObj).done(key => { - assert.ok(key === insertedObj); - assert.ok(!store._array.length); + assert.strictEqual(key, insertedObj); + assert.notOk(store._array.length); done(); }); diff --git a/testing/tests/DevExpress.data/utils.tests.js b/testing/tests/DevExpress.data/utils.tests.js index 2cc05998a41a..703646246eb5 100644 --- a/testing/tests/DevExpress.data/utils.tests.js +++ b/testing/tests/DevExpress.data/utils.tests.js @@ -22,7 +22,7 @@ QUnit.test('toComparable is used for compound keys', function(assert) { const guid1 = new Guid(); const guid2 = new Guid(guid1); - assert.ok(guid1 !== guid2); + assert.notStrictEqual(guid1, guid2); assert.ok(keysEqual( ['a', 'b'], @@ -36,7 +36,7 @@ QUnit.test('toComparable is used for EdmLiteral', function(assert) { const edm1 = new EdmLiteral('50m'); const edm2 = new EdmLiteral('50m'); - assert.ok(edm1 !== edm2); + assert.notStrictEqual(edm1, edm2); assert.ok(keysEqual(null, edm1, edm2)); }); diff --git a/testing/tests/DevExpress.exporter/exceljsParts/ExcelJSTestHelper.js b/testing/tests/DevExpress.exporter/exceljsParts/ExcelJSTestHelper.js index b3e98d30ad21..a21998249897 100644 --- a/testing/tests/DevExpress.exporter/exceljsParts/ExcelJSTestHelper.js +++ b/testing/tests/DevExpress.exporter/exceljsParts/ExcelJSTestHelper.js @@ -95,12 +95,12 @@ class ExcelJSTestHelper { assert.equal(this.worksheet.columnCount, total.column === 0 ? total.column : topLeft.column + total.column - 1, 'worksheet.columnCount'); } - checkCellsRange(cellsRange, actual, topLeft) { - assert.deepEqual(cellsRange.from, topLeft, 'cellsRange.from'); + checkCellRange(cellRange, actual, topLeft) { + assert.deepEqual(cellRange.from, topLeft, 'cellRange.from'); if(actual.row > 0 && actual.column > 0) { - assert.deepEqual(cellsRange.to, { row: topLeft.row + actual.row - 1, column: topLeft.column + actual.column - 1 }, 'cellsRange.to'); + assert.deepEqual(cellRange.to, { row: topLeft.row + actual.row - 1, column: topLeft.column + actual.column - 1 }, 'cellRange.to'); } else { - assert.deepEqual(cellsRange.to, { row: topLeft.row + actual.row, column: topLeft.column + actual.column }, 'cellsRange.to'); + assert.deepEqual(cellRange.to, { row: topLeft.row + actual.row, column: topLeft.column + actual.column }, 'cellRange.to'); } } diff --git a/testing/tests/DevExpress.exporter/exceljsParts/exceljs.format.tests.js b/testing/tests/DevExpress.exporter/exceljsParts/exceljs.format.tests.js index 0c21f38b5b1e..fa5e5faa840d 100644 --- a/testing/tests/DevExpress.exporter/exceljsParts/exceljs.format.tests.js +++ b/testing/tests/DevExpress.exporter/exceljsParts/exceljs.format.tests.js @@ -1,7 +1,7 @@ import $ from 'jquery'; import ExcelJS from 'exceljs'; import ExcelJSTestHelper from './ExcelJSTestHelper.js'; -import { exportDataGrid } from 'exporter/exceljs/excelExporter'; +import { exportDataGrid } from 'excel_exporter'; import { initializeDxObjectAssign, clearDxObjectAssign } from './objectAssignHelper.js'; import { initializeDxArrayFind, clearDxArrayFind } from './arrayFindHelper.js'; @@ -61,10 +61,10 @@ const ExcelJSLocalizationFormatTests = { exportDataGrid({ component: dataGrid, worksheet: this.worksheet - }).then((cellsRange) => { + }).then((cellRange) => { helper.checkValues(expectedCells); helper.checkCellFormat(expectedCells); - helper.checkCellsRange(cellsRange, { row: 1, column: 6 }, topLeft); + helper.checkCellRange(cellRange, { row: 1, column: 6 }, topLeft); done(); }); }); diff --git a/testing/tests/DevExpress.exporter/exceljsParts/exceljs.tests.js b/testing/tests/DevExpress.exporter/exceljsParts/exceljs.tests.js index da307948941c..0f6f8d95e6d2 100644 --- a/testing/tests/DevExpress.exporter/exceljsParts/exceljs.tests.js +++ b/testing/tests/DevExpress.exporter/exceljsParts/exceljs.tests.js @@ -4,12 +4,11 @@ import devices from 'core/devices'; import localization from 'localization'; import ja from 'localization/messages/ja.json!'; import messageLocalization from 'localization/message'; -import { isDefined } from 'core/utils/type'; import { extend } from 'core/utils/extend'; import ExcelJS from 'exceljs'; import ExcelJSTestHelper from './ExcelJSTestHelper.js'; -import { exportDataGrid } from 'exporter/exceljs/excelExporter'; -import { MAX_EXCEL_COLUMN_WIDTH, _getFullOptions } from 'exporter/exceljs/exportDataGrid'; +import { exportDataGrid } from 'excel_exporter'; +import { MAX_EXCEL_COLUMN_WIDTH, _getFullOptions } from 'exporter/exceljs/export_data_grid'; import { initializeDxObjectAssign, clearDxObjectAssign } from './objectAssignHelper.js'; import { initializeDxArrayFind, clearDxArrayFind } from './arrayFindHelper.js'; import ExcelJSLocalizationFormatTests from './exceljs.format.tests.js'; @@ -29,14 +28,12 @@ const excelColumnWidthFromColumn200Pixels = 28.57; const excelColumnWidthFromColumn250Pixels = 35.71; const excelColumnWidthFromColumn300Pixels = 42.85; -const alignLeftNoWrap = { horizontal: 'left', wrapText: false }; -const alignLeftWrap = { horizontal: 'left', wrapText: true }; -const alignRightWrap = { horizontal: 'right', wrapText: true }; -const alignRightNoWrap = { horizontal: 'right', wrapText: false }; -const alignRightTopWrap = { horizontal: 'right', wrapText: true }; -const alignRightTopNoWrap = { horizontal: 'right', wrapText: false }; -const alignCenterNoWrap = { horizontal: 'center', wrapText: false }; -const alignCenterWrap = { horizontal: 'center', wrapText: true }; +const alignLeftTopWrap = { horizontal: 'left', vertical: 'top', wrapText: true }; +const alignLeftTopNoWrap = { horizontal: 'left', vertical: 'top', wrapText: false }; +const alignRightTopWrap = { horizontal: 'right', vertical: 'top', wrapText: true }; +const alignRightTopNoWrap = { horizontal: 'right', vertical: 'top', wrapText: false }; +const alignCenterTopWrap = { horizontal: 'center', vertical: 'top', wrapText: true }; +const alignCenterTopNoWrap = { horizontal: 'center', vertical: 'top', wrapText: false }; QUnit.testStart(() => { @@ -102,12 +99,12 @@ const moduleConfig = { const expectedCells = []; - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 0, column: 0 }, { row: 0, column: 0 }, topLeft); helper.checkColumnWidths([undefined], topLeft.column); helper.checkAutoFilter(autoFilterEnabled, null); helper.checkValues(expectedCells); - helper.checkCellsRange(cellsRange, { row: 0, column: 0 }, topLeft); + helper.checkCellRange(cellRange, { row: 0, column: 0 }, topLeft); done(); }); }); @@ -121,12 +118,12 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: 'f1', alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', value: 'f1', column: dataGrid.columnOption(0) } } + { excelCell: { value: 'f1', alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', value: 'f1', column: dataGrid.columnOption(0) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 1, column: 1 }, { row: 1, column: 1 }, topLeft); helper.checkColumnWidths([excelColumnWidthFromGrid500Pixels, undefined], topLeft.column); helper.checkFont(expectedCells); @@ -135,7 +132,7 @@ const moduleConfig = { helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0], topLeft.row); helper.checkAutoFilter(autoFilterEnabled, { from: topLeft, to: topLeft }, { state: 'frozen', ySplit: topLeft.row }); - helper.checkCellsRange(cellsRange, { row: 1, column: 1 }, topLeft); + helper.checkCellRange(cellRange, { row: 1, column: 1 }, topLeft); done(); }); }); @@ -148,22 +145,22 @@ const moduleConfig = { helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 1, column: 1 }, { row: 1, column: 1 }, topLeft); helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkAutoFilter(autoFilterEnabled, { from: topLeft, to: topLeft }, { state: 'frozen', ySplit: topLeft.row }); - helper.checkCellsRange(cellsRange, { row: 1, column: 1 }, topLeft); + helper.checkCellRange(cellRange, { row: 1, column: 1 }, topLeft); this.customizeCellCallCount = 0; const newTopLeft = { row: topLeft.row + 3, column: topLeft.column + 3 }; helper._extendExpectedCells(expectedCells, newTopLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells, { topLeftCell: newTopLeft })).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells, { topLeftCell: newTopLeft })).then((cellRange) => { helper.checkRowAndColumnCount({ row: 2, column: 2 }, { row: 1, column: 1 }, newTopLeft); helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, newTopLeft); helper.checkAutoFilter(autoFilterEnabled, { from: topLeft, to: topLeft }, { state: 'frozen', ySplit: topLeft.row }); - helper.checkCellsRange(cellsRange, { row: 1, column: 1 }, newTopLeft); + helper.checkCellRange(cellRange, { row: 1, column: 1 }, newTopLeft); done(); }); }); @@ -185,13 +182,13 @@ const moduleConfig = { helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 1, column: 1 }, { row: 1, column: 1 }, topLeft); helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0], topLeft.row); helper.checkAutoFilter(autoFilterEnabled, { from: topLeft, to: topLeft }, { state: 'frozen', ySplit: topLeft.row }); - helper.checkCellsRange(cellsRange, { row: 1, column: 1 }, topLeft); + helper.checkCellRange(cellRange, { row: 1, column: 1 }, topLeft); done(); }); }); @@ -207,7 +204,7 @@ const moduleConfig = { const expectedCells = [[ { excelCell: {}, gridCell: { rowType: 'header', value: 'f1', column: dataGrid.columnOption(0) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkColumnWidths([242.85, undefined], topLeft.column); done(); }); @@ -224,7 +221,7 @@ const moduleConfig = { const expectedCells = [[ { excelCell: {}, gridCell: { rowType: 'header', value: 'f1', column: dataGrid.columnOption(0) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkColumnWidths([MAX_EXCEL_COLUMN_WIDTH, undefined], topLeft.column); done(); }); @@ -241,12 +238,12 @@ const moduleConfig = { const expectedCells = []; - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 0, column: 0 }, { row: 0, column: 0 }, topLeft); helper.checkColumnWidths([excelColumnWidthFromGrid500Pixels, undefined], topLeft.column); helper.checkAutoFilter(autoFilterEnabled, null); - assert.deepEqual(cellsRange.from, topLeft, 'cellsRange.from'); - assert.deepEqual(cellsRange.to, topLeft, 'cellsRange.to'); + assert.deepEqual(cellRange.from, topLeft, 'cellRange.from'); + assert.deepEqual(cellRange.to, topLeft, 'cellRange.to'); done(); }); }); @@ -262,13 +259,13 @@ const moduleConfig = { helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 0, column: 0 }, { row: 0, column: 0 }, topLeft); helper.checkColumnWidths([undefined], topLeft.column); helper.checkAutoFilter(autoFilterEnabled, null); helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); - helper.checkCellsRange(cellsRange, { row: 0, column: 0 }, topLeft); + helper.checkCellRange(cellRange, { row: 0, column: 0 }, topLeft); done(); }); }); @@ -289,12 +286,12 @@ const moduleConfig = { dataGrid.beginUpdate(); dataGrid.columnOption('f1', 'visible', true); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 1, column: 1 }, { row: 1, column: 1 }, topLeft); helper.checkColumnWidths([excelColumnWidthFromColumn300Pixels], topLeft.column); helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); - helper.checkCellsRange(cellsRange, { row: 1, column: 1 }, topLeft); + helper.checkCellRange(cellRange, { row: 1, column: 1 }, topLeft); }).then(() => { dataGrid.columnOption('f1', 'visible', false); dataGrid.endUpdate(); @@ -316,11 +313,11 @@ const moduleConfig = { dataGrid.beginUpdate(); dataGrid.columnOption('f1', 'visible', false); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 0, column: 0 }, { row: 0, column: 0 }, topLeft); helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); - helper.checkCellsRange(cellsRange, { row: 0, column: 0 }, topLeft); + helper.checkCellRange(cellRange, { row: 0, column: 0 }, topLeft); }).then(() => { dataGrid.columnOption('f1', 'visible', true); dataGrid.endUpdate(); @@ -339,13 +336,13 @@ const moduleConfig = { helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 0, column: 0 }, { row: 0, column: 0 }, topLeft); helper.checkColumnWidths([undefined], topLeft.column); helper.checkAutoFilter(autoFilterEnabled, null); helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); - helper.checkCellsRange(cellsRange, { row: 0, column: 0 }, topLeft); + helper.checkCellRange(cellRange, { row: 0, column: 0 }, topLeft); done(); }); }); @@ -358,7 +355,7 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: 'f1', alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } } + { excelCell: { value: 'f1', alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); @@ -378,7 +375,7 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: 'f1', alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } } + { excelCell: { value: 'f1', alignment: alignCenterTopWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); @@ -389,73 +386,6 @@ const moduleConfig = { }); }); - QUnit.test('Header - 1 column, export.excelWrapTextEnabled: true', function(assert) { - const done = assert.async(); - - const dataGrid = $('#dataGrid').dxDataGrid({ - columns: [{ caption: 'f1' }], - export: { - excelWrapTextEnabled: true - } - }).dxDataGrid('instance'); - - const expectedCells = [[ - { excelCell: { value: 'f1', alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } } - ]]; - - helper._extendExpectedCells(expectedCells, topLeft); - - exportDataGrid(getOptions(this, dataGrid, expectedCells, { keepColumnWidths: false })).then(() => { - helper.checkAlignment(expectedCells); - done(); - }); - }); - - QUnit.test('Header - 1 column, export.excelWrapTextEnabled: false', function(assert) { - const done = assert.async(); - - const dataGrid = $('#dataGrid').dxDataGrid({ - columns: [{ caption: 'f1' }], - export: { - excelWrapTextEnabled: true - } - }).dxDataGrid('instance'); - - const expectedCells = [[ - { excelCell: { value: 'f1', alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } } - ]]; - - helper._extendExpectedCells(expectedCells, topLeft); - - exportDataGrid(getOptions(this, dataGrid, expectedCells, { keepColumnWidths: false })).then(() => { - helper.checkAlignment(expectedCells); - done(); - }); - }); - - QUnit.test('Header - 1 column, grid.wordWrapEnabled: true, export.excelWrapTextEnabled: false', function(assert) { - const done = assert.async(); - - const dataGrid = $('#dataGrid').dxDataGrid({ - columns: [{ caption: 'f1' }], - wordWrapEnabled: true, - export: { - excelWrapTextEnabled: false - } - }).dxDataGrid('instance'); - - const expectedCells = [[ - { excelCell: { value: 'f1', alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } } - ]]; - - helper._extendExpectedCells(expectedCells, topLeft); - - exportDataGrid(getOptions(this, dataGrid, expectedCells, { keepColumnWidths: false })).then(() => { - helper.checkAlignment(expectedCells); - done(); - }); - }); - QUnit.test('Header - 2 column', function(assert) { const done = assert.async(); @@ -465,20 +395,20 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: 'f1', alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } }, - { excelCell: { value: 'f2', alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(1) } } + { excelCell: { value: 'f1', alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } }, + { excelCell: { value: 'f2', alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(1) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells, { keepColumnWidths: true })).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells, { keepColumnWidths: true })).then((cellRange) => { helper.checkRowAndColumnCount({ row: 1, column: 2 }, { row: 1, column: 2 }, topLeft); helper.checkColumnWidths([excelColumnWidthFromColumn200Pixels, excelColumnWidthFromColumn300Pixels, undefined], topLeft.column); helper.checkFont(expectedCells); helper.checkAlignment(expectedCells); helper.checkAutoFilter(autoFilterEnabled, { from: topLeft, to: { row: topLeft.row, column: topLeft.column + 1 } }, { state: 'frozen', ySplit: topLeft.row }); helper.checkValues(expectedCells, topLeft); - helper.checkCellsRange(cellsRange, { row: 1, column: 2 }, topLeft); + helper.checkCellRange(cellRange, { row: 1, column: 2 }, topLeft); done(); }); }); @@ -557,11 +487,11 @@ const moduleConfig = { const expectedCells = []; - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 0, column: 0 }, { row: 0, column: 0 }, topLeft); helper.checkColumnWidths([undefined], topLeft.column); helper.checkAutoFilter(autoFilterEnabled, null); - helper.checkCellsRange(cellsRange, { row: 0, column: 0 }, topLeft); + helper.checkCellRange(cellRange, { row: 0, column: 0 }, topLeft); done(); }); }); @@ -575,19 +505,19 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: 'f1', alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } } + { excelCell: { value: 'f1', alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 1, column: 1 }, { row: 1, column: 1 }, topLeft); helper.checkColumnWidths([excelColumnWidthFromGrid500Pixels, undefined], topLeft.column); helper.checkFont(expectedCells); helper.checkAlignment(expectedCells); helper.checkAutoFilter(autoFilterEnabled, { from: topLeft, to: topLeft }, { state: 'frozen', ySplit: topLeft.row }); helper.checkValues(expectedCells, topLeft); - helper.checkCellsRange(cellsRange, { row: 1, column: 1 }, topLeft); + helper.checkCellRange(cellRange, { row: 1, column: 1 }, topLeft); done(); }); }); @@ -601,19 +531,19 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: 'f2', alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(1) } } + { excelCell: { value: 'f2', alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(1) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 1, column: 1 }, { row: 1, column: 1 }, topLeft); helper.checkColumnWidths([excelColumnWidthFromGrid500Pixels, undefined], topLeft.column); helper.checkFont(expectedCells); helper.checkAlignment(expectedCells); helper.checkAutoFilter(autoFilterEnabled, { from: topLeft, to: topLeft }, { state: 'frozen', ySplit: topLeft.row }); helper.checkValues(expectedCells, topLeft); - helper.checkCellsRange(cellsRange, { row: 1, column: 1 }, topLeft); + helper.checkCellRange(cellRange, { row: 1, column: 1 }, topLeft); done(); }); }); @@ -638,12 +568,12 @@ const moduleConfig = { helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 1, column: 3 }, { row: 1, column: 3 }, topLeft); helper.checkColumnWidths([excelColumnWidthFromColumn100Pixels, excelColumnWidthFromColumn150Pixels, excelColumnWidthFromColumn250Pixels, undefined], topLeft.column); helper.checkAutoFilter(autoFilterEnabled, { from: topLeft, to: { row: topLeft.row, column: topLeft.column + 2 } }, { state: 'frozen', ySplit: topLeft.row }); helper.checkValues(expectedCells, topLeft); - helper.checkCellsRange(cellsRange, { row: 1, column: 3 }, topLeft); + helper.checkCellRange(cellRange, { row: 1, column: 3 }, topLeft); done(); }); }); @@ -667,12 +597,12 @@ const moduleConfig = { helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 1, column: 2 }, { row: 1, column: 2 }, topLeft); helper.checkColumnWidths([excelColumnWidthFromColumn200Pixels, excelColumnWidthFromColumn300Pixels, undefined], topLeft.column); helper.checkAutoFilter(autoFilterEnabled, { from: topLeft, to: { row: topLeft.row, column: topLeft.column + 1 } }, { state: 'frozen', ySplit: topLeft.row }); helper.checkValues(expectedCells, topLeft); - helper.checkCellsRange(cellsRange, { row: 1, column: 2 }, topLeft); + helper.checkCellRange(cellRange, { row: 1, column: 2 }, topLeft); done(); }); }); @@ -696,12 +626,12 @@ const moduleConfig = { helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 1, column: 2 }, { row: 1, column: 2 }, topLeft); helper.checkColumnWidths([excelColumnWidthFromColumn200Pixels, excelColumnWidthFromColumn300Pixels, undefined], topLeft.column); helper.checkAutoFilter(autoFilterEnabled, { from: topLeft, to: { row: topLeft.row, column: topLeft.column + 1 } }, { state: 'frozen', ySplit: topLeft.row }); helper.checkValues(expectedCells, topLeft); - helper.checkCellsRange(cellsRange, { row: 1, column: 2 }, topLeft); + helper.checkCellRange(cellRange, { row: 1, column: 2 }, topLeft); done(); }); }); @@ -724,12 +654,12 @@ const moduleConfig = { helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 1, column: 1 }, { row: 1, column: 1 }, topLeft); helper.checkColumnWidths([excelColumnWidthFromColumn300Pixels], topLeft.column); helper.checkAutoFilter(autoFilterEnabled, { from: topLeft, to: topLeft }, { state: 'frozen', ySplit: topLeft.row }); helper.checkValues(expectedCells, topLeft); - helper.checkCellsRange(cellsRange, { row: 1, column: 1 }, topLeft); + helper.checkCellRange(cellRange, { row: 1, column: 1 }, topLeft); done(); }); }); @@ -753,12 +683,12 @@ const moduleConfig = { helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 1, column: 2 }, { row: 1, column: 2 }, topLeft); helper.checkColumnWidths([excelColumnWidthFromColumn200Pixels, excelColumnWidthFromColumn300Pixels, undefined], topLeft.column); helper.checkAutoFilter(autoFilterEnabled, { from: topLeft, to: { row: topLeft.row, column: topLeft.column + 1 } }, { state: 'frozen', ySplit: topLeft.row }); helper.checkValues(expectedCells, topLeft); - helper.checkCellsRange(cellsRange, { row: 1, column: 2 }, topLeft); + helper.checkCellRange(cellRange, { row: 1, column: 2 }, topLeft); done(); }); }); @@ -782,12 +712,12 @@ const moduleConfig = { helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 1, column: 2 }, { row: 1, column: 2 }, topLeft); helper.checkColumnWidths([excelColumnWidthFromColumn200Pixels, excelColumnWidthFromColumn300Pixels, undefined], topLeft.column); helper.checkAutoFilter(autoFilterEnabled, { from: topLeft, to: { row: topLeft.row, column: topLeft.column + 1 } }, { state: 'frozen', ySplit: topLeft.row }); helper.checkValues(expectedCells, topLeft); - helper.checkCellsRange(cellsRange, { row: 1, column: 2 }, topLeft); + helper.checkCellRange(cellRange, { row: 1, column: 2 }, topLeft); done(); }); }); @@ -811,52 +741,16 @@ const moduleConfig = { helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 1, column: 2 }, { row: 1, column: 2 }, topLeft); helper.checkColumnWidths([excelColumnWidthFromColumn200Pixels, excelColumnWidthFromColumn300Pixels, undefined], topLeft.column); helper.checkAutoFilter(autoFilterEnabled, { from: topLeft, to: { row: topLeft.row, column: topLeft.column + 1 } }, { state: 'frozen', ySplit: topLeft.row }); helper.checkValues(expectedCells, topLeft); - helper.checkCellsRange(cellsRange, { row: 1, column: 2 }, topLeft); + helper.checkCellRange(cellRange, { row: 1, column: 2 }, topLeft); done(); }); }); - [true, false, undefined].forEach((gridExcelFilterEnabled) => { - QUnit.test(`Data - 1 column & 2 rows, grid.export.excelFilterEnabled: ${gridExcelFilterEnabled}`, function(assert) { - const done = assert.async(); - const ds = [{ f1: '1' }]; - const dataGrid = $('#dataGrid').dxDataGrid({ - dataSource: ds, - loadingTimeout: undefined, - export: { - excelFilterEnabled: gridExcelFilterEnabled - } - }).dxDataGrid('instance'); - - const expectedCells = [[ - { excelCell: { value: 'F1' }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } }, - ], [ - { excelCell: { value: ds[0].f1 }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } } - ]]; - - helper._extendExpectedCells(expectedCells, topLeft); - - let expectedAutoFilterEnabled = !!gridExcelFilterEnabled; - if(isDefined(autoFilterEnabled)) { - expectedAutoFilterEnabled = autoFilterEnabled; - } - - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { - helper.checkRowAndColumnCount({ row: 2, column: 1 }, { row: 2, column: 1 }, topLeft); - helper.checkAutoFilter(expectedAutoFilterEnabled, { from: topLeft, to: { row: topLeft.row + 1, column: topLeft.column } }, { state: 'frozen', ySplit: topLeft.row }); - helper.checkValues(expectedCells); - helper.checkMergeCells(expectedCells, topLeft); - helper.checkCellsRange(cellsRange, { row: 2, column: 1 }, topLeft); - done(); - }); - }); - }); - QUnit.test('Data - 1 row & 1 columns, value as html', function(assert) { const done = assert.async(); const ds = [{ f1: '

text

' }]; @@ -870,12 +764,12 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: ds[0].f1, alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } } + { excelCell: { value: ds[0].f1, alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 1, column: 1 }, { row: 1, column: 1 }, topLeft); helper.checkAutoFilter(autoFilterEnabled, null); helper.checkFont(expectedCells); @@ -883,7 +777,7 @@ const moduleConfig = { helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 1, column: 1 }, topLeft); + helper.checkCellRange(cellRange, { row: 1, column: 1 }, topLeft); done(); }); }); @@ -902,12 +796,12 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: ds[0].f1, alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } } + { excelCell: { value: ds[0].f1, alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 1, column: 1 }, { row: 1, column: 1 }, topLeft); helper.checkAutoFilter(autoFilterEnabled, null); helper.checkFont(expectedCells); @@ -915,7 +809,7 @@ const moduleConfig = { helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 1, column: 1 }, topLeft); + helper.checkCellRange(cellRange, { row: 1, column: 1 }, topLeft); done(); }); }); @@ -930,15 +824,15 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: ds[0].f1, alignment: alignLeftNoWrap, numberFormat: '@' }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, - { excelCell: { value: ds[0].f2, alignment: alignLeftNoWrap, numberFormat: '@' }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } }, - { excelCell: { value: ds[0].f3, alignment: alignLeftNoWrap, numberFormat: '@' }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } }, - { excelCell: { value: ds[0].f4, alignment: alignLeftNoWrap, numberFormat: '@' }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(3) } } + { excelCell: { value: ds[0].f1, alignment: alignLeftTopNoWrap, numberFormat: '@' }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, + { excelCell: { value: ds[0].f2, alignment: alignLeftTopNoWrap, numberFormat: '@' }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } }, + { excelCell: { value: ds[0].f3, alignment: alignLeftTopNoWrap, numberFormat: '@' }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } }, + { excelCell: { value: ds[0].f4, alignment: alignLeftTopNoWrap, numberFormat: '@' }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(3) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 1, column: 4 }, { row: 1, column: 4 }, topLeft); helper.checkAutoFilter(autoFilterEnabled, null); helper.checkFont(expectedCells); @@ -946,7 +840,7 @@ const moduleConfig = { helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 1, column: 4 }, topLeft); + helper.checkCellRange(cellRange, { row: 1, column: 4 }, topLeft); done(); }); }); @@ -966,16 +860,16 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: ds[0].f1, alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } } + { excelCell: { value: ds[0].f1, alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } } ], [ - { excelCell: { value: ds[1].f1, alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(0) } } + { excelCell: { value: ds[1].f1, alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(0) } } ], [ - { excelCell: { value: ds[2].f1, alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[2], column: dataGrid.columnOption(0) } } + { excelCell: { value: ds[2].f1, alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[2], column: dataGrid.columnOption(0) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 3, column: 1 }, { row: 3, column: 1 }, topLeft); helper.checkAutoFilter(autoFilterEnabled, null); helper.checkFont(expectedCells); @@ -983,7 +877,7 @@ const moduleConfig = { helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0, 0, 0], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 3, column: 1 }, topLeft); + helper.checkCellRange(cellRange, { row: 3, column: 1 }, topLeft); done(); }); }); @@ -997,16 +891,16 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: 'F1', alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } }, - { excelCell: { value: 'F2', alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(1) } } + { excelCell: { value: 'F1', alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } }, + { excelCell: { value: 'F2', alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(1) } } ], [ - { excelCell: { value: ds[0].f1, alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, - { excelCell: { value: ds[0].f2, alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } } + { excelCell: { value: ds[0].f1, alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, + { excelCell: { value: ds[0].f2, alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 2, column: 2 }, { row: 2, column: 2 }, topLeft); helper.checkAutoFilter(autoFilterEnabled, { from: topLeft, to: { row: topLeft.row + 1, column: topLeft.column + 1 } }, { state: 'frozen', ySplit: topLeft.row }); helper.checkFont(expectedCells); @@ -1014,7 +908,7 @@ const moduleConfig = { helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0, 0], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 2, column: 2 }, topLeft); + helper.checkCellRange(cellRange, { row: 2, column: 2 }, topLeft); done(); }); }); @@ -1029,16 +923,16 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: 'F1', alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } }, - { excelCell: { value: 'F2', alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(1) } } + { excelCell: { value: 'F1', alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } }, + { excelCell: { value: 'F2', alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(1) } } ], [ - { excelCell: { value: ds[0].f1, alignment: alignRightNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, - { excelCell: { value: ds[0].f2, alignment: alignRightNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } } + { excelCell: { value: ds[0].f1, alignment: alignRightTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, + { excelCell: { value: ds[0].f2, alignment: alignRightTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 2, column: 2 }, { row: 2, column: 2 }, topLeft); helper.checkAutoFilter(autoFilterEnabled, { from: topLeft, to: { row: topLeft.row + 1, column: topLeft.column + 1 } }, { state: 'frozen', ySplit: topLeft.row, rightToLeft: true }); helper.checkFont(expectedCells); @@ -1046,7 +940,7 @@ const moduleConfig = { helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0, 0], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 2, column: 2 }, topLeft); + helper.checkCellRange(cellRange, { row: 2, column: 2 }, topLeft); done(); }); }); @@ -1069,24 +963,24 @@ const moduleConfig = { helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 2, column: 2 }, { row: 2, column: 2 }, topLeft); helper.checkAutoFilter(autoFilterEnabled, { from: topLeft, to: { row: topLeft.row + 1, column: topLeft.column + 1 } }, { state: 'frozen', ySplit: topLeft.row }); helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0, 0], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 2, column: 2 }, topLeft); + helper.checkCellRange(cellRange, { row: 2, column: 2 }, topLeft); this.customizeCellCallCount = 0; const newTopLeft = { row: topLeft.row + 3, column: topLeft.column + 3 }; helper._extendExpectedCells(expectedCells, newTopLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells, { topLeftCell: newTopLeft })).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells, { topLeftCell: newTopLeft })).then((cellRange) => { helper.checkRowAndColumnCount({ row: 4, column: 4 }, { row: 2, column: 2 }, newTopLeft); helper.checkAutoFilter(autoFilterEnabled, { from: topLeft, to: { row: topLeft.row + 1, column: topLeft.column + 1 } }, { state: 'frozen', ySplit: topLeft.row }); helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, newTopLeft); helper.checkOutlineLevel([0, 0], newTopLeft.row); - helper.checkCellsRange(cellsRange, { row: 2, column: 2 }, newTopLeft); + helper.checkCellRange(cellRange, { row: 2, column: 2 }, newTopLeft); done(); }); }); @@ -1102,16 +996,16 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: 'F1', alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } }, - { excelCell: { value: 'F2', alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(1) } } + { excelCell: { value: 'F1', alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } }, + { excelCell: { value: 'F2', alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(1) } } ], [ - { excelCell: { value: 'f1_1', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, - { excelCell: { value: 'f1_2', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } } + { excelCell: { value: 'f1_1', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, + { excelCell: { value: 'f1_2', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 2, column: 2 }, { row: 2, column: 2 }, topLeft); helper.checkAutoFilter(autoFilterEnabled, { from: topLeft, to: { row: topLeft.row + 1, column: topLeft.column + 1 } }, { state: 'frozen', ySplit: topLeft.row }); helper.checkFont(expectedCells); @@ -1119,7 +1013,7 @@ const moduleConfig = { helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0, 0], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 2, column: 2 }, topLeft); + helper.checkCellRange(cellRange, { row: 2, column: 2 }, topLeft); done(); }); }); @@ -1141,16 +1035,16 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: 'F1', alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(1) } }, - { excelCell: { value: 'F2', alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(3) } } + { excelCell: { value: 'F1', alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(1) } }, + { excelCell: { value: 'F2', alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(3) } } ], [ - { excelCell: { value: ds[0].f1, alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } }, - { excelCell: { value: ds[0].f2, alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(3) } } + { excelCell: { value: ds[0].f1, alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } }, + { excelCell: { value: ds[0].f2, alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(3) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 2, column: 2 }, { row: 2, column: 2 }, topLeft); helper.checkAutoFilter(autoFilterEnabled, { from: topLeft, to: { row: topLeft.row + 1, column: topLeft.column + 1 } }, { state: 'frozen', ySplit: topLeft.row }); helper.checkColumnWidths([excelColumnWidthFromColumn200Pixels, excelColumnWidthFromColumn300Pixels], topLeft.column); @@ -1159,7 +1053,7 @@ const moduleConfig = { helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0, 0], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 2, column: 2 }, topLeft); + helper.checkCellRange(cellRange, { row: 2, column: 2 }, topLeft); done(); }); }); @@ -1183,16 +1077,16 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: 'F1', alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } }, - { excelCell: { value: 'F2', alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(1) } } + { excelCell: { value: 'F1', alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } }, + { excelCell: { value: 'F2', alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(1) } } ], [ - { excelCell: { value: ds[0].f1, alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, - { excelCell: { value: ds[0].f2, alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } } + { excelCell: { value: ds[0].f1, alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, + { excelCell: { value: ds[0].f2, alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 2, column: 2 }, { row: 2, column: 2 }, topLeft); helper.checkAutoFilter(autoFilterEnabled, { from: topLeft, to: { row: topLeft.row + 1, column: topLeft.column + 1 } }, { state: 'frozen', ySplit: topLeft.row }); helper.checkColumnWidths([excelColumnWidthFromColumn100Pixels /* excelColumnWidthFromColumn150Pixels */ ], topLeft.column); @@ -1201,7 +1095,7 @@ const moduleConfig = { helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0, 0], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 2, column: 2 }, topLeft); + helper.checkCellRange(cellRange, { row: 2, column: 2 }, topLeft); done(); }); }); @@ -1216,11 +1110,11 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: 'F1', alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } }, - { excelCell: { value: 'F2', alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(1) } } + { excelCell: { value: 'F1', alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } }, + { excelCell: { value: 'F2', alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(1) } } ], [ - { excelCell: { value: ds[0].f1, alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, - { excelCell: { value: ds[0].f2, alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } } + { excelCell: { value: ds[0].f1, alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, + { excelCell: { value: ds[0].f2, alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); @@ -1228,7 +1122,7 @@ const moduleConfig = { dataGrid.beginUpdate(); dataGrid.columnOption('f1', 'visible', true); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 2, column: 2 }, { row: 2, column: 2 }, topLeft); helper.checkAutoFilter(autoFilterEnabled, { from: topLeft, to: { row: topLeft.row + 1, column: topLeft.column + 1 } }, { state: 'frozen', ySplit: topLeft.row }); // helper.checkColumnWidths([excelColumnWidthFromColumn250Pixels, excelColumnWidthFromColumn150Pixels], topLeft.column); @@ -1237,7 +1131,7 @@ const moduleConfig = { helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0, 0], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 2, column: 2 }, topLeft); + helper.checkCellRange(cellRange, { row: 2, column: 2 }, topLeft); }).then(() => { dataGrid.columnOption('f1', 'visible', false); dataGrid.endUpdate(); @@ -1255,18 +1149,18 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: 'F1', alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } }, - { excelCell: { value: 'F2', alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(1) } } + { excelCell: { value: 'F1', alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } }, + { excelCell: { value: 'F2', alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(1) } } ], [ - { excelCell: { value: ds[0].f1, alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, - { excelCell: { value: ds[0].f2, alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } } + { excelCell: { value: ds[0].f1, alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, + { excelCell: { value: ds[0].f2, alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); dataGrid.columnOption('f1', 'visible', true); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 2, column: 2 }, { row: 2, column: 2 }, topLeft); helper.checkAutoFilter(autoFilterEnabled, { from: topLeft, to: { row: topLeft.row + 1, column: topLeft.column + 1 } }, { state: 'frozen', ySplit: topLeft.row }); helper.checkColumnWidths([excelColumnWidthFromColumn250Pixels, excelColumnWidthFromColumn150Pixels], topLeft.column); @@ -1275,7 +1169,7 @@ const moduleConfig = { helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0, 0], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 2, column: 2 }, topLeft); + helper.checkCellRange(cellRange, { row: 2, column: 2 }, topLeft); }).then(() => { dataGrid.columnOption('f1', 'visible', false); done(); @@ -1292,9 +1186,9 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: 'F2', alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(1) } } + { excelCell: { value: 'F2', alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(1) } } ], [ - { excelCell: { value: ds[0].f2, alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } } + { excelCell: { value: ds[0].f2, alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); @@ -1302,7 +1196,7 @@ const moduleConfig = { dataGrid.beginUpdate(); dataGrid.columnOption('f1', 'visible', false); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 2, column: 1 }, { row: 2, column: 1 }, topLeft); helper.checkAutoFilter(autoFilterEnabled, { from: topLeft, to: { row: topLeft.row + 1, column: topLeft.column } }, { state: 'frozen', ySplit: topLeft.row }); // helper.checkColumnWidths([excelColumnWidthFromColumn150Pixels], topLeft.column); @@ -1311,7 +1205,7 @@ const moduleConfig = { helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0, 0], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 2, column: 1 }, topLeft); + helper.checkCellRange(cellRange, { row: 2, column: 1 }, topLeft); }).then(() => { dataGrid.columnOption('f1', 'visible', true); dataGrid.endUpdate(); @@ -1338,7 +1232,7 @@ const moduleConfig = { if(gridCell.rowType === 'header') { excelCell.font = undefined; } if(gridCell.rowType === 'data') { excelCell.font = { bold: true }; } } - }).then((cellsRange) => { + }).then((cellRange) => { assert.deepEqual(this.worksheet.getCell(topLeft.row, topLeft.column).font, undefined, `this.worksheet.getCell(${topLeft.row}, ${topLeft.column}).font`); assert.deepEqual(this.worksheet.getCell(topLeft.row, topLeft.column + 1).font, undefined, `this.worksheet.getCell(${topLeft.row}, ${topLeft.column + 1}).font`); assert.deepEqual(this.worksheet.getCell(topLeft.row + 1, topLeft.column).font, { bold: true }, `this.worksheet.getCell(${topLeft.row + 1}, ${topLeft.column}).font`); @@ -1363,53 +1257,24 @@ const moduleConfig = { component: dataGrid, worksheet: this.worksheet, topLeftCell: topLeft - }).then((cellsRange) => { - assert.deepEqual(this.worksheet.getCell(topLeft.row, topLeft.column).alignment, alignCenterWrap, `this.worksheet.getCell(${topLeft.row}, ${topLeft.column}).alignment`); - assert.deepEqual(this.worksheet.getCell(topLeft.row, topLeft.column + 1).alignment, alignCenterWrap, `this.worksheet.getCell(${topLeft.row}, ${topLeft.column + 1}).alignment`); - assert.deepEqual(this.worksheet.getCell(topLeft.row + 1, topLeft.column).alignment, alignLeftWrap, `this.worksheet.getCell(${topLeft.row + 1}, ${topLeft.column}).alignment`); - assert.deepEqual(this.worksheet.getCell(topLeft.row + 1, topLeft.column + 1).alignment, alignRightWrap, `this.worksheet.getCell(${topLeft.row + 1}, ${topLeft.column + 1}).alignment`); + }).then((cellRange) => { + assert.deepEqual(this.worksheet.getCell(topLeft.row, topLeft.column).alignment, alignCenterTopWrap, `this.worksheet.getCell(${topLeft.row}, ${topLeft.column}).alignment`); + assert.deepEqual(this.worksheet.getCell(topLeft.row, topLeft.column + 1).alignment, alignCenterTopWrap, `this.worksheet.getCell(${topLeft.row}, ${topLeft.column + 1}).alignment`); + assert.deepEqual(this.worksheet.getCell(topLeft.row + 1, topLeft.column).alignment, alignLeftTopWrap, `this.worksheet.getCell(${topLeft.row + 1}, ${topLeft.column}).alignment`); + assert.deepEqual(this.worksheet.getCell(topLeft.row + 1, topLeft.column + 1).alignment, alignRightTopWrap, `this.worksheet.getCell(${topLeft.row + 1}, ${topLeft.column + 1}).alignment`); done(); }); }); - QUnit.test('Data - 2 column & 2 rows, wordWrapEnabled = true, export.excelWrapTextEnabled = false', function(assert) { + QUnit.test('Data - 2 column & 2 rows, grid.wordWrapEnabled = true, clearing predefined alignment settings', function(assert) { const done = assert.async(); const ds = [{ f1: '1', f2: '2' }]; const dataGrid = $('#dataGrid').dxDataGrid({ dataSource: ds, - wordWrapEnabled: true, - export: { - excelWrapTextEnabled: false - }, loadingTimeout: undefined, - }).dxDataGrid('instance'); - - exportDataGrid({ - component: dataGrid, - worksheet: this.worksheet, - topLeftCell: topLeft - }).then((cellsRange) => { - assert.deepEqual(this.worksheet.getCell(topLeft.row, topLeft.column).alignment, alignCenterWrap, `this.worksheet.getCell(${topLeft.row}, ${topLeft.column}).alignment`); - assert.deepEqual(this.worksheet.getCell(topLeft.row, topLeft.column + 1).alignment, alignCenterWrap, `this.worksheet.getCell(${topLeft.row}, ${topLeft.column + 1}).alignment`); - assert.deepEqual(this.worksheet.getCell(topLeft.row + 1, topLeft.column).alignment, alignLeftNoWrap, `this.worksheet.getCell(${topLeft.row + 1}, ${topLeft.column}).alignment`); - assert.deepEqual(this.worksheet.getCell(topLeft.row + 1, topLeft.column + 1).alignment, alignLeftNoWrap, `this.worksheet.getCell(${topLeft.row + 1}, ${topLeft.column + 1}).alignment`); - - done(); - }); - }); - - QUnit.test('Data - 2 column & 2 rows, export.excelWrapTextEnabled = true, clearing predefined alignment settings', function(assert) { - const done = assert.async(); - const ds = [{ f1: '1', f2: '2' }]; - - const dataGrid = $('#dataGrid').dxDataGrid({ - dataSource: ds, - loadingTimeout: undefined, - export: { - excelWrapTextEnabled: true - } + wordWrapEnabled: true }).dxDataGrid('instance'); const alignment = { wrapText: true, horizontal: 'right', vertical: 'bottom' }; @@ -1424,7 +1289,7 @@ const moduleConfig = { if(gridCell.rowType === 'header') { excelCell.alignment = undefined; } if(gridCell.rowType === 'data') { excelCell.alignment = alignment; } } - }).then((cellsRange) => { + }).then((cellRange) => { assert.deepEqual(this.worksheet.getCell(topLeft.row, topLeft.column).alignment, undefined, `this.worksheet.getCell(${topLeft.row}, ${topLeft.column}).alignment`); assert.deepEqual(this.worksheet.getCell(topLeft.row, topLeft.column + 1).alignment, undefined, `this.worksheet.getCell(${topLeft.row}, ${topLeft.column + 1}).alignment`); assert.deepEqual(this.worksheet.getCell(topLeft.row + 1, topLeft.column).alignment, alignment, `this.worksheet.getCell(${topLeft.row + 1}, ${topLeft.column}).alignment`); @@ -1448,16 +1313,16 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: 'F1', alignment: alignCenterWrap, type: ExcelJS.ValueType.String, dataType: 'string', font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } }, - { excelCell: { value: 'F1', alignment: alignCenterWrap, type: ExcelJS.ValueType.String, dataType: 'string', font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(1) } } + { excelCell: { value: 'F1', alignment: alignCenterTopNoWrap, type: ExcelJS.ValueType.String, dataType: 'string', font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } }, + { excelCell: { value: 'F1', alignment: alignCenterTopNoWrap, type: ExcelJS.ValueType.String, dataType: 'string', font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(1) } } ], [ - { excelCell: { value: '1', type: ExcelJS.ValueType.String, dataType: 'string', numberFormat: undefined, alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, - { excelCell: { value: 1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: undefined, alignment: alignRightNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } } + { excelCell: { value: '1', type: ExcelJS.ValueType.String, dataType: 'string', numberFormat: undefined, alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, + { excelCell: { value: 1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: undefined, alignment: alignRightTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 2, column: 2 }, { row: 2, column: 2 }, topLeft); helper.checkAutoFilter(autoFilterEnabled, { from: topLeft, to: { row: topLeft.row + 1, column: topLeft.column + 1 } }, { state: 'frozen', ySplit: topLeft.row }); helper.checkFont(expectedCells); @@ -1466,7 +1331,7 @@ const moduleConfig = { helper.checkMergeCells(expectedCells, topLeft); helper.checkCellFormat(expectedCells); helper.checkOutlineLevel([0, 0], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 2, column: 2 }, topLeft); + helper.checkCellRange(cellRange, { row: 2, column: 2 }, topLeft); done(); }); }); @@ -1487,7 +1352,7 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: 'custom', alignment: alignLeftNoWrap }, gridCell: { value: '1', rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } } + { excelCell: { value: 'custom', alignment: alignLeftTopNoWrap }, gridCell: { value: '1', rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); @@ -1515,14 +1380,14 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: 'F1', alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } } + { excelCell: { value: 'F1', alignment: alignCenterTopWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } } ], [ - { excelCell: { value: ds[0].f1, alignment: alignLeftWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } } + { excelCell: { value: ds[0].f1, alignment: alignLeftTopWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells, { keepColumnWidths: false })).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells, { keepColumnWidths: false })).then((cellRange) => { helper.checkFont(expectedCells); helper.checkAlignment(expectedCells); helper.checkValues(expectedCells); @@ -1543,12 +1408,12 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: '1', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(0) } } + { excelCell: { value: '1', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(0) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells, { keepColumnWidths: false, selectedRowsOnly: true })).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells, { keepColumnWidths: false, selectedRowsOnly: true })).then((cellRange) => { helper.checkRowAndColumnCount({ row: 1, column: 1 }, { row: 1, column: 1 }, topLeft); helper.checkAutoFilter(autoFilterEnabled, null); helper.checkFont(expectedCells); @@ -1556,7 +1421,7 @@ const moduleConfig = { helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 1, column: 1 }, topLeft); + helper.checkCellRange(cellRange, { row: 1, column: 1 }, topLeft); done(); }); }); @@ -1579,16 +1444,16 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: '', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], value: undefined, column: dataGrid.columnOption(0) } }, + { excelCell: { value: '', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], value: undefined, column: dataGrid.columnOption(0) } }, { excelCell: { value: null }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } }, - { excelCell: { value: '', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } }, - { excelCell: { value: 'str1', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(3) } }, - { excelCell: { value: 'str2', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(4) } }, + { excelCell: { value: '', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } }, + { excelCell: { value: 'str1', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(3) } }, + { excelCell: { value: 'str2', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(4) } }, ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 1, column: 4 }, { row: 1, column: 5 }, topLeft); helper.checkAutoFilter(autoFilterEnabled, null); helper.checkFont(expectedCells); @@ -1596,7 +1461,7 @@ const moduleConfig = { helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 1, column: 5 }, topLeft); + helper.checkCellRange(cellRange, { row: 1, column: 5 }, topLeft); done(); }); }); @@ -1617,13 +1482,13 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: 0, alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, - { excelCell: { value: 0, alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } } + { excelCell: { value: 0, alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, + { excelCell: { value: 0, alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells, { selectedRowsOnly: true })).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells, { selectedRowsOnly: true })).then((cellRange) => { helper.checkRowAndColumnCount({ row: 1, column: 2 }, { row: 1, column: 2 }, topLeft); helper.checkAutoFilter(autoFilterEnabled, null); helper.checkFont(expectedCells); @@ -1631,7 +1496,7 @@ const moduleConfig = { helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 1, column: 2 }, topLeft); + helper.checkCellRange(cellRange, { row: 1, column: 2 }, topLeft); done(); }); }); @@ -1653,14 +1518,14 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: 'str1', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, - { excelCell: { value: 'str1_1', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } }, - { excelCell: { value: 'str1_notExists', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } }, + { excelCell: { value: 'str1', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, + { excelCell: { value: 'str1_1', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } }, + { excelCell: { value: 'str1_notExists', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } }, ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells, { selectedRowsOnly: true })).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells, { selectedRowsOnly: true })).then((cellRange) => { helper.checkRowAndColumnCount({ row: 1, column: 3 }, { row: 1, column: 3 }, topLeft); helper.checkAutoFilter(autoFilterEnabled, null); helper.checkFont(expectedCells); @@ -1668,7 +1533,7 @@ const moduleConfig = { helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0, 0, 0], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 1, column: 3 }, topLeft); + helper.checkCellRange(cellRange, { row: 1, column: 3 }, topLeft); done(); }); }); @@ -1687,14 +1552,14 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: 'F1', alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } } + { excelCell: { value: 'F1', alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } } ], [ - { excelCell: { value: ds[0].f1, alignment: alignRightNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } } + { excelCell: { value: ds[0].f1, alignment: alignRightTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells, { keepColumnWidths: false })).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells, { keepColumnWidths: false })).then((cellRange) => { helper.checkRowAndColumnCount({ row: 2, column: 1 }, { row: 2, column: 1 }, topLeft); helper.checkAutoFilter(autoFilterEnabled, { from: topLeft, to: { row: topLeft.row + 1, column: topLeft.column } }, { state: 'frozen', ySplit: topLeft.row }); helper.checkFont(expectedCells); @@ -1703,7 +1568,7 @@ const moduleConfig = { helper.checkMergeCells(expectedCells, topLeft); assert.equal(typeof this.worksheet.getCell(topLeft.row + 1, topLeft.column).value, 'number', `this.worksheet.getCell(${topLeft.row + 1}, ${topLeft.column}).value`); helper.checkOutlineLevel([0, 0], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 2, column: 1 }, topLeft); + helper.checkCellRange(cellRange, { row: 2, column: 1 }, topLeft); done(); }); }); @@ -1756,18 +1621,18 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: '', alignment: alignRightNoWrap }, gridCell: { rowType: 'data', data: ds[0], value: undefined, column: dataGrid.columnOption(0) } }, + { excelCell: { value: '', alignment: alignRightTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], value: undefined, column: dataGrid.columnOption(0) } }, { excelCell: { value: null }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } }, - { excelCell: { value: 0, alignment: alignRightNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } }, - { excelCell: { value: 1, alignment: alignRightNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(3) } }, - { excelCell: { value: -2, alignment: alignRightNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(4) } }, - { excelCell: { value: 'Infinity', alignment: alignRightNoWrap }, gridCell: { value: Infinity, rowType: 'data', data: ds[0], column: dataGrid.columnOption(5) } }, - { excelCell: { value: '-Infinity', alignment: alignRightNoWrap }, gridCell: { value: -Infinity, rowType: 'data', data: ds[0], column: dataGrid.columnOption(6) } }, + { excelCell: { value: 0, alignment: alignRightTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } }, + { excelCell: { value: 1, alignment: alignRightTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(3) } }, + { excelCell: { value: -2, alignment: alignRightTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(4) } }, + { excelCell: { value: 'Infinity', alignment: alignRightTopNoWrap }, gridCell: { value: Infinity, rowType: 'data', data: ds[0], column: dataGrid.columnOption(5) } }, + { excelCell: { value: '-Infinity', alignment: alignRightTopNoWrap }, gridCell: { value: -Infinity, rowType: 'data', data: ds[0], column: dataGrid.columnOption(6) } }, ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 1, column: 6 }, { row: 1, column: 7 }, topLeft); helper.checkAutoFilter(autoFilterEnabled, null); helper.checkFont(expectedCells); @@ -1775,7 +1640,7 @@ const moduleConfig = { helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 1, column: 7 }, topLeft); + helper.checkCellRange(cellRange, { row: 1, column: 7 }, topLeft); const expectedCellTypes = ['string', 'object', 'number', 'number', 'number', 'string', 'string', 'object']; @@ -1801,12 +1666,12 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: 0, alignment: alignRightNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } } + { excelCell: { value: 0, alignment: alignRightTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells, { selectedRowsOnly: true })).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells, { selectedRowsOnly: true })).then((cellRange) => { helper.checkRowAndColumnCount({ row: 1, column: 1 }, { row: 1, column: 1 }, topLeft); helper.checkAutoFilter(autoFilterEnabled, null); helper.checkFont(expectedCells); @@ -1814,7 +1679,7 @@ const moduleConfig = { helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 1, column: 1 }, topLeft); + helper.checkCellRange(cellRange, { row: 1, column: 1 }, topLeft); done(); }); }); @@ -1833,14 +1698,14 @@ const moduleConfig = { const expectedCells = [[ - { excelCell: { value: 'F1', alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } } + { excelCell: { value: 'F1', alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } } ], [ - { excelCell: { value: 'true', alignment: alignCenterNoWrap }, gridCell: { rowType: 'data', data: ds[0], value: true, column: dataGrid.columnOption(0) } } + { excelCell: { value: 'true', alignment: alignCenterTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], value: true, column: dataGrid.columnOption(0) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 2, column: 1 }, { row: 2, column: 1 }, topLeft); helper.checkAutoFilter(autoFilterEnabled, { from: topLeft, to: { row: topLeft.row + 1, column: topLeft.column } }, { state: 'frozen', ySplit: topLeft.row }); helper.checkFont(expectedCells); @@ -1849,7 +1714,7 @@ const moduleConfig = { helper.checkMergeCells(expectedCells, topLeft); assert.equal(typeof this.worksheet.getCell(topLeft.row + 1, topLeft.column).value, 'string', `typeof this.worksheet.getCell(${topLeft.row + 1}, ${topLeft.column}).value`); helper.checkOutlineLevel([0, 0], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 2, column: 1 }, topLeft); + helper.checkCellRange(cellRange, { row: 2, column: 1 }, topLeft); done(); }); }); @@ -1900,15 +1765,15 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: '', type: ExcelJS.ValueType.String, dataType: 'string', numberFormat: '[$-9]M\\/d\\/yyyy', alignment: alignLeftNoWrap }, gridCell: { value: ds[0].f1, rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, + { excelCell: { value: '', type: ExcelJS.ValueType.String, dataType: 'string', numberFormat: '[$-9]M\\/d\\/yyyy', alignment: alignLeftTopNoWrap }, gridCell: { value: ds[0].f1, rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, { excelCell: { value: ds[0].f2, type: ExcelJS.ValueType.Null, dataType: 'object' }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } }, - { excelCell: { value: ds[0].f3, type: ExcelJS.ValueType.Date, dataType: 'object', numberFormat: '[$-9]M\\/d\\/yyyy', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } }, - { excelCell: { value: ds[0].f4, type: ExcelJS.ValueType.Date, dataType: 'object', numberFormat: '[$-9]M\\/d\\/yyyy', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(3) } } + { excelCell: { value: ds[0].f3, type: ExcelJS.ValueType.Date, dataType: 'object', numberFormat: '[$-9]M\\/d\\/yyyy', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } }, + { excelCell: { value: ds[0].f4, type: ExcelJS.ValueType.Date, dataType: 'object', numberFormat: '[$-9]M\\/d\\/yyyy', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(3) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 1, column: 3 }, { row: 1, column: 4 }, topLeft); helper.checkAutoFilter(autoFilterEnabled, null); helper.checkFont(expectedCells); @@ -1917,7 +1782,7 @@ const moduleConfig = { helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0], topLeft.row); helper.checkCellFormat(expectedCells); - helper.checkCellsRange(cellsRange, { row: 1, column: 4 }, topLeft); + helper.checkCellRange(cellRange, { row: 1, column: 4 }, topLeft); done(); }); }); @@ -1944,13 +1809,13 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Date, dataType: 'object', numberFormat: '[$-9]d-M-yyyy', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, - { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Date, dataType: 'object', numberFormat: '[$-9]d+M+yyyy', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } } + { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Date, dataType: 'object', numberFormat: '[$-9]d-M-yyyy', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, + { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Date, dataType: 'object', numberFormat: '[$-9]d+M+yyyy', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 1, column: 2 }, { row: 1, column: 2 }, topLeft); helper.checkAutoFilter(autoFilterEnabled, null); helper.checkFont(expectedCells); @@ -1959,7 +1824,7 @@ const moduleConfig = { helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0], topLeft.row); helper.checkCellFormat(expectedCells); - helper.checkCellsRange(cellsRange, { row: 1, column: 2 }, topLeft); + helper.checkCellRange(cellRange, { row: 1, column: 2 }, topLeft); done(); }); }); @@ -2005,12 +1870,12 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: date.expected || date.value, type: ExcelJS.ValueType.Date, dataType: 'object', numberFormat: format.expectedFormat, alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, + { excelCell: { value: date.expected || date.value, type: ExcelJS.ValueType.Date, dataType: 'object', numberFormat: format.expectedFormat, alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 1, column: 1 }, { row: 1, column: 1 }, topLeft); helper.checkAutoFilter(autoFilterEnabled, null); helper.checkFont(expectedCells); @@ -2019,7 +1884,7 @@ const moduleConfig = { helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0], topLeft.row); helper.checkCellFormat(expectedCells); - helper.checkCellsRange(cellsRange, { row: 1, column: 1 }, topLeft); + helper.checkCellRange(cellRange, { row: 1, column: 1 }, topLeft); done(); }); }); @@ -2043,15 +1908,15 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: '', type: ExcelJS.ValueType.String, dataType: 'string', numberFormat: '[$-9]M\\/d\\/yyyy, H:mm AM/PM', alignment: alignLeftNoWrap }, gridCell: { value: ds[0].f1, rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, + { excelCell: { value: '', type: ExcelJS.ValueType.String, dataType: 'string', numberFormat: '[$-9]M\\/d\\/yyyy, H:mm AM/PM', alignment: alignLeftTopNoWrap }, gridCell: { value: ds[0].f1, rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, { excelCell: { value: ds[0].f2, type: ExcelJS.ValueType.Null, dataType: 'object' }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } }, - { excelCell: { value: ds[0].f3, type: ExcelJS.ValueType.Date, dataType: 'object', numberFormat: '[$-9]M\\/d\\/yyyy, H:mm AM/PM', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } }, - { excelCell: { value: ds[0].f4, type: ExcelJS.ValueType.Date, dataType: 'object', numberFormat: '[$-9]M\\/d\\/yyyy, H:mm AM/PM', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(3) } } + { excelCell: { value: ds[0].f3, type: ExcelJS.ValueType.Date, dataType: 'object', numberFormat: '[$-9]M\\/d\\/yyyy, H:mm AM/PM', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } }, + { excelCell: { value: ds[0].f4, type: ExcelJS.ValueType.Date, dataType: 'object', numberFormat: '[$-9]M\\/d\\/yyyy, H:mm AM/PM', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(3) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 1, column: 3 }, { row: 1, column: 4 }, topLeft); helper.checkAutoFilter(autoFilterEnabled, null); helper.checkFont(expectedCells); @@ -2060,7 +1925,7 @@ const moduleConfig = { helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0], topLeft.row); helper.checkCellFormat(expectedCells); - helper.checkCellsRange(cellsRange, { row: 1, column: 4 }, topLeft); + helper.checkCellRange(cellRange, { row: 1, column: 4 }, topLeft); done(); }); }); @@ -2114,14 +1979,14 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: 'F1', alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } } + { excelCell: { value: 'F1', alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } } ], [ - { excelCell: { value: '[object Object]', alignment: alignLeftNoWrap }, gridCell: { value: ds[0].f1, rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } } + { excelCell: { value: '[object Object]', alignment: alignLeftTopNoWrap }, gridCell: { value: ds[0].f1, rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 2, column: 1 }, { row: 2, column: 1 }, topLeft); helper.checkAutoFilter(autoFilterEnabled, { from: topLeft, to: { row: topLeft.row + 1, column: topLeft.column } }, { state: 'frozen', ySplit: topLeft.row }); helper.checkFont(expectedCells); @@ -2129,7 +1994,7 @@ const moduleConfig = { helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0, 0], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 2, column: 1 }, topLeft); + helper.checkCellRange(cellRange, { row: 2, column: 1 }, topLeft); done(); }); }); @@ -2152,22 +2017,22 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: '0.000%', alignment: alignRightNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, - { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: '0%', alignment: alignRightNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } }, - { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: '0%', alignment: alignRightNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } }, - { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: '0.0%', alignment: alignRightNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(3) } }, - { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: '0.000000%', alignment: alignRightNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(4) } } + { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: '0.000%', alignment: alignRightTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, + { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: '0%', alignment: alignRightTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } }, + { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: '0%', alignment: alignRightTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } }, + { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: '0.0%', alignment: alignRightTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(3) } }, + { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: '0.000000%', alignment: alignRightTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(4) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 1, column: 5 }, { row: 1, column: 5 }, topLeft); helper.checkAlignment(expectedCells); helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkCellFormat(expectedCells); - helper.checkCellsRange(cellsRange, { row: 1, column: 5 }, topLeft); + helper.checkCellRange(cellRange, { row: 1, column: 5 }, topLeft); done(); }); }); @@ -2190,22 +2055,22 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: '#,##0.000', alignment: alignRightNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, - { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: '#,##0', alignment: alignRightNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } }, - { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: '#,##0', alignment: alignRightNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } }, - { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: '#,##0.0', alignment: alignRightNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(3) } }, - { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: '#,##0.000000', alignment: alignRightNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(4) } } + { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: '#,##0.000', alignment: alignRightTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, + { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: '#,##0', alignment: alignRightTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } }, + { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: '#,##0', alignment: alignRightTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } }, + { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: '#,##0.0', alignment: alignRightTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(3) } }, + { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: '#,##0.000000', alignment: alignRightTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(4) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 1, column: 5 }, { row: 1, column: 5 }, topLeft); helper.checkAlignment(expectedCells); helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkCellFormat(expectedCells); - helper.checkCellsRange(cellsRange, { row: 1, column: 5 }, topLeft); + helper.checkCellRange(cellRange, { row: 1, column: 5 }, topLeft); done(); }); }); @@ -2228,22 +2093,22 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: '#000', alignment: alignRightNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, - { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: '#', alignment: alignRightNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } }, - { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: '#', alignment: alignRightNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } }, - { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: '#0', alignment: alignRightNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(3) } }, - { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: '#000000', alignment: alignRightNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(4) } } + { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: '#000', alignment: alignRightTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, + { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: '#', alignment: alignRightTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } }, + { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: '#', alignment: alignRightTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } }, + { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: '#0', alignment: alignRightTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(3) } }, + { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: '#000000', alignment: alignRightTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(4) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 1, column: 5 }, { row: 1, column: 5 }, topLeft); helper.checkAlignment(expectedCells); helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkCellFormat(expectedCells); - helper.checkCellsRange(cellsRange, { row: 1, column: 5 }, topLeft); + helper.checkCellRange(cellRange, { row: 1, column: 5 }, topLeft); done(); }); }); @@ -2266,22 +2131,22 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: '0.000E+00', alignment: alignRightNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, - { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: '0E+00', alignment: alignRightNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } }, - { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: '0.0E+00', alignment: alignRightNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } }, - { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: '0.0E+00', alignment: alignRightNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(3) } }, - { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: '0.000000E+00', alignment: alignRightNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(4) } } + { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: '0.000E+00', alignment: alignRightTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, + { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: '0E+00', alignment: alignRightTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } }, + { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: '0.0E+00', alignment: alignRightTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } }, + { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: '0.0E+00', alignment: alignRightTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(3) } }, + { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: '0.000000E+00', alignment: alignRightTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(4) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 1, column: 5 }, { row: 1, column: 5 }, topLeft); helper.checkAlignment(expectedCells); helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkCellFormat(expectedCells); - helper.checkCellsRange(cellsRange, { row: 1, column: 5 }, topLeft); + helper.checkCellRange(cellRange, { row: 1, column: 5 }, topLeft); done(); }); }); @@ -2304,22 +2169,22 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: undefined, alignment: alignRightNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, - { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: undefined, alignment: alignRightNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } }, - { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: undefined, alignment: alignRightNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } }, - { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: undefined, alignment: alignRightNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(3) } }, - { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: undefined, alignment: alignRightNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(4) } } + { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: undefined, alignment: alignRightTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, + { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: undefined, alignment: alignRightTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } }, + { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: undefined, alignment: alignRightTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } }, + { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: undefined, alignment: alignRightTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(3) } }, + { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: undefined, alignment: alignRightTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(4) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 1, column: 5 }, { row: 1, column: 5 }, topLeft); helper.checkAlignment(expectedCells); helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkCellFormat(expectedCells); - helper.checkCellsRange(cellsRange, { row: 1, column: 5 }, topLeft); + helper.checkCellRange(cellRange, { row: 1, column: 5 }, topLeft); done(); }); }); @@ -2342,22 +2207,22 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: '#,##0.000,K', alignment: alignRightNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, - { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: '#,##0,K', alignment: alignRightNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } }, - { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: '#,##0,K', alignment: alignRightNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } }, - { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: '#,##0.0,K', alignment: alignRightNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(3) } }, - { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: '#,##0.000000,K', alignment: alignRightNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(4) } } + { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: '#,##0.000,K', alignment: alignRightTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, + { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: '#,##0,K', alignment: alignRightTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } }, + { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: '#,##0,K', alignment: alignRightTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } }, + { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: '#,##0.0,K', alignment: alignRightTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(3) } }, + { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: '#,##0.000000,K', alignment: alignRightTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(4) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 1, column: 5 }, { row: 1, column: 5 }, topLeft); helper.checkAlignment(expectedCells); helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkCellFormat(expectedCells); - helper.checkCellsRange(cellsRange, { row: 1, column: 5 }, topLeft); + helper.checkCellRange(cellRange, { row: 1, column: 5 }, topLeft); done(); }); }); @@ -2380,22 +2245,22 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: '#,##0.000,,M', alignment: alignRightNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, - { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: '#,##0,,M', alignment: alignRightNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } }, - { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: '#,##0,,M', alignment: alignRightNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } }, - { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: '#,##0.0,,M', alignment: alignRightNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(3) } }, - { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: '#,##0.000000,,M', alignment: alignRightNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(4) } } + { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: '#,##0.000,,M', alignment: alignRightTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, + { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: '#,##0,,M', alignment: alignRightTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } }, + { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: '#,##0,,M', alignment: alignRightTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } }, + { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: '#,##0.0,,M', alignment: alignRightTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(3) } }, + { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: '#,##0.000000,,M', alignment: alignRightTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(4) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 1, column: 5 }, { row: 1, column: 5 }, topLeft); helper.checkAlignment(expectedCells); helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkCellFormat(expectedCells); - helper.checkCellsRange(cellsRange, { row: 1, column: 5 }, topLeft); + helper.checkCellRange(cellRange, { row: 1, column: 5 }, topLeft); done(); }); }); @@ -2418,22 +2283,22 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: '#,##0.000,,,B', alignment: alignRightNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, - { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: '#,##0,,,B', alignment: alignRightNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } }, - { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: '#,##0,,,B', alignment: alignRightNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } }, - { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: '#,##0.0,,,B', alignment: alignRightNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(3) } }, - { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: '#,##0.000000,,,B', alignment: alignRightNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(4) } } + { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: '#,##0.000,,,B', alignment: alignRightTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, + { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: '#,##0,,,B', alignment: alignRightTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } }, + { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: '#,##0,,,B', alignment: alignRightTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } }, + { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: '#,##0.0,,,B', alignment: alignRightTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(3) } }, + { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: '#,##0.000000,,,B', alignment: alignRightTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(4) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 1, column: 5 }, { row: 1, column: 5 }, topLeft); helper.checkAlignment(expectedCells); helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkCellFormat(expectedCells); - helper.checkCellsRange(cellsRange, { row: 1, column: 5 }, topLeft); + helper.checkCellRange(cellRange, { row: 1, column: 5 }, topLeft); done(); }); }); @@ -2456,22 +2321,22 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: '#,##0.000,,,,T', alignment: alignRightNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, - { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: '#,##0,,,,T', alignment: alignRightNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } }, - { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: '#,##0,,,,T', alignment: alignRightNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } }, - { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: '#,##0.0,,,,T', alignment: alignRightNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(3) } }, - { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: '#,##0.000000,,,,T', alignment: alignRightNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(4) } } + { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: '#,##0.000,,,,T', alignment: alignRightTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, + { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: '#,##0,,,,T', alignment: alignRightTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } }, + { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: '#,##0,,,,T', alignment: alignRightTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } }, + { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: '#,##0.0,,,,T', alignment: alignRightTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(3) } }, + { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: '#,##0.000000,,,,T', alignment: alignRightTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(4) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 1, column: 5 }, { row: 1, column: 5 }, topLeft); helper.checkAlignment(expectedCells); helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkCellFormat(expectedCells); - helper.checkCellsRange(cellsRange, { row: 1, column: 5 }, topLeft); + helper.checkCellRange(cellRange, { row: 1, column: 5 }, topLeft); done(); }); }); @@ -2495,23 +2360,23 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: '$#,##0.00_);\\($#,##0.00\\)', alignment: alignRightNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, - { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: '$#,##0.0000_);\\($#,##0.0000\\)', alignment: alignRightNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } }, - { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: '$#,##0_);\\($#,##0\\)', alignment: alignRightNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } }, - { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: '$#,##0_);\\($#,##0\\)', alignment: alignRightNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(3) } }, - { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: '$#,##0.0_);\\($#,##0.0\\)', alignment: alignRightNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(4) } }, - { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: '$#,##0.00000_);\\($#,##0.00000\\)', alignment: alignRightNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(5) } } + { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: '$#,##0.00_);\\($#,##0.00\\)', alignment: alignRightTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, + { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: '$#,##0.0000_);\\($#,##0.0000\\)', alignment: alignRightTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } }, + { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: '$#,##0_);\\($#,##0\\)', alignment: alignRightTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } }, + { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: '$#,##0_);\\($#,##0\\)', alignment: alignRightTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(3) } }, + { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: '$#,##0.0_);\\($#,##0.0\\)', alignment: alignRightTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(4) } }, + { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.Number, dataType: 'number', numberFormat: '$#,##0.00000_);\\($#,##0.00000\\)', alignment: alignRightTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(5) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 1, column: 6 }, { row: 1, column: 6 }, topLeft); helper.checkAlignment(expectedCells); helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkCellFormat(expectedCells); - helper.checkCellsRange(cellsRange, { row: 1, column: 6 }, topLeft); + helper.checkCellRange(cellRange, { row: 1, column: 6 }, topLeft); done(); }); }); @@ -2547,17 +2412,17 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.String, dataType: 'string', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, - { excelCell: { value: ds[0].f2, type: ExcelJS.ValueType.Number, dataType: 'number', alignment: alignRightNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } }, - { excelCell: { value: ds[0].f3, type: ExcelJS.ValueType.Date, dataType: 'object', numberFormat: '[$-9]M\\/d\\/yyyy', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } }, - { excelCell: { value: String(ds[0].f4), type: ExcelJS.ValueType.String, dataType: 'string', alignment: alignCenterNoWrap }, gridCell: { value: ds[0].f4, rowType: 'data', data: ds[0], column: dataGrid.columnOption(3) } }, - { excelCell: { value: 'name1', type: ExcelJS.ValueType.String, dataType: 'string', alignment: alignLeftNoWrap }, gridCell: { value: ds[0].f5, rowType: 'data', data: ds[0], column: dataGrid.columnOption(4) } }, - { excelCell: { value: ds[0].f6, type: ExcelJS.ValueType.Date, dataType: 'object', numberFormat: '[$-9]M\\/d\\/yyyy, H:mm AM/PM', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(5) } } + { excelCell: { value: ds[0].f1, type: ExcelJS.ValueType.String, dataType: 'string', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, + { excelCell: { value: ds[0].f2, type: ExcelJS.ValueType.Number, dataType: 'number', alignment: alignRightTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } }, + { excelCell: { value: ds[0].f3, type: ExcelJS.ValueType.Date, dataType: 'object', numberFormat: '[$-9]M\\/d\\/yyyy', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } }, + { excelCell: { value: String(ds[0].f4), type: ExcelJS.ValueType.String, dataType: 'string', alignment: alignCenterTopNoWrap }, gridCell: { value: ds[0].f4, rowType: 'data', data: ds[0], column: dataGrid.columnOption(3) } }, + { excelCell: { value: 'name1', type: ExcelJS.ValueType.String, dataType: 'string', alignment: alignLeftTopNoWrap }, gridCell: { value: ds[0].f5, rowType: 'data', data: ds[0], column: dataGrid.columnOption(4) } }, + { excelCell: { value: ds[0].f6, type: ExcelJS.ValueType.Date, dataType: 'object', numberFormat: '[$-9]M\\/d\\/yyyy, H:mm AM/PM', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(5) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 1, column: 6 }, { row: 1, column: 6 }, topLeft); helper.checkAutoFilter(autoFilterEnabled, null); helper.checkFont(expectedCells); @@ -2567,7 +2432,7 @@ const moduleConfig = { helper.checkOutlineLevel([0], topLeft.row); helper.checkCellFormat(expectedCells); helper.checkCellFormat(expectedCells); - helper.checkCellsRange(cellsRange, { row: 1, column: 6 }, topLeft); + helper.checkCellRange(cellRange, { row: 1, column: 6 }, topLeft); done(); }); }); @@ -2599,16 +2464,16 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: ds[0].f1, alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, - { excelCell: { value: 'Item_1', alignment: alignLeftNoWrap }, gridCell: { value: 0, rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } } + { excelCell: { value: ds[0].f1, alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, + { excelCell: { value: 'Item_1', alignment: alignLeftTopNoWrap }, gridCell: { value: 0, rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } } ], [ - { excelCell: { value: ds[1].f1, alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(0) } }, - { excelCell: { value: 'Item_2', alignment: alignLeftNoWrap }, gridCell: { value: 1, rowType: 'data', data: ds[1], column: dataGrid.columnOption(1) } } + { excelCell: { value: ds[1].f1, alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(0) } }, + { excelCell: { value: 'Item_2', alignment: alignLeftTopNoWrap }, gridCell: { value: 1, rowType: 'data', data: ds[1], column: dataGrid.columnOption(1) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 2, column: 2 }, { row: 2, column: 2 }, topLeft); helper.checkAutoFilter(autoFilterEnabled, null); helper.checkFont(expectedCells); @@ -2616,7 +2481,7 @@ const moduleConfig = { helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0, 0], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 2, column: 2 }, topLeft); + helper.checkCellRange(cellRange, { row: 2, column: 2 }, topLeft); done(); }); }); @@ -2640,18 +2505,18 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: 'f1_1', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, - { excelCell: { value: 'f2_1', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } }, - { excelCell: { value: 'f3_1', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } } + { excelCell: { value: 'f1_1', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, + { excelCell: { value: 'f2_1', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } }, + { excelCell: { value: 'f3_1', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } } ], [ - { excelCell: { value: 'f1_2', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(0) } }, - { excelCell: { value: 'f2_2', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(1) } }, - { excelCell: { value: 'f3_2', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(2) } } + { excelCell: { value: 'f1_2', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(0) } }, + { excelCell: { value: 'f2_2', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(1) } }, + { excelCell: { value: 'f3_2', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(2) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 2, column: 3 }, { row: 2, column: 3 }, topLeft); helper.checkAutoFilter(autoFilterEnabled, null); helper.checkFont(expectedCells); @@ -2659,12 +2524,12 @@ const moduleConfig = { helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0, 0], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 2, column: 3 }, topLeft); + helper.checkCellRange(cellRange, { row: 2, column: 3 }, topLeft); done(); }); }); - QUnit.test('Data - 3 columns, grid.wordWrapEnabled: true, export.excelWrapTextEnabled: false, col_1.alignment: \'center\', col_2.alignment: \'right\', col_3.alignment: \'left\'', function(assert) { + QUnit.test('Data - 3 columns, grid.wordWrapEnabled: true, col_1.alignment: \'center\', col_2.alignment: \'right\', col_3.alignment: \'left\'', function(assert) { const done = assert.async(); const ds = [ { f1: 'f1_1', f2: true, f3: 1 }, @@ -2676,28 +2541,25 @@ const moduleConfig = { { dataField: 'f2', caption: 'f2', dataType: 'boolean', alignment: 'right' }, { dataField: 'f3', caption: 'f3', dataType: 'number', alignment: 'left' }, ], - export: { - excelWrapTextEnabled: false - }, dataSource: ds, - wordWrapEnabled: false, + wordWrapEnabled: true, loadingTimeout: undefined, showColumnHeaders: false }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: 'f1_1', alignment: alignCenterNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, - { excelCell: { value: 'true', alignment: alignRightTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1), value: true } }, - { excelCell: { value: 1, alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } } + { excelCell: { value: 'f1_1', alignment: alignCenterTopWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, + { excelCell: { value: 'true', alignment: alignRightTopWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1), value: true } }, + { excelCell: { value: 1, alignment: alignLeftTopWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } } ], [ - { excelCell: { value: 'f1_2', alignment: alignCenterNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(0) } }, - { excelCell: { value: 'false', alignment: alignRightTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(1), value: false } }, - { excelCell: { value: 2, alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(2) } } + { excelCell: { value: 'f1_2', alignment: alignCenterTopWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(0) } }, + { excelCell: { value: 'false', alignment: alignRightTopWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(1), value: false } }, + { excelCell: { value: 2, alignment: alignLeftTopWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(2) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells, { keepColumnWidths: false })).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells, { keepColumnWidths: false })).then((cellRange) => { helper.checkRowAndColumnCount({ row: 2, column: 3 }, { row: 2, column: 3 }, topLeft); helper.checkAutoFilter(autoFilterEnabled, null); helper.checkFont(expectedCells); @@ -2705,7 +2567,7 @@ const moduleConfig = { helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0, 0], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 2, column: 3 }, topLeft); + helper.checkCellRange(cellRange, { row: 2, column: 3 }, topLeft); done(); }); }); @@ -2730,16 +2592,16 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: 'f2_1', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } }, - { excelCell: { value: 'f3_1', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } } + { excelCell: { value: 'f2_1', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } }, + { excelCell: { value: 'f3_1', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } } ], [ - { excelCell: { value: 'f2_2', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(1) } }, - { excelCell: { value: 'f3_2', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(2) } } + { excelCell: { value: 'f2_2', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(1) } }, + { excelCell: { value: 'f3_2', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(2) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 2, column: 2 }, { row: 2, column: 2 }, topLeft); helper.checkColumnWidths([excelColumnWidthFromColumn200Pixels, excelColumnWidthFromColumn300Pixels, undefined], topLeft.column); helper.checkAutoFilter(autoFilterEnabled, null); @@ -2748,7 +2610,7 @@ const moduleConfig = { helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0, 0], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 2, column: 2 }, topLeft); + helper.checkCellRange(cellRange, { row: 2, column: 2 }, topLeft); done(); }); }); @@ -2773,16 +2635,16 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: 'f1_1', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, - { excelCell: { value: 'f3_1', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } } + { excelCell: { value: 'f1_1', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, + { excelCell: { value: 'f3_1', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } } ], [ - { excelCell: { value: 'f1_2', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(0) } }, - { excelCell: { value: 'f3_2', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(2) } } + { excelCell: { value: 'f1_2', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(0) } }, + { excelCell: { value: 'f3_2', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(2) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 2, column: 2 }, { row: 2, column: 2 }, topLeft); helper.checkColumnWidths([excelColumnWidthFromColumn200Pixels, excelColumnWidthFromColumn300Pixels, undefined], topLeft.column); helper.checkAutoFilter(autoFilterEnabled, null); @@ -2791,7 +2653,7 @@ const moduleConfig = { helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0, 0], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 2, column: 2 }, topLeft); + helper.checkCellRange(cellRange, { row: 2, column: 2 }, topLeft); done(); }); }); @@ -2816,16 +2678,16 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: 'f1_1', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, - { excelCell: { value: 'f2_1', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } } + { excelCell: { value: 'f1_1', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, + { excelCell: { value: 'f2_1', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } } ], [ - { excelCell: { value: 'f1_2', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(0) } }, - { excelCell: { value: 'f2_2', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(1) } } + { excelCell: { value: 'f1_2', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(0) } }, + { excelCell: { value: 'f2_2', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(1) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 2, column: 2 }, { row: 2, column: 2 }, topLeft); helper.checkColumnWidths([excelColumnWidthFromColumn200Pixels, excelColumnWidthFromColumn300Pixels, undefined], topLeft.column); helper.checkAutoFilter(autoFilterEnabled, null); @@ -2834,7 +2696,7 @@ const moduleConfig = { helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0, 0], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 2, column: 2 }, topLeft); + helper.checkCellRange(cellRange, { row: 2, column: 2 }, topLeft); done(); }); }); @@ -2859,18 +2721,18 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: 'f2_1', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } }, - { excelCell: { value: 'f3_1', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } }, - { excelCell: { value: 'f1_1', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, + { excelCell: { value: 'f2_1', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } }, + { excelCell: { value: 'f3_1', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } }, + { excelCell: { value: 'f1_1', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, ], [ - { excelCell: { value: 'f2_2', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(1) } }, - { excelCell: { value: 'f3_2', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(2) } }, - { excelCell: { value: 'f1_2', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(0) } }, + { excelCell: { value: 'f2_2', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(1) } }, + { excelCell: { value: 'f3_2', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(2) } }, + { excelCell: { value: 'f1_2', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(0) } }, ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 2, column: 3 }, { row: 2, column: 3 }, topLeft); helper.checkColumnWidths([excelColumnWidthFromColumn150Pixels, excelColumnWidthFromColumn250Pixels, excelColumnWidthFromColumn100Pixels], topLeft.column); helper.checkAutoFilter(autoFilterEnabled, null); @@ -2879,7 +2741,7 @@ const moduleConfig = { helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0, 0], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 2, column: 3 }, topLeft); + helper.checkCellRange(cellRange, { row: 2, column: 3 }, topLeft); done(); }); }); @@ -2904,18 +2766,18 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: 'f3_1', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } }, - { excelCell: { value: 'f1_1', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, - { excelCell: { value: 'f2_1', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } }, + { excelCell: { value: 'f3_1', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } }, + { excelCell: { value: 'f1_1', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, + { excelCell: { value: 'f2_1', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } }, ], [ - { excelCell: { value: 'f3_2', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(2) } }, - { excelCell: { value: 'f1_2', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(0) } }, - { excelCell: { value: 'f2_2', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(1) } }, + { excelCell: { value: 'f3_2', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(2) } }, + { excelCell: { value: 'f1_2', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(0) } }, + { excelCell: { value: 'f2_2', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(1) } }, ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 2, column: 3 }, { row: 2, column: 3 }, topLeft); helper.checkColumnWidths([excelColumnWidthFromColumn250Pixels, excelColumnWidthFromColumn100Pixels, excelColumnWidthFromColumn150Pixels], topLeft.column); helper.checkAutoFilter(autoFilterEnabled, null); @@ -2924,7 +2786,7 @@ const moduleConfig = { helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0, 0], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 2, column: 3 }, topLeft); + helper.checkCellRange(cellRange, { row: 2, column: 3 }, topLeft); done(); }); }); @@ -2949,18 +2811,18 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: 'f1_1', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, - { excelCell: { value: 'f3_1', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } }, - { excelCell: { value: 'f2_1', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } }, + { excelCell: { value: 'f1_1', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, + { excelCell: { value: 'f3_1', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } }, + { excelCell: { value: 'f2_1', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } }, ], [ - { excelCell: { value: 'f1_2', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(0) } }, - { excelCell: { value: 'f3_2', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(2) } }, - { excelCell: { value: 'f2_2', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(1) } }, + { excelCell: { value: 'f1_2', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(0) } }, + { excelCell: { value: 'f3_2', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(2) } }, + { excelCell: { value: 'f2_2', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(1) } }, ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 2, column: 3 }, { row: 2, column: 3 }, topLeft); helper.checkColumnWidths([excelColumnWidthFromColumn100Pixels, excelColumnWidthFromColumn250Pixels, excelColumnWidthFromColumn150Pixels], topLeft.column); helper.checkAutoFilter(autoFilterEnabled, null); @@ -2969,7 +2831,7 @@ const moduleConfig = { helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0, 0], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 2, column: 3 }, topLeft); + helper.checkCellRange(cellRange, { row: 2, column: 3 }, topLeft); done(); }); }); @@ -2990,20 +2852,20 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: 'f2', alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', value: 'f2', column: dataGrid.columnOption(1) } } + { excelCell: { value: 'f2', alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', value: 'f2', column: dataGrid.columnOption(1) } } ], [ - { excelCell: { value: 'f1: f1_1', alignment: alignLeftNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(0), value: ds[0].f1 } } + { excelCell: { value: 'f1: f1_1', alignment: alignLeftTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(0), value: ds[0].f1 } } ], [ - { excelCell: { value: 'f2_1', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } } + { excelCell: { value: 'f2_1', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } } ], [ - { excelCell: { value: 'f1: f1_2', alignment: alignLeftNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(0), value: ds[1].f1 } } + { excelCell: { value: 'f1: f1_2', alignment: alignLeftTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(0), value: ds[1].f1 } } ], [ - { excelCell: { value: 'f2_2', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(1) } } + { excelCell: { value: 'f2_2', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(1) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 5, column: 1 }, { row: 5, column: 1 }, topLeft); helper.checkAutoFilter(autoFilterEnabled, { from: topLeft, to: { row: topLeft.row + 4, column: topLeft.column } }, { state: 'frozen', ySplit: topLeft.row }); helper.checkFont(expectedCells); @@ -3011,7 +2873,7 @@ const moduleConfig = { helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0, 0, 1, 0, 1], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 5, column: 1 }, topLeft); + helper.checkCellRange(cellRange, { row: 5, column: 1 }, topLeft); done(); }); }); @@ -3032,16 +2894,16 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: 'f2', alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', value: 'f2', column: dataGrid.columnOption(1) } } + { excelCell: { value: 'f2', alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', value: 'f2', column: dataGrid.columnOption(1) } } ], [ - { excelCell: { value: 'f1: 1996-07-04', alignment: alignLeftNoWrap, font: { bold: true } }, gridCell: { value: remoteOperations ? ds[0].f1 : new Date(ds[0].f1), rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(0) } } + { excelCell: { value: 'f1: 1996-07-04', alignment: alignLeftTopNoWrap, font: { bold: true } }, gridCell: { value: remoteOperations ? ds[0].f1 : new Date(ds[0].f1), rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(0) } } ], [ - { excelCell: { value: 'f1_1', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } } + { excelCell: { value: 'f1_1', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 3, column: 1 }, { row: 3, column: 1 }, topLeft); helper.checkAutoFilter(autoFilterEnabled, { from: topLeft, to: { row: topLeft.row + 2, column: topLeft.column } }, { state: 'frozen', ySplit: topLeft.row }); helper.checkFont(expectedCells); @@ -3049,7 +2911,7 @@ const moduleConfig = { helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0, 0, 1], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 3, column: 1 }, topLeft); + helper.checkCellRange(cellRange, { row: 3, column: 1 }, topLeft); done(); }); }); @@ -3084,7 +2946,7 @@ const moduleConfig = { helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); done(); @@ -3117,7 +2979,7 @@ const moduleConfig = { helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); done(); @@ -3140,22 +3002,22 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: 'f1', alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } }, - { excelCell: { value: 'f2', alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(1) } }, + { excelCell: { value: 'f1', alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } }, + { excelCell: { value: 'f2', alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(1) } }, ], [ - { excelCell: { value: 'f1: custom', alignment: alignLeftNoWrap, font: { bold: true } }, gridCell: { value: 'custom', rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(0) } }, + { excelCell: { value: 'f1: custom', alignment: alignLeftTopNoWrap, font: { bold: true } }, gridCell: { value: 'custom', rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(0) } }, { excelCell: { value: null }, gridCell: { value: undefined, rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(1) } } ], [ - { excelCell: { value: 'f1_1', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, - { excelCell: { value: 'f2_1', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } } + { excelCell: { value: 'f1_1', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, + { excelCell: { value: 'f2_1', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } } ], [ - { excelCell: { value: 'f1_2', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(0) } }, - { excelCell: { value: 'f2_2', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(1) } } + { excelCell: { value: 'f1_2', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(0) } }, + { excelCell: { value: 'f2_2', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(1) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 4, column: 2 }, { row: 4, column: 2 }, topLeft); helper.checkColumnWidths([excelColumnWidthFromColumn100Pixels, excelColumnWidthFromColumn150Pixels, undefined], topLeft.column); helper.checkAutoFilter(autoFilterEnabled, { from: topLeft, to: { row: topLeft.row + 3, column: topLeft.column + 1 } }, { state: 'frozen', ySplit: topLeft.row }); @@ -3164,7 +3026,7 @@ const moduleConfig = { helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0, 0], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 4, column: 2 }, topLeft); + helper.checkCellRange(cellRange, { row: 4, column: 2 }, topLeft); done(); }); }); @@ -3195,14 +3057,14 @@ const moduleConfig = { helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); done(); }); }); - QUnit.test('Grouping - 1 level, grid.wrapTextEnabled: false, export.excelWrapTextEnabled: true, col_1.alignment: \'center\', col_2.alignment: \'right\'', function(assert) { + QUnit.test('Grouping - 1 level, grid.wordWrapEnabled: true, col_1.alignment: \'center\', col_2.alignment: \'right\'', function(assert) { const done = assert.async(); const ds = [ { f1: 'f1_1', f2: 'f2_1' }, @@ -3213,29 +3075,26 @@ const moduleConfig = { { dataField: 'f1', caption: 'f1', dataType: 'string', groupIndex: 0, alignment: 'center' }, { dataField: 'f2', caption: 'f2', dataType: 'string', alignment: 'right' }, ], - wrapTextEnabled: false, - export: { - excelWrapTextEnabled: true - }, + wordWrapEnabled: true, dataSource: ds, loadingTimeout: undefined }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: 'f2', alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', value: 'f2', column: dataGrid.columnOption(1) } } + { excelCell: { value: 'f2', alignment: alignCenterTopWrap, font: { bold: true } }, gridCell: { rowType: 'header', value: 'f2', column: dataGrid.columnOption(1) } } ], [ - { excelCell: { value: 'f1: f1_1', alignment: alignLeftNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(0), value: ds[0].f1 } } + { excelCell: { value: 'f1: f1_1', alignment: alignLeftTopWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(0), value: ds[0].f1 } } ], [ { excelCell: { value: 'f2_1', alignment: alignRightTopWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } } ], [ - { excelCell: { value: 'f1: f1_2', alignment: alignLeftNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(0), value: ds[1].f1 } } + { excelCell: { value: 'f1: f1_2', alignment: alignLeftTopWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(0), value: ds[1].f1 } } ], [ { excelCell: { value: 'f2_2', alignment: alignRightTopWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(1) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 5, column: 1 }, { row: 5, column: 1 }, topLeft); helper.checkAutoFilter(autoFilterEnabled, { from: topLeft, to: { row: topLeft.row + 4, column: topLeft.column } }, { state: 'frozen', ySplit: topLeft.row }); helper.checkFont(expectedCells); @@ -3243,12 +3102,12 @@ const moduleConfig = { helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0, 0, 1, 0, 1], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 5, column: 1 }, topLeft); + helper.checkCellRange(cellRange, { row: 5, column: 1 }, topLeft); done(); }); }); - QUnit.test('Grouping - 1 level, export.excelWrapTextEnabled: true, rtlEnabled: true', function(assert) { + QUnit.test('Grouping - 1 level, grid.wordWrapEnabled: true, rtlEnabled: true', function(assert) { const done = assert.async(); const ds = [ { f1: 'f1_1', f2: 'f2_1' }, @@ -3259,29 +3118,27 @@ const moduleConfig = { { dataField: 'f1', caption: 'f1', dataType: 'string', groupIndex: 0 }, { dataField: 'f2', caption: 'f2', dataType: 'string' }, ], - export: { - excelWrapTextEnabled: true - }, + wordWrapEnabled: true, dataSource: ds, rtlEnabled: true, loadingTimeout: undefined }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: 'f2', alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', value: 'f2', column: dataGrid.columnOption(1) } } + { excelCell: { value: 'f2', alignment: alignCenterTopWrap, font: { bold: true } }, gridCell: { rowType: 'header', value: 'f2', column: dataGrid.columnOption(1) } } ], [ - { excelCell: { value: 'f1: f1_1', alignment: alignRightNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(0), value: ds[0].f1 } } + { excelCell: { value: 'f1: f1_1', alignment: alignRightTopWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(0), value: ds[0].f1 } } ], [ - { excelCell: { value: 'f2_1', alignment: alignRightWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } } + { excelCell: { value: 'f2_1', alignment: alignRightTopWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } } ], [ - { excelCell: { value: 'f1: f1_2', alignment: alignRightNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(0), value: ds[1].f1 } } + { excelCell: { value: 'f1: f1_2', alignment: alignRightTopWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(0), value: ds[1].f1 } } ], [ - { excelCell: { value: 'f2_2', alignment: alignRightWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(1) } } + { excelCell: { value: 'f2_2', alignment: alignRightTopWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(1) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells, { keepColumnWidths: false, wrapText: true })).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells, { keepColumnWidths: false, wrapText: true })).then((cellRange) => { helper.checkRowAndColumnCount({ row: 5, column: 1 }, { row: 5, column: 1 }, topLeft); helper.checkAutoFilter(autoFilterEnabled, { from: topLeft, to: { row: topLeft.row + 4, column: topLeft.column } }, { state: 'frozen', ySplit: topLeft.row, rightToLeft: true }); helper.checkFont(expectedCells); @@ -3289,7 +3146,7 @@ const moduleConfig = { helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0, 0, 1, 0, 1], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 5, column: 1 }, topLeft); + helper.checkCellRange(cellRange, { row: 5, column: 1 }, topLeft); done(); }); }); @@ -3310,14 +3167,14 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: 'F1: str1', alignment: alignLeftNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(0), value: ds[0].f1 } } + { excelCell: { value: 'F1: str1', alignment: alignLeftTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(0), value: ds[0].f1 } } ], [ - { excelCell: { value: 'str1_1', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } } + { excelCell: { value: 'str1_1', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells, { selectedRowsOnly: true })).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells, { selectedRowsOnly: true })).then((cellRange) => { helper.checkRowAndColumnCount({ row: 2, column: 1 }, { row: 2, column: 1 }, topLeft); helper.checkAutoFilter(autoFilterEnabled, null); helper.checkFont(expectedCells); @@ -3325,7 +3182,7 @@ const moduleConfig = { helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0, 1], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 2, column: 1 }, topLeft); + helper.checkCellRange(cellRange, { row: 2, column: 1 }, topLeft); done(); }); }); @@ -3346,14 +3203,14 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: 'F1: str1', alignment: alignLeftNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(0), value: ds[0].f1 } } + { excelCell: { value: 'F1: str1', alignment: alignLeftTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(0), value: ds[0].f1 } } ], [ - { excelCell: { value: 'str_1_2', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(1) } } + { excelCell: { value: 'str_1_2', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(1) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells, { selectedRowsOnly: true })).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells, { selectedRowsOnly: true })).then((cellRange) => { helper.checkRowAndColumnCount({ row: 2, column: 1 }, { row: 2, column: 1 }, topLeft); helper.checkAutoFilter(autoFilterEnabled, null); helper.checkFont(expectedCells); @@ -3361,7 +3218,7 @@ const moduleConfig = { helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0, 1], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 2, column: 1 }, topLeft); + helper.checkCellRange(cellRange, { row: 2, column: 1 }, topLeft); done(); }); }); @@ -3382,16 +3239,16 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: 'F1: str1', alignment: alignLeftNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(0), value: ds[0].f1 } } + { excelCell: { value: 'F1: str1', alignment: alignLeftTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(0), value: ds[0].f1 } } ], [ - { excelCell: { value: 'str1_1', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } } + { excelCell: { value: 'str1_1', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } } ], [ - { excelCell: { value: 'str_1_2', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(1) } } + { excelCell: { value: 'str_1_2', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(1) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells, { selectedRowsOnly: true })).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells, { selectedRowsOnly: true })).then((cellRange) => { helper.checkRowAndColumnCount({ row: 3, column: 1 }, { row: 3, column: 1 }, topLeft); helper.checkAutoFilter(autoFilterEnabled, null); helper.checkFont(expectedCells); @@ -3399,7 +3256,7 @@ const moduleConfig = { helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0, 1, 1], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 3, column: 1 }, topLeft); + helper.checkCellRange(cellRange, { row: 3, column: 1 }, topLeft); done(); }); }); @@ -3419,19 +3276,19 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: 'Field 3: str1!', alignment: alignLeftNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(2), value: 'str1!' } }, + { excelCell: { value: 'Field 3: str1!', alignment: alignLeftTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(2), value: 'str1!' } }, { excelCell: { value: null }, gridCell: { value: undefined, rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(1) } } ], [ - { excelCell: { value: 'str1', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, - { excelCell: { value: 'str1_f2', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } } + { excelCell: { value: 'str1', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, + { excelCell: { value: 'str1_f2', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } } ], [ - { excelCell: { value: 'str1', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(0) } }, - { excelCell: { value: 'str1_f2', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(1) } } + { excelCell: { value: 'str1', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(0) } }, + { excelCell: { value: 'str1_f2', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(1) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 3, column: 2 }, { row: 3, column: 2 }, topLeft); helper.checkAutoFilter(autoFilterEnabled, null); helper.checkFont(expectedCells); @@ -3439,7 +3296,7 @@ const moduleConfig = { helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0, 1, 1], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 3, column: 2 }, topLeft); + helper.checkCellRange(cellRange, { row: 3, column: 2 }, topLeft); done(); }); }); @@ -3461,23 +3318,23 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: 'Field 3: str1!', alignment: alignLeftNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(2), value: 'str1!' } }, + { excelCell: { value: 'Field 3: str1!', alignment: alignLeftTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(2), value: 'str1!' } }, { excelCell: { value: null }, gridCell: { value: undefined, rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(1) } } ], [ - { excelCell: { value: 'str1', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(0) } }, - { excelCell: { value: 'str1_f2', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(1) } } + { excelCell: { value: 'str1', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(0) } }, + { excelCell: { value: 'str1_f2', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(1) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells, { keepColumnWidths: false, selectedRowsOnly: true })).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells, { keepColumnWidths: false, selectedRowsOnly: true })).then((cellRange) => { helper.checkRowAndColumnCount({ row: 2, column: 2 }, { row: 2, column: 2 }, topLeft); helper.checkFont(expectedCells); helper.checkAlignment(expectedCells); helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0, 1], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 2, column: 2 }, topLeft); + helper.checkCellRange(cellRange, { row: 2, column: 2 }, topLeft); done(); }); }); @@ -3498,14 +3355,14 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: 'F1: str2_1', alignment: alignLeftNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(0), value: ds[1].f1 } } + { excelCell: { value: 'F1: str2_1', alignment: alignLeftTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(0), value: ds[1].f1 } } ], [ - { excelCell: { value: 'str2_2', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(1) } } + { excelCell: { value: 'str2_2', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(1) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells, { selectedRowsOnly: true })).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells, { selectedRowsOnly: true })).then((cellRange) => { helper.checkRowAndColumnCount({ row: 2, column: 1 }, { row: 2, column: 1 }, topLeft); helper.checkAutoFilter(autoFilterEnabled, null); helper.checkFont(expectedCells); @@ -3513,7 +3370,7 @@ const moduleConfig = { helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0, 1], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 2, column: 1 }, topLeft); + helper.checkCellRange(cellRange, { row: 2, column: 1 }, topLeft); done(); }); }); @@ -3538,18 +3395,18 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: 'f1: f1_1 (Max of f2 is 1)', alignment: alignLeftNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(0), value: ds[0].f1, groupSummaryItems: [{ name: 'GroupItems 1', value: 1 }] } } + { excelCell: { value: 'f1: f1_1 (Max of f2 is 1)', alignment: alignLeftTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(0), value: ds[0].f1, groupSummaryItems: [{ name: 'GroupItems 1', value: 1 }] } } ], [ - { excelCell: { value: 1, alignment: alignRightNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } } + { excelCell: { value: 1, alignment: alignRightTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } } ], [ - { excelCell: { value: 'f1: f1_2 (Max of f2 is 3)', alignment: alignLeftNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(0), value: ds[1].f1, groupSummaryItems: [{ name: 'GroupItems 1', value: 3 }] } } + { excelCell: { value: 'f1: f1_2 (Max of f2 is 3)', alignment: alignLeftTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(0), value: ds[1].f1, groupSummaryItems: [{ name: 'GroupItems 1', value: 3 }] } } ], [ - { excelCell: { value: 3, alignment: alignRightNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(1) } } + { excelCell: { value: 3, alignment: alignRightTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(1) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 4, column: 1 }, { row: 4, column: 1 }, topLeft); helper.checkAutoFilter(autoFilterEnabled, null); helper.checkFont(expectedCells); @@ -3557,7 +3414,7 @@ const moduleConfig = { helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0, 1, 0, 1], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 4, column: 1 }, topLeft); + helper.checkCellRange(cellRange, { row: 4, column: 1 }, topLeft); done(); }); }); @@ -3622,22 +3479,22 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: 'f1: f1_1', alignment: alignLeftNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 0, value: ds[0].f1, column: dataGrid.columnOption(0) } } + { excelCell: { value: 'f1: f1_1', alignment: alignLeftTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 0, value: ds[0].f1, column: dataGrid.columnOption(0) } } ], [ - { excelCell: { value: 'f2_1', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } } + { excelCell: { value: 'f2_1', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } } ], [ - { excelCell: { value: 'Max: f2_1', alignment: alignLeftWrap, font: { bold: true } }, gridCell: { rowType: 'groupFooter', value: ds[0].f2, column: dataGrid.columnOption(1) } } + { excelCell: { value: 'Max: f2_1', alignment: alignLeftTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'groupFooter', value: ds[0].f2, column: dataGrid.columnOption(1) } } ], [ - { excelCell: { value: 'f1: f1_2', alignment: alignLeftNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', value: 'f1_2', groupIndex: 0, column: dataGrid.columnOption(0) } } + { excelCell: { value: 'f1: f1_2', alignment: alignLeftTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', value: 'f1_2', groupIndex: 0, column: dataGrid.columnOption(0) } } ], [ - { excelCell: { value: 'f2_2', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(1) } } + { excelCell: { value: 'f2_2', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(1) } } ], [ - { excelCell: { value: 'Max: f2_2', alignment: alignLeftWrap, font: { bold: true } }, gridCell: { rowType: 'groupFooter', value: 'f2_2', column: dataGrid.columnOption(1) } } + { excelCell: { value: 'Max: f2_2', alignment: alignLeftTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'groupFooter', value: 'f2_2', column: dataGrid.columnOption(1) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 6, column: 1 }, { row: 6, column: 1 }, topLeft); helper.checkAutoFilter(autoFilterEnabled, null); helper.checkFont(expectedCells); @@ -3645,7 +3502,7 @@ const moduleConfig = { helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0, 1, 1, 0, 1, 1], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 6, column: 1 }, topLeft); + helper.checkCellRange(cellRange, { row: 6, column: 1 }, topLeft); done(); }); }); @@ -3673,22 +3530,22 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: 'f1: f1_1', alignment: alignRightNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 0, value: ds[0].f1, column: dataGrid.columnOption(0) } } + { excelCell: { value: 'f1: f1_1', alignment: alignRightTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 0, value: ds[0].f1, column: dataGrid.columnOption(0) } } ], [ - { excelCell: { value: 'f2_1', alignment: alignRightNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } } + { excelCell: { value: 'f2_1', alignment: alignRightTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } } ], [ - { excelCell: { value: 'Max: f2_1', alignment: alignRightTopWrap, font: { bold: true } }, gridCell: { rowType: 'groupFooter', value: ds[0].f2, column: dataGrid.columnOption(1) } } + { excelCell: { value: 'Max: f2_1', alignment: alignRightTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'groupFooter', value: ds[0].f2, column: dataGrid.columnOption(1) } } ], [ - { excelCell: { value: 'f1: f1_2', alignment: alignRightNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', value: 'f1_2', groupIndex: 0, column: dataGrid.columnOption(0) } } + { excelCell: { value: 'f1: f1_2', alignment: alignRightTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', value: 'f1_2', groupIndex: 0, column: dataGrid.columnOption(0) } } ], [ - { excelCell: { value: 'f2_2', alignment: alignRightNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(1) } } + { excelCell: { value: 'f2_2', alignment: alignRightTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(1) } } ], [ - { excelCell: { value: 'Max: f2_2', alignment: alignRightTopWrap, font: { bold: true } }, gridCell: { rowType: 'groupFooter', value: 'f2_2', column: dataGrid.columnOption(1) } } + { excelCell: { value: 'Max: f2_2', alignment: alignRightTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'groupFooter', value: 'f2_2', column: dataGrid.columnOption(1) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 6, column: 1 }, { row: 6, column: 1 }, topLeft); helper.checkAutoFilter(autoFilterEnabled, null, { 'rightToLeft': true }); helper.checkFont(expectedCells); @@ -3696,7 +3553,7 @@ const moduleConfig = { helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0, 1, 1, 0, 1, 1], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 6, column: 1 }, topLeft); + helper.checkCellRange(cellRange, { row: 6, column: 1 }, topLeft); done(); }); }); @@ -3726,22 +3583,22 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: 'f1: f1_1 (Count: 1, Count: 1)', alignment: alignLeftNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(0), value: ds[0].f1, groupSummaryItems: [{ 'name': 'GroupItems 1', value: 1 }, { 'name': 'GroupItems 2', value: 1 } ] } }, + { excelCell: { value: 'f1: f1_1 (Count: 1, Count: 1)', alignment: alignLeftTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(0), value: ds[0].f1, groupSummaryItems: [{ 'name': 'GroupItems 1', value: 1 }, { 'name': 'GroupItems 2', value: 1 } ] } }, { excelCell: { value: null }, gridCell: { value: undefined, rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(2) } } ], [ - { excelCell: { value: 'f1_2', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } }, - { excelCell: { value: 'f3_1', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } } + { excelCell: { value: 'f1_2', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } }, + { excelCell: { value: 'f3_1', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } } ], [ - { excelCell: { value: 'f1: f1_2 (Count: 1, Count: 1)', alignment: alignLeftNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(0), value: ds[0].f2, groupSummaryItems: [{ 'name': 'GroupItems 1', value: 1 }, { 'name': 'GroupItems 2', value: 1 } ] } }, + { excelCell: { value: 'f1: f1_2 (Count: 1, Count: 1)', alignment: alignLeftTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(0), value: ds[0].f2, groupSummaryItems: [{ 'name': 'GroupItems 1', value: 1 }, { 'name': 'GroupItems 2', value: 1 } ] } }, { excelCell: { value: null }, gridCell: { value: undefined, rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(2) } } ], [ - { excelCell: { value: 'f2_2', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(1) } }, - { excelCell: { value: 'f3_2', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(2) } } + { excelCell: { value: 'f2_2', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(1) } }, + { excelCell: { value: 'f3_2', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(2) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 4, column: 2 }, { row: 4, column: 2 }, topLeft); helper.checkAutoFilter(autoFilterEnabled, null); helper.checkFont(expectedCells); @@ -3749,7 +3606,7 @@ const moduleConfig = { helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0, 1, 0, 1], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 4, column: 2 }, topLeft); + helper.checkCellRange(cellRange, { row: 4, column: 2 }, topLeft); done(); }); }); @@ -3780,19 +3637,19 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: 'f1: f2_1', alignment: alignLeftNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(0), value: ds[1].f1 } }, - { excelCell: { value: 'Count: 1', alignment: alignLeftWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(2), groupSummaryItems: [{ 'name': 'GroupItems 2', value: 1 }] } } + { excelCell: { value: 'f1: f2_1', alignment: alignLeftTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(0), value: ds[1].f1 } }, + { excelCell: { value: 'Count: 1', alignment: alignLeftTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(2), groupSummaryItems: [{ 'name': 'GroupItems 2', value: 1 }] } } ], [ - { excelCell: { value: 'f2_2', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(1) } }, - { excelCell: { value: 'f3_2', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(2) } } + { excelCell: { value: 'f2_2', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(1) } }, + { excelCell: { value: 'f3_2', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(2) } } ], [ { excelCell: { value: null }, gridCell: { value: undefined, rowType: 'groupFooter', data: ds[1], column: dataGrid.columnOption(1) } }, - { excelCell: { value: 'Count: 1', alignment: alignLeftWrap, font: { bold: true } }, gridCell: { rowType: 'groupFooter', data: ds[1], column: dataGrid.columnOption(2), value: 1, totalSummaryItemName: 'GroupItems 1' } } + { excelCell: { value: 'Count: 1', alignment: alignLeftTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'groupFooter', data: ds[1], column: dataGrid.columnOption(2), value: 1, totalSummaryItemName: 'GroupItems 1' } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells, { selectedRowsOnly: true })).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells, { selectedRowsOnly: true })).then((cellRange) => { helper.checkRowAndColumnCount({ row: 3, column: 2 }, { row: 3, column: 2 }, topLeft); helper.checkAutoFilter(autoFilterEnabled, null); helper.checkFont(expectedCells); @@ -3800,7 +3657,7 @@ const moduleConfig = { helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0, 1, 1], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 3, column: 2 }, topLeft); + helper.checkCellRange(cellRange, { row: 3, column: 2 }, topLeft); done(); }); }); @@ -3824,22 +3681,22 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: 'f1: f1_1', alignment: alignLeftNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 0, value: ds[0].f1, column: dataGrid.columnOption(0) } } + { excelCell: { value: 'f1: f1_1', alignment: alignLeftTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 0, value: ds[0].f1, column: dataGrid.columnOption(0) } } ], [ - { excelCell: { value: 'f2: f1_2', alignment: alignLeftNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 1, value: ds[0].f2, column: dataGrid.columnOption(1) } } + { excelCell: { value: 'f2: f1_2', alignment: alignLeftTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 1, value: ds[0].f2, column: dataGrid.columnOption(1) } } ], [ - { excelCell: { value: 'f3_1', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } } + { excelCell: { value: 'f3_1', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } } ], [ - { excelCell: { value: 'f1: f1_2', alignment: alignLeftNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 0, value: ds[1].f1, column: dataGrid.columnOption(0) } } + { excelCell: { value: 'f1: f1_2', alignment: alignLeftTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 0, value: ds[1].f1, column: dataGrid.columnOption(0) } } ], [ - { excelCell: { value: 'f2: f2_2', alignment: alignLeftNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 1, value: ds[1].f2, column: dataGrid.columnOption(1) } } + { excelCell: { value: 'f2: f2_2', alignment: alignLeftTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 1, value: ds[1].f2, column: dataGrid.columnOption(1) } } ], [ - { excelCell: { value: 'f3_2', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(2) } } + { excelCell: { value: 'f3_2', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(2) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 6, column: 1 }, { row: 6, column: 1 }, topLeft); helper.checkAutoFilter(autoFilterEnabled, null); helper.checkFont(expectedCells); @@ -3847,7 +3704,7 @@ const moduleConfig = { helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0, 1, 2, 0, 1, 2], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 6, column: 1 }, topLeft); + helper.checkCellRange(cellRange, { row: 6, column: 1 }, topLeft); done(); }); }); @@ -3873,20 +3730,20 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: 'f1: f1_1 (Max of f3 is f3_2, Count: 2)', alignment: alignLeftNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(0), value: ds[0].f1, groupSummaryItems: [{ 'name': 'GroupItems 1', value: 'f3_2' }, { 'name': 'GroupItems 2', value: 2 }] } } + { excelCell: { value: 'f1: f1_1 (Max of f3 is f3_2, Count: 2)', alignment: alignLeftTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(0), value: ds[0].f1, groupSummaryItems: [{ 'name': 'GroupItems 1', value: 'f3_2' }, { 'name': 'GroupItems 2', value: 2 }] } } ], [ - { excelCell: { value: 'f2: f1_2 (Max of f3 is f3_1, Count: 1)', alignment: alignLeftNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 1, column: dataGrid.columnOption(1), value: ds[0].f2, groupSummaryItems: [{ 'name': 'GroupItems 1', value: 'f3_1' }, { 'name': 'GroupItems 2', value: 1 }] } } + { excelCell: { value: 'f2: f1_2 (Max of f3 is f3_1, Count: 1)', alignment: alignLeftTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 1, column: dataGrid.columnOption(1), value: ds[0].f2, groupSummaryItems: [{ 'name': 'GroupItems 1', value: 'f3_1' }, { 'name': 'GroupItems 2', value: 1 }] } } ], [ - { excelCell: { value: 'f3_1', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } } + { excelCell: { value: 'f3_1', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } } ], [ - { excelCell: { value: 'f2: f2_2 (Max of f3 is f3_2, Count: 1)', alignment: alignLeftNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 1, column: dataGrid.columnOption(1), value: ds[1].f2, groupSummaryItems: [{ 'name': 'GroupItems 1', value: 'f3_2' }, { 'name': 'GroupItems 2', value: 1 }] } } + { excelCell: { value: 'f2: f2_2 (Max of f3 is f3_2, Count: 1)', alignment: alignLeftTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 1, column: dataGrid.columnOption(1), value: ds[1].f2, groupSummaryItems: [{ 'name': 'GroupItems 1', value: 'f3_2' }, { 'name': 'GroupItems 2', value: 1 }] } } ], [ - { excelCell: { value: 'f3_2', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(2) } } + { excelCell: { value: 'f3_2', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(2) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 5, column: 1 }, { row: 5, column: 1 }, topLeft); helper.checkAutoFilter(autoFilterEnabled, null); helper.checkFont(expectedCells); @@ -3894,7 +3751,7 @@ const moduleConfig = { helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0, 1, 2, 1, 2], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 5, column: 1 }, topLeft); + helper.checkCellRange(cellRange, { row: 5, column: 1 }, topLeft); done(); }); }); @@ -3921,32 +3778,32 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: 'f1: f1_1', alignment: alignLeftNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 0, value: ds[0].f1, column: dataGrid.columnOption(0) } } + { excelCell: { value: 'f1: f1_1', alignment: alignLeftTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 0, value: ds[0].f1, column: dataGrid.columnOption(0) } } ], [ - { excelCell: { value: 'f2: f1_2', alignment: alignLeftNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 1, value: ds[0].f2, column: dataGrid.columnOption(1) } } + { excelCell: { value: 'f2: f1_2', alignment: alignLeftTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 1, value: ds[0].f2, column: dataGrid.columnOption(1) } } ], [ - { excelCell: { value: 'f3_1', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } } + { excelCell: { value: 'f3_1', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } } ], [ - { excelCell: { value: 'Max: f3_1', alignment: alignLeftWrap, font: { bold: true } }, gridCell: { rowType: 'groupFooter', value: ds[0].f3, column: dataGrid.columnOption(2) } } + { excelCell: { value: 'Max: f3_1', alignment: alignLeftTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'groupFooter', value: ds[0].f3, column: dataGrid.columnOption(2) } } ], [ - { excelCell: { value: 'Count: 1', alignment: alignLeftWrap, font: { bold: true } }, gridCell: { rowType: 'groupFooter', value: 1, column: dataGrid.columnOption(2) } } + { excelCell: { value: 'Count: 1', alignment: alignLeftTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'groupFooter', value: 1, column: dataGrid.columnOption(2) } } ], [ - { excelCell: { value: 'f2: f2_2', alignment: alignLeftNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 1, value: ds[1].f2, column: dataGrid.columnOption(1) } } + { excelCell: { value: 'f2: f2_2', alignment: alignLeftTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 1, value: ds[1].f2, column: dataGrid.columnOption(1) } } ], [ - { excelCell: { value: 'f3_2', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(2) } } + { excelCell: { value: 'f3_2', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(2) } } ], [ - { excelCell: { value: 'Max: f3_2', alignment: alignLeftWrap, font: { bold: true } }, gridCell: { rowType: 'groupFooter', column: dataGrid.columnOption(2), value: ds[1].f3 } } + { excelCell: { value: 'Max: f3_2', alignment: alignLeftTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'groupFooter', column: dataGrid.columnOption(2), value: ds[1].f3 } } ], [ - { excelCell: { value: 'Count: 1', alignment: alignLeftWrap, font: { bold: true } }, gridCell: { rowType: 'groupFooter', column: dataGrid.columnOption(2), value: 1 } } + { excelCell: { value: 'Count: 1', alignment: alignLeftTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'groupFooter', column: dataGrid.columnOption(2), value: 1 } } ], [ - { excelCell: { value: 'Max: f3_2', alignment: alignLeftWrap, font: { bold: true } }, gridCell: { rowType: 'groupFooter', column: dataGrid.columnOption(2), value: ds[1].f3 } } + { excelCell: { value: 'Max: f3_2', alignment: alignLeftTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'groupFooter', column: dataGrid.columnOption(2), value: ds[1].f3 } } ], [ - { excelCell: { value: 'Count: 2', alignment: alignLeftWrap, font: { bold: true } }, gridCell: { rowType: 'groupFooter', value: 2, column: dataGrid.columnOption(2) } } + { excelCell: { value: 'Count: 2', alignment: alignLeftTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'groupFooter', value: 2, column: dataGrid.columnOption(2) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 11, column: 1 }, { row: 11, column: 1 }, topLeft); helper.checkAutoFilter(autoFilterEnabled, null); helper.checkFont(expectedCells); @@ -3954,7 +3811,7 @@ const moduleConfig = { helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0, 1, 2, 2, 2, 1, 2, 2, 2, 2, 2], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 11, column: 1 }, topLeft); + helper.checkCellRange(cellRange, { row: 11, column: 1 }, topLeft); done(); }); }); @@ -3984,43 +3841,43 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: 'f1: f1_1', alignment: alignLeftNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(0), value: ds[0].f1 } }, + { excelCell: { value: 'f1: f1_1', alignment: alignLeftTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(0), value: ds[0].f1 } }, { excelCell: { value: null }, gridCell: { value: undefined, rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(3) } } ], [ - { excelCell: { value: 'f2: f1_2', alignment: alignLeftNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 1, column: dataGrid.columnOption(1), value: ds[0].f2 } }, + { excelCell: { value: 'f2: f1_2', alignment: alignLeftTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 1, column: dataGrid.columnOption(1), value: ds[0].f2 } }, { excelCell: { value: null }, gridCell: { value: undefined, rowType: 'group', groupIndex: 1, column: dataGrid.columnOption(3) } } ], [ - { excelCell: { value: 'f3_1', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } }, - { excelCell: { value: 'f4_1', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(3) } } + { excelCell: { value: 'f3_1', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } }, + { excelCell: { value: 'f4_1', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(3) } } ], [ - { excelCell: { value: 'Max: f3_1', alignment: alignLeftWrap, font: { bold: true } }, gridCell: { rowType: 'groupFooter', column: dataGrid.columnOption(2), value: ds[0].f3 } }, - { excelCell: { value: 'Max: f4_1', alignment: alignLeftWrap, font: { bold: true } }, gridCell: { rowType: 'groupFooter', column: dataGrid.columnOption(3), value: ds[0].f4 } } + { excelCell: { value: 'Max: f3_1', alignment: alignLeftTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'groupFooter', column: dataGrid.columnOption(2), value: ds[0].f3 } }, + { excelCell: { value: 'Max: f4_1', alignment: alignLeftTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'groupFooter', column: dataGrid.columnOption(3), value: ds[0].f4 } } ], [ - { excelCell: { value: 'Count: 1', alignment: alignLeftWrap, font: { bold: true } }, gridCell: { rowType: 'groupFooter', column: dataGrid.columnOption(2), value: 1 } }, - { excelCell: { value: 'Count: 1', alignment: alignLeftWrap, font: { bold: true } }, gridCell: { rowType: 'groupFooter', column: dataGrid.columnOption(3), value: 1 } } + { excelCell: { value: 'Count: 1', alignment: alignLeftTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'groupFooter', column: dataGrid.columnOption(2), value: 1 } }, + { excelCell: { value: 'Count: 1', alignment: alignLeftTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'groupFooter', column: dataGrid.columnOption(3), value: 1 } } ], [ - { excelCell: { value: 'f2: f2_2', alignment: alignLeftNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 1, column: dataGrid.columnOption(1), value: ds[1].f2 } }, + { excelCell: { value: 'f2: f2_2', alignment: alignLeftTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 1, column: dataGrid.columnOption(1), value: ds[1].f2 } }, { excelCell: { value: null }, gridCell: { value: undefined, rowType: 'group', groupIndex: 1, column: dataGrid.columnOption(3) } } ], [ - { excelCell: { value: 'f3_2', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(2) } }, - { excelCell: { value: 'f4_2', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(3) } } + { excelCell: { value: 'f3_2', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(2) } }, + { excelCell: { value: 'f4_2', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(3) } } ], [ - { excelCell: { value: 'Max: f3_2', alignment: alignLeftWrap, font: { bold: true } }, gridCell: { rowType: 'groupFooter', column: dataGrid.columnOption(2), value: ds[1].f3 } }, - { excelCell: { value: 'Max: f4_2', alignment: alignLeftWrap, font: { bold: true } }, gridCell: { rowType: 'groupFooter', column: dataGrid.columnOption(3), value: ds[1].f4 } } + { excelCell: { value: 'Max: f3_2', alignment: alignLeftTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'groupFooter', column: dataGrid.columnOption(2), value: ds[1].f3 } }, + { excelCell: { value: 'Max: f4_2', alignment: alignLeftTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'groupFooter', column: dataGrid.columnOption(3), value: ds[1].f4 } } ], [ - { excelCell: { value: 'Count: 1', alignment: alignLeftWrap, font: { bold: true } }, gridCell: { rowType: 'groupFooter', column: dataGrid.columnOption(2), value: 1 } }, - { excelCell: { value: 'Count: 1', alignment: alignLeftWrap, font: { bold: true } }, gridCell: { rowType: 'groupFooter', column: dataGrid.columnOption(3), value: 1 } } + { excelCell: { value: 'Count: 1', alignment: alignLeftTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'groupFooter', column: dataGrid.columnOption(2), value: 1 } }, + { excelCell: { value: 'Count: 1', alignment: alignLeftTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'groupFooter', column: dataGrid.columnOption(3), value: 1 } } ], [ - { excelCell: { value: 'Max: f3_2', alignment: alignLeftWrap, font: { bold: true } }, gridCell: { rowType: 'groupFooter', column: dataGrid.columnOption(2), value: ds[1].f3 } }, - { excelCell: { value: 'Max: f4_2', alignment: alignLeftWrap, font: { bold: true } }, gridCell: { rowType: 'groupFooter', column: dataGrid.columnOption(3), value: ds[1].f4 } } + { excelCell: { value: 'Max: f3_2', alignment: alignLeftTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'groupFooter', column: dataGrid.columnOption(2), value: ds[1].f3 } }, + { excelCell: { value: 'Max: f4_2', alignment: alignLeftTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'groupFooter', column: dataGrid.columnOption(3), value: ds[1].f4 } } ], [ - { excelCell: { value: 'Count: 2', alignment: alignLeftWrap, font: { bold: true } }, gridCell: { rowType: 'groupFooter', column: dataGrid.columnOption(2), value: 2 } }, - { excelCell: { value: 'Count: 2', alignment: alignLeftWrap, font: { bold: true } }, gridCell: { rowType: 'groupFooter', column: dataGrid.columnOption(3), value: 2 } } + { excelCell: { value: 'Count: 2', alignment: alignLeftTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'groupFooter', column: dataGrid.columnOption(2), value: 2 } }, + { excelCell: { value: 'Count: 2', alignment: alignLeftTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'groupFooter', column: dataGrid.columnOption(3), value: 2 } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 11, column: 2 }, { row: 11, column: 2 }, topLeft); helper.checkAutoFilter(autoFilterEnabled, null); helper.checkFont(expectedCells); @@ -4028,7 +3885,7 @@ const moduleConfig = { helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0, 1, 2, 2, 2, 1, 2, 2, 2, 2, 2], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 11, column: 2 }, topLeft); + helper.checkCellRange(cellRange, { row: 11, column: 2 }, topLeft); done(); }); }); @@ -4059,30 +3916,30 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: 'f1: f1_1', alignment: alignLeftNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(0), value: ds[0].f1 } }, - { excelCell: { value: 'Max: f4_2\nCount: 2', alignment: alignLeftWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(3), groupSummaryItems: [{ 'name': 'GroupItems 1', value: 'f4_2' }, { 'name': 'GroupItems 2', value: 2 }] } }, - { excelCell: { value: 'Max: f5_2\nCount: 2', alignment: alignLeftWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(4), groupSummaryItems: [{ 'name': 'GroupItems 3', value: 'f5_2' }, { 'name': 'GroupItems 4', value: 2 }] } } + { excelCell: { value: 'f1: f1_1', alignment: alignLeftTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(0), value: ds[0].f1 } }, + { excelCell: { value: 'Max: f4_2\nCount: 2', alignment: alignLeftTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(3), groupSummaryItems: [{ 'name': 'GroupItems 1', value: 'f4_2' }, { 'name': 'GroupItems 2', value: 2 }] } }, + { excelCell: { value: 'Max: f5_2\nCount: 2', alignment: alignLeftTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(4), groupSummaryItems: [{ 'name': 'GroupItems 3', value: 'f5_2' }, { 'name': 'GroupItems 4', value: 2 }] } } ], [ - { excelCell: { value: 'f2: f1_2', alignment: alignLeftNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 1, column: dataGrid.columnOption(1), value: ds[0].f2 } }, - { excelCell: { value: 'Max: f4_1\nCount: 1', alignment: alignLeftWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 1, column: dataGrid.columnOption(3), groupSummaryItems: [{ 'name': 'GroupItems 1', value: 'f4_1' }, { 'name': 'GroupItems 2', value: 1 }] } }, - { excelCell: { value: 'Max: f5_1\nCount: 1', alignment: alignLeftWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 1, column: dataGrid.columnOption(4), groupSummaryItems: [{ 'name': 'GroupItems 3', value: 'f5_1' }, { 'name': 'GroupItems 4', value: 1 }] } } + { excelCell: { value: 'f2: f1_2', alignment: alignLeftTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 1, column: dataGrid.columnOption(1), value: ds[0].f2 } }, + { excelCell: { value: 'Max: f4_1\nCount: 1', alignment: alignLeftTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 1, column: dataGrid.columnOption(3), groupSummaryItems: [{ 'name': 'GroupItems 1', value: 'f4_1' }, { 'name': 'GroupItems 2', value: 1 }] } }, + { excelCell: { value: 'Max: f5_1\nCount: 1', alignment: alignLeftTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 1, column: dataGrid.columnOption(4), groupSummaryItems: [{ 'name': 'GroupItems 3', value: 'f5_1' }, { 'name': 'GroupItems 4', value: 1 }] } } ], [ - { excelCell: { value: 'f3_1', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } }, - { excelCell: { value: 'f4_1', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(3) } }, - { excelCell: { value: 'f5_1', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(4) } } + { excelCell: { value: 'f3_1', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } }, + { excelCell: { value: 'f4_1', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(3) } }, + { excelCell: { value: 'f5_1', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(4) } } ], [ - { excelCell: { value: 'f2: f2_2', alignment: alignLeftNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 1, column: dataGrid.columnOption(1), value: ds[1].f2 } }, - { excelCell: { value: 'Max: f4_2\nCount: 1', alignment: alignLeftWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 1, column: dataGrid.columnOption(3), groupSummaryItems: [{ 'name': 'GroupItems 1', value: 'f4_2' }, { 'name': 'GroupItems 2', value: 1 }] } }, - { excelCell: { value: 'Max: f5_2\nCount: 1', alignment: alignLeftWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 1, column: dataGrid.columnOption(4), groupSummaryItems: [{ 'name': 'GroupItems 3', value: 'f5_2' }, { 'name': 'GroupItems 4', value: 1 }] } } + { excelCell: { value: 'f2: f2_2', alignment: alignLeftTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 1, column: dataGrid.columnOption(1), value: ds[1].f2 } }, + { excelCell: { value: 'Max: f4_2\nCount: 1', alignment: alignLeftTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 1, column: dataGrid.columnOption(3), groupSummaryItems: [{ 'name': 'GroupItems 1', value: 'f4_2' }, { 'name': 'GroupItems 2', value: 1 }] } }, + { excelCell: { value: 'Max: f5_2\nCount: 1', alignment: alignLeftTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 1, column: dataGrid.columnOption(4), groupSummaryItems: [{ 'name': 'GroupItems 3', value: 'f5_2' }, { 'name': 'GroupItems 4', value: 1 }] } } ], [ - { excelCell: { value: 'f3_2', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(2) } }, - { excelCell: { value: 'f4_2', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(3) } }, - { excelCell: { value: 'f5_2', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(4) } } + { excelCell: { value: 'f3_2', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(2) } }, + { excelCell: { value: 'f4_2', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(3) } }, + { excelCell: { value: 'f5_2', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(4) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 5, column: 3 }, { row: 5, column: 3 }, topLeft); helper.checkAutoFilter(autoFilterEnabled, null); helper.checkFont(expectedCells); @@ -4090,7 +3947,7 @@ const moduleConfig = { helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0, 1, 2, 1, 2], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 5, column: 3 }, topLeft); + helper.checkCellRange(cellRange, { row: 5, column: 3 }, topLeft); done(); }); }); @@ -4121,30 +3978,30 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: 'f1: f1_1 (Max of f4 is f4_2, Count: 2, Max of f5 is f5_2, Count: 2)', alignment: alignLeftNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(0), value: ds[0].f1, groupSummaryItems: [{ 'name': 'GroupItems 1', value: 'f4_2' }, { 'name': 'GroupItems 2', value: 2 }, { 'name': 'GroupItems 3', value: 'f5_2' }, { 'name': 'GroupItems 4', value: 2 }] } }, + { excelCell: { value: 'f1: f1_1 (Max of f4 is f4_2, Count: 2, Max of f5 is f5_2, Count: 2)', alignment: alignLeftTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(0), value: ds[0].f1, groupSummaryItems: [{ 'name': 'GroupItems 1', value: 'f4_2' }, { 'name': 'GroupItems 2', value: 2 }, { 'name': 'GroupItems 3', value: 'f5_2' }, { 'name': 'GroupItems 4', value: 2 }] } }, { excelCell: { value: null }, gridCell: { value: undefined, rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(3) } }, { excelCell: { value: null }, gridCell: { value: undefined, rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(4) } } ], [ - { excelCell: { value: 'f2: f1_2 (Max of f4 is f4_1, Count: 1, Max of f5 is f5_1, Count: 1)', alignment: alignLeftNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 1, column: dataGrid.columnOption(1), value: ds[0].f2, groupSummaryItems: [{ 'name': 'GroupItems 1', value: 'f4_1' }, { 'name': 'GroupItems 2', value: 1 }, { 'name': 'GroupItems 3', value: 'f5_1' }, { 'name': 'GroupItems 4', value: 1 }] } }, + { excelCell: { value: 'f2: f1_2 (Max of f4 is f4_1, Count: 1, Max of f5 is f5_1, Count: 1)', alignment: alignLeftTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 1, column: dataGrid.columnOption(1), value: ds[0].f2, groupSummaryItems: [{ 'name': 'GroupItems 1', value: 'f4_1' }, { 'name': 'GroupItems 2', value: 1 }, { 'name': 'GroupItems 3', value: 'f5_1' }, { 'name': 'GroupItems 4', value: 1 }] } }, { excelCell: { value: null }, gridCell: { value: undefined, rowType: 'group', groupIndex: 1, column: dataGrid.columnOption(3) } }, { excelCell: { value: null }, gridCell: { value: undefined, rowType: 'group', groupIndex: 1, column: dataGrid.columnOption(4) } } ], [ - { excelCell: { value: 'f3_1', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } }, - { excelCell: { value: 'f4_1', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(3) } }, - { excelCell: { value: 'f5_1', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(4) } } + { excelCell: { value: 'f3_1', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } }, + { excelCell: { value: 'f4_1', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(3) } }, + { excelCell: { value: 'f5_1', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(4) } } ], [ - { excelCell: { value: 'f2: f2_2 (Max of f4 is f4_2, Count: 1, Max of f5 is f5_2, Count: 1)', alignment: alignLeftNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 1, column: dataGrid.columnOption(1), value: ds[1].f2, groupSummaryItems: [{ 'name': 'GroupItems 1', value: 'f4_2' }, { 'name': 'GroupItems 2', value: 1 }, { 'name': 'GroupItems 3', value: 'f5_2' }, { 'name': 'GroupItems 4', value: 1 }] } }, + { excelCell: { value: 'f2: f2_2 (Max of f4 is f4_2, Count: 1, Max of f5 is f5_2, Count: 1)', alignment: alignLeftTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 1, column: dataGrid.columnOption(1), value: ds[1].f2, groupSummaryItems: [{ 'name': 'GroupItems 1', value: 'f4_2' }, { 'name': 'GroupItems 2', value: 1 }, { 'name': 'GroupItems 3', value: 'f5_2' }, { 'name': 'GroupItems 4', value: 1 }] } }, { excelCell: { value: null }, gridCell: { value: undefined, rowType: 'group', groupIndex: 1, column: dataGrid.columnOption(3) } }, { excelCell: { value: null }, gridCell: { value: undefined, rowType: 'group', groupIndex: 1, column: dataGrid.columnOption(4) } } ], [ - { excelCell: { value: 'f3_2', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(2) } }, - { excelCell: { value: 'f4_2', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(3) } }, - { excelCell: { value: 'f5_2', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(4) } } + { excelCell: { value: 'f3_2', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(2) } }, + { excelCell: { value: 'f4_2', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(3) } }, + { excelCell: { value: 'f5_2', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(4) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 5, column: 3 }, { row: 5, column: 3 }, topLeft); helper.checkAutoFilter(autoFilterEnabled, null); helper.checkFont(expectedCells); @@ -4152,7 +4009,7 @@ const moduleConfig = { helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0, 1, 2, 1, 2], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 5, column: 3 }, topLeft); + helper.checkCellRange(cellRange, { row: 5, column: 3 }, topLeft); done(); }); }); @@ -4178,22 +4035,22 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: 'f4: f4_1', alignment: alignLeftNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(3), value: ds[0].f4 } }, + { excelCell: { value: 'f4: f4_1', alignment: alignLeftTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(3), value: ds[0].f4 } }, { excelCell: { value: null }, gridCell: { value: undefined, rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(1) } }, { excelCell: { value: null }, gridCell: { value: undefined, rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(2) } } ], [ - { excelCell: { value: 'f1_1', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, - { excelCell: { value: 'f2_1', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } }, - { excelCell: { value: 'f3_1', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } } + { excelCell: { value: 'f1_1', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, + { excelCell: { value: 'f2_1', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } }, + { excelCell: { value: 'f3_1', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } } ], [ - { excelCell: { value: 'f1_2', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(0) } }, - { excelCell: { value: 'f2_2', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(1) } }, - { excelCell: { value: 'f3_2', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(2) } } + { excelCell: { value: 'f1_2', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(0) } }, + { excelCell: { value: 'f2_2', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(1) } }, + { excelCell: { value: 'f3_2', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(2) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 3, column: 3 }, { row: 3, column: 3 }, topLeft); helper.checkAutoFilter(autoFilterEnabled, null); helper.checkColumnWidths([excelColumnWidthFromColumn100Pixels, excelColumnWidthFromColumn150Pixels, excelColumnWidthFromColumn250Pixels, undefined], topLeft.column); @@ -4202,7 +4059,7 @@ const moduleConfig = { helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0, 1, 1], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 3, column: 3 }, topLeft); + helper.checkCellRange(cellRange, { row: 3, column: 3 }, topLeft); done(); }); }); @@ -4228,22 +4085,22 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: 'f4: f4_1', alignment: alignLeftNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(3), value: ds[0].f4 } }, + { excelCell: { value: 'f4: f4_1', alignment: alignLeftTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(3), value: ds[0].f4 } }, { excelCell: { value: null }, gridCell: { value: undefined, rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(1) } }, { excelCell: { value: null }, gridCell: { value: undefined, rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(2) } } ], [ - { excelCell: { value: 'f1_1', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, - { excelCell: { value: 'f2_1', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } }, - { excelCell: { value: 'f3_1', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } } + { excelCell: { value: 'f1_1', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, + { excelCell: { value: 'f2_1', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } }, + { excelCell: { value: 'f3_1', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } } ], [ - { excelCell: { value: 'f1_2', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(0) } }, - { excelCell: { value: 'f2_2', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(1) } }, - { excelCell: { value: 'f3_2', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(2) } } + { excelCell: { value: 'f1_2', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(0) } }, + { excelCell: { value: 'f2_2', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(1) } }, + { excelCell: { value: 'f3_2', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(2) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 3, column: 3 }, { row: 3, column: 3 }, topLeft); helper.checkAutoFilter(autoFilterEnabled, null); helper.checkColumnWidths([excelColumnWidthFromColumn100Pixels, excelColumnWidthFromColumn150Pixels, excelColumnWidthFromColumn250Pixels, undefined], topLeft.column); @@ -4252,7 +4109,7 @@ const moduleConfig = { helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0, 1, 1], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 3, column: 3 }, topLeft); + helper.checkCellRange(cellRange, { row: 3, column: 3 }, topLeft); done(); }); }); @@ -4278,19 +4135,19 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: 'f4: f4_1', alignment: alignLeftNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(3), value: ds[0].f4 } }, + { excelCell: { value: 'f4: f4_1', alignment: alignLeftTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(3), value: ds[0].f4 } }, { excelCell: { value: null }, gridCell: { value: undefined, rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(2) } } ], [ - { excelCell: { value: 'f2_1', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } }, - { excelCell: { value: 'f3_1', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } } + { excelCell: { value: 'f2_1', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } }, + { excelCell: { value: 'f3_1', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } } ], [ - { excelCell: { value: 'f2_2', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(1) } }, - { excelCell: { value: 'f3_2', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(2) } } + { excelCell: { value: 'f2_2', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(1) } }, + { excelCell: { value: 'f3_2', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(2) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 3, column: 2 }, { row: 3, column: 2 }, topLeft); helper.checkAutoFilter(autoFilterEnabled, null); helper.checkColumnWidths([excelColumnWidthFromColumn200Pixels, excelColumnWidthFromColumn300Pixels, undefined], topLeft.column); @@ -4299,7 +4156,7 @@ const moduleConfig = { helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0, 1, 1], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 3, column: 2 }, topLeft); + helper.checkCellRange(cellRange, { row: 3, column: 2 }, topLeft); done(); }); }); @@ -4325,19 +4182,19 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: 'f4: f4_1', alignment: alignLeftNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(3), value: ds[0].f4 } }, + { excelCell: { value: 'f4: f4_1', alignment: alignLeftTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(3), value: ds[0].f4 } }, { excelCell: { value: null }, gridCell: { value: undefined, rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(2) } } ], [ - { excelCell: { value: 'f1_1', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, - { excelCell: { value: 'f3_1', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } } + { excelCell: { value: 'f1_1', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, + { excelCell: { value: 'f3_1', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } } ], [ - { excelCell: { value: 'f1_2', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(0) } }, - { excelCell: { value: 'f3_2', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(2) } } + { excelCell: { value: 'f1_2', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(0) } }, + { excelCell: { value: 'f3_2', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(2) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 3, column: 2 }, { row: 3, column: 2 }, topLeft); helper.checkAutoFilter(autoFilterEnabled, null); helper.checkColumnWidths([excelColumnWidthFromColumn200Pixels, excelColumnWidthFromColumn300Pixels, undefined], topLeft.column); @@ -4346,7 +4203,7 @@ const moduleConfig = { helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0, 1, 1], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 3, column: 2 }, topLeft); + helper.checkCellRange(cellRange, { row: 3, column: 2 }, topLeft); done(); }); }); @@ -4372,19 +4229,19 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: 'f4: f4_1', alignment: alignLeftNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(3), value: ds[0].f4 } }, + { excelCell: { value: 'f4: f4_1', alignment: alignLeftTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(3), value: ds[0].f4 } }, { excelCell: { value: null }, gridCell: { value: undefined, rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(1) } } ], [ - { excelCell: { value: 'f1_1', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, - { excelCell: { value: 'f2_1', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } } + { excelCell: { value: 'f1_1', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, + { excelCell: { value: 'f2_1', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } } ], [ - { excelCell: { value: 'f1_2', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(0) } }, - { excelCell: { value: 'f2_2', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(1) } } + { excelCell: { value: 'f1_2', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(0) } }, + { excelCell: { value: 'f2_2', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(1) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 3, column: 2 }, { row: 3, column: 2 }, topLeft); helper.checkAutoFilter(autoFilterEnabled, null); helper.checkColumnWidths([excelColumnWidthFromColumn200Pixels, excelColumnWidthFromColumn300Pixels, undefined], topLeft.column); @@ -4393,7 +4250,7 @@ const moduleConfig = { helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0, 1, 1], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 3, column: 2 }, topLeft); + helper.checkCellRange(cellRange, { row: 3, column: 2 }, topLeft); done(); }); }); @@ -4419,22 +4276,22 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: 'f4: f4_1', alignment: alignLeftNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(3), value: ds[0].f4 } }, + { excelCell: { value: 'f4: f4_1', alignment: alignLeftTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(3), value: ds[0].f4 } }, { excelCell: { value: null }, gridCell: { value: undefined, rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(0) } }, { excelCell: { value: null }, gridCell: { value: undefined, rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(1) } } ], [ - { excelCell: { value: 'f3_1', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } }, - { excelCell: { value: 'f1_1', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, - { excelCell: { value: 'f2_1', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } } + { excelCell: { value: 'f3_1', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } }, + { excelCell: { value: 'f1_1', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, + { excelCell: { value: 'f2_1', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } } ], [ - { excelCell: { value: 'f3_2', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(2) } }, - { excelCell: { value: 'f1_2', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(0) } }, - { excelCell: { value: 'f2_2', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(1) } } + { excelCell: { value: 'f3_2', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(2) } }, + { excelCell: { value: 'f1_2', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(0) } }, + { excelCell: { value: 'f2_2', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(1) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 3, column: 3 }, { row: 3, column: 3 }, topLeft); helper.checkAutoFilter(autoFilterEnabled, null); helper.checkColumnWidths([excelColumnWidthFromColumn300Pixels, excelColumnWidthFromColumn200Pixels, excelColumnWidthFromColumn300Pixels, undefined], topLeft.column); @@ -4443,7 +4300,7 @@ const moduleConfig = { helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0, 1, 1], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 3, column: 3 }, topLeft); + helper.checkCellRange(cellRange, { row: 3, column: 3 }, topLeft); done(); }); }); @@ -4473,26 +4330,26 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: 'f4: f4_1', alignment: alignLeftNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(3), value: ds[0].f4 } }, + { excelCell: { value: 'f4: f4_1', alignment: alignLeftTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(3), value: ds[0].f4 } }, { excelCell: { value: null }, gridCell: { value: undefined, rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(1) } }, { excelCell: { value: null }, gridCell: { value: undefined, rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(2) } } ], [ - { excelCell: { value: 'f1_1', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, - { excelCell: { value: 'f2_1', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } }, - { excelCell: { value: 'f3_1', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } } + { excelCell: { value: 'f1_1', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, + { excelCell: { value: 'f2_1', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } }, + { excelCell: { value: 'f3_1', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } } ], [ - { excelCell: { value: 'f1_2', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(0) } }, - { excelCell: { value: 'f2_2', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(1) } }, - { excelCell: { value: 'f3_2', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(2) } } + { excelCell: { value: 'f1_2', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(0) } }, + { excelCell: { value: 'f2_2', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(1) } }, + { excelCell: { value: 'f3_2', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(2) } } ], [ { excelCell: { value: null }, gridCell: { value: undefined, rowType: 'groupFooter', column: dataGrid.columnOption(0) } }, { excelCell: { value: null }, gridCell: { value: undefined, rowType: 'groupFooter', column: dataGrid.columnOption(1) } }, - { excelCell: { value: 'Max: f3_2', alignment: alignLeftWrap, font: { bold: true } }, gridCell: { rowType: 'groupFooter', column: dataGrid.columnOption(2), value: ds[1].f3 } } + { excelCell: { value: 'Max: f3_2', alignment: alignLeftTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'groupFooter', column: dataGrid.columnOption(2), value: ds[1].f3 } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 4, column: 3 }, { row: 4, column: 3 }, topLeft); helper.checkAutoFilter(autoFilterEnabled, null); helper.checkFont(expectedCells); @@ -4500,7 +4357,7 @@ const moduleConfig = { helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0, 1, 1], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 4, column: 3 }, topLeft); + helper.checkCellRange(cellRange, { row: 4, column: 3 }, topLeft); done(); }); }); @@ -4530,22 +4387,22 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: 'f4: f4_1', alignment: alignLeftNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(3), value: ds[0].f4 } }, + { excelCell: { value: 'f4: f4_1', alignment: alignLeftTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(3), value: ds[0].f4 } }, { excelCell: { value: null }, gridCell: { value: undefined, rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(1) } }, - { excelCell: { value: 'Max: f3_2', alignment: alignLeftWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(2), groupSummaryItems: [{ 'name': 'GroupItems 1', value: 'f3_2' }] } } + { excelCell: { value: 'Max: f3_2', alignment: alignLeftTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(2), groupSummaryItems: [{ 'name': 'GroupItems 1', value: 'f3_2' }] } } ], [ - { excelCell: { value: 'f1_1', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, - { excelCell: { value: 'f2_1', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } }, - { excelCell: { value: 'f3_1', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } } + { excelCell: { value: 'f1_1', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, + { excelCell: { value: 'f2_1', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } }, + { excelCell: { value: 'f3_1', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } } ], [ - { excelCell: { value: 'f1_2', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(0) } }, - { excelCell: { value: 'f2_2', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(1) } }, - { excelCell: { value: 'f3_2', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(2) } } + { excelCell: { value: 'f1_2', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(0) } }, + { excelCell: { value: 'f2_2', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(1) } }, + { excelCell: { value: 'f3_2', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(2) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 3, column: 3 }, { row: 3, column: 3 }, topLeft); helper.checkAutoFilter(autoFilterEnabled, null); helper.checkFont(expectedCells); @@ -4553,7 +4410,7 @@ const moduleConfig = { helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0, 1, 1], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 3, column: 3 }, topLeft); + helper.checkCellRange(cellRange, { row: 3, column: 3 }, topLeft); done(); }); }); @@ -4583,22 +4440,22 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: 'f4: f4_1', alignment: alignLeftNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(3), value: ds[0].f4 } }, + { excelCell: { value: 'f4: f4_1', alignment: alignLeftTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(3), value: ds[0].f4 } }, { excelCell: { value: null }, gridCell: { value: undefined, rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(2) } } ], [ - { excelCell: { value: 'f2_1', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } }, - { excelCell: { value: 'f3_1', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } } + { excelCell: { value: 'f2_1', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } }, + { excelCell: { value: 'f3_1', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } } ], [ - { excelCell: { value: 'f2_2', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(1) } }, - { excelCell: { value: 'f3_2', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(2) } } + { excelCell: { value: 'f2_2', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(1) } }, + { excelCell: { value: 'f3_2', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(2) } } ], [ { excelCell: { value: null }, gridCell: { value: undefined, rowType: 'groupFooter', column: dataGrid.columnOption(1) } }, - { excelCell: { value: 'Max: f3_2', alignment: alignLeftWrap, font: { bold: true } }, gridCell: { rowType: 'groupFooter', column: dataGrid.columnOption(2), value: ds[1].f3 } } + { excelCell: { value: 'Max: f3_2', alignment: alignLeftTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'groupFooter', column: dataGrid.columnOption(2), value: ds[1].f3 } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 4, column: 2 }, { row: 4, column: 2 }, topLeft); helper.checkAutoFilter(autoFilterEnabled, null); helper.checkFont(expectedCells); @@ -4606,7 +4463,7 @@ const moduleConfig = { helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0, 1, 1, 1], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 4, column: 2 }, topLeft); + helper.checkCellRange(cellRange, { row: 4, column: 2 }, topLeft); done(); }); }); @@ -4636,14 +4493,14 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: 'f4: f4_1', alignment: alignLeftNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(3), value: ds[0].f4 } }, + { excelCell: { value: 'f4: f4_1', alignment: alignLeftTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(3), value: ds[0].f4 } }, { excelCell: { value: null }, gridCell: { value: undefined, rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(2) } } ], [ - { excelCell: { value: 'f2_1', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } }, - { excelCell: { value: 'f3_1', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } } + { excelCell: { value: 'f2_1', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } }, + { excelCell: { value: 'f3_1', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } } ], [ - { excelCell: { value: 'f2_2', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(1) } }, - { excelCell: { value: 'f3_2', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(2) } } + { excelCell: { value: 'f2_2', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(1) } }, + { excelCell: { value: 'f3_2', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(2) } } ], [ { excelCell: { value: null }, gridCell: { value: undefined, rowType: 'groupFooter', column: dataGrid.columnOption(1) } }, { excelCell: { value: null }, gridCell: { value: undefined, rowType: 'groupFooter', column: dataGrid.columnOption(2) } } @@ -4651,7 +4508,7 @@ const moduleConfig = { helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 3, column: 2 }, { row: 4, column: 2 }, topLeft); helper.checkAutoFilter(autoFilterEnabled, null); helper.checkFont(expectedCells); @@ -4659,7 +4516,7 @@ const moduleConfig = { helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0, 1, 1, 1], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 4, column: 2 }, topLeft); + helper.checkCellRange(cellRange, { row: 4, column: 2 }, topLeft); done(); }); }); @@ -4689,19 +4546,19 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: 'f4: f4_1', alignment: alignLeftNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(3), value: ds[0].f4 } }, - { excelCell: { value: 'Max: f3_2', alignment: alignLeftWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(2), groupSummaryItems: [{ 'name': 'GroupItems 1', value: 'f3_2' }] } } + { excelCell: { value: 'f4: f4_1', alignment: alignLeftTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(3), value: ds[0].f4 } }, + { excelCell: { value: 'Max: f3_2', alignment: alignLeftTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(2), groupSummaryItems: [{ 'name': 'GroupItems 1', value: 'f3_2' }] } } ], [ - { excelCell: { value: 'f2_1', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } }, - { excelCell: { value: 'f3_1', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } } + { excelCell: { value: 'f2_1', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } }, + { excelCell: { value: 'f3_1', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } } ], [ - { excelCell: { value: 'f2_2', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(1) } }, - { excelCell: { value: 'f3_2', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(2) } } + { excelCell: { value: 'f2_2', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(1) } }, + { excelCell: { value: 'f3_2', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(2) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 3, column: 2 }, { row: 3, column: 2 }, topLeft); helper.checkAutoFilter(autoFilterEnabled, null); helper.checkFont(expectedCells); @@ -4709,7 +4566,7 @@ const moduleConfig = { helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0, 1, 1], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 3, column: 2 }, topLeft); + helper.checkCellRange(cellRange, { row: 3, column: 2 }, topLeft); done(); }); }); @@ -4739,22 +4596,22 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: 'f4: f4_1', alignment: alignLeftNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(3), value: ds[0].f4 } }, + { excelCell: { value: 'f4: f4_1', alignment: alignLeftTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(3), value: ds[0].f4 } }, { excelCell: { value: null }, gridCell: { value: undefined, rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(2) } } ], [ - { excelCell: { value: 'f1_1', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, - { excelCell: { value: 'f3_1', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } } + { excelCell: { value: 'f1_1', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, + { excelCell: { value: 'f3_1', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } } ], [ - { excelCell: { value: 'f1_2', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(0) } }, - { excelCell: { value: 'f3_2', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(2) } } + { excelCell: { value: 'f1_2', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(0) } }, + { excelCell: { value: 'f3_2', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(2) } } ], [ { excelCell: { value: null }, gridCell: { value: undefined, rowType: 'groupFooter', column: dataGrid.columnOption(0) } }, - { excelCell: { value: 'Max: f3_2', alignment: alignLeftWrap, font: { bold: true } }, gridCell: { rowType: 'groupFooter', column: dataGrid.columnOption(2), value: ds[1].f3 } } + { excelCell: { value: 'Max: f3_2', alignment: alignLeftTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'groupFooter', column: dataGrid.columnOption(2), value: ds[1].f3 } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 4, column: 2 }, { row: 4, column: 2 }, topLeft); helper.checkAutoFilter(autoFilterEnabled, null); helper.checkFont(expectedCells); @@ -4762,7 +4619,7 @@ const moduleConfig = { helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0, 1, 1, 1], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 4, column: 2 }, topLeft); + helper.checkCellRange(cellRange, { row: 4, column: 2 }, topLeft); done(); }); }); @@ -4792,19 +4649,19 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: 'f4: f4_1', alignment: alignLeftNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(3), value: ds[0].f4 } }, - { excelCell: { value: 'Max: f3_2', alignment: alignLeftWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(2), groupSummaryItems: [{ 'name': 'GroupItems 1', value: 'f3_2' }] } } + { excelCell: { value: 'f4: f4_1', alignment: alignLeftTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(3), value: ds[0].f4 } }, + { excelCell: { value: 'Max: f3_2', alignment: alignLeftTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'group', groupIndex: 0, column: dataGrid.columnOption(2), groupSummaryItems: [{ 'name': 'GroupItems 1', value: 'f3_2' }] } } ], [ - { excelCell: { value: 'f1_1', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, - { excelCell: { value: 'f3_1', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } } + { excelCell: { value: 'f1_1', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, + { excelCell: { value: 'f3_1', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } } ], [ - { excelCell: { value: 'f1_2', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(0) } }, - { excelCell: { value: 'f3_2', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(2) } } + { excelCell: { value: 'f1_2', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(0) } }, + { excelCell: { value: 'f3_2', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(2) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 3, column: 2 }, { row: 3, column: 2 }, topLeft); helper.checkAutoFilter(autoFilterEnabled, null); helper.checkFont(expectedCells); @@ -4812,7 +4669,7 @@ const moduleConfig = { helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0, 1, 1], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 3, column: 2 }, topLeft); + helper.checkCellRange(cellRange, { row: 3, column: 2 }, topLeft); done(); }); }); @@ -4842,29 +4699,29 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: 'f1_1', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, - { excelCell: { value: 'f2_1', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } } + { excelCell: { value: 'f1_1', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, + { excelCell: { value: 'f2_1', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } } ], [ - { excelCell: { value: 'f1_2', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(0) } }, - { excelCell: { value: 'f2_2', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(1) } } + { excelCell: { value: 'f1_2', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(0) } }, + { excelCell: { value: 'f2_2', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(1) } } ], [ - { excelCell: { value: 'Max: f1_2', alignment: alignLeftWrap, font: { bold: true } }, gridCell: { rowType: 'totalFooter', column: dataGrid.columnOption(0), value: ds[1].f1, totalSummaryItemName: 'TotalSummary 1' } }, - { excelCell: { value: 'Max: f2_2', alignment: alignLeftWrap, font: { bold: true } }, gridCell: { rowType: 'totalFooter', column: dataGrid.columnOption(1), value: ds[1].f2, totalSummaryItemName: 'TotalSummary 3' } } + { excelCell: { value: 'Max: f1_2', alignment: alignLeftTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'totalFooter', column: dataGrid.columnOption(0), value: ds[1].f1, totalSummaryItemName: 'TotalSummary 1' } }, + { excelCell: { value: 'Max: f2_2', alignment: alignLeftTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'totalFooter', column: dataGrid.columnOption(1), value: ds[1].f2, totalSummaryItemName: 'TotalSummary 3' } } ], [ - { excelCell: { value: 'Min: f1_1', alignment: alignLeftWrap, font: { bold: true } }, gridCell: { rowType: 'totalFooter', column: dataGrid.columnOption(0), value: ds[0].f1, totalSummaryItemName: 'TotalSummary 2' } }, - { excelCell: { value: 'Min: f2_1', alignment: alignLeftWrap, font: { bold: true } }, gridCell: { rowType: 'totalFooter', column: dataGrid.columnOption(1), value: ds[0].f2, totalSummaryItemName: 'TotalSummary 4' } } + { excelCell: { value: 'Min: f1_1', alignment: alignLeftTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'totalFooter', column: dataGrid.columnOption(0), value: ds[0].f1, totalSummaryItemName: 'TotalSummary 2' } }, + { excelCell: { value: 'Min: f2_1', alignment: alignLeftTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'totalFooter', column: dataGrid.columnOption(1), value: ds[0].f2, totalSummaryItemName: 'TotalSummary 4' } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 4, column: 2 }, { row: 4, column: 2 }, topLeft); helper.checkFont(expectedCells); helper.checkAlignment(expectedCells); helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0, 0, 0], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 4, column: 2 }, topLeft); + helper.checkCellRange(cellRange, { row: 4, column: 2 }, topLeft); done(); }); }); @@ -4896,14 +4753,14 @@ const moduleConfig = { helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); done(); }); }); - QUnit.test('Total summary, export.excelWrapTextEnabled: false, rtlEnabled: true', function(assert) { + QUnit.test('Total summary, grid.wordWrapEnabled: false, rtlEnabled: true', function(assert) { const done = assert.async(); const ds = [ { f1: 'f1_1', f2: 'f2_1' }, @@ -4923,31 +4780,29 @@ const moduleConfig = { { name: 'TotalSummary 4', column: 'f2', summaryType: 'min' } ] }, - export: { - excelWrapTextEnabled: false - }, + wordWrapEnabled: false, rtlEnabled: true, showColumnHeaders: false, loadingTimeout: undefined }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: 'f1_1', alignment: alignRightNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, - { excelCell: { value: 'f2_1', alignment: alignRightNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } } + { excelCell: { value: 'f1_1', alignment: alignRightTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, + { excelCell: { value: 'f2_1', alignment: alignRightTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } } ], [ - { excelCell: { value: 'f1_2', alignment: alignRightNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(0) } }, - { excelCell: { value: 'f2_2', alignment: alignRightNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(1) } } + { excelCell: { value: 'f1_2', alignment: alignRightTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(0) } }, + { excelCell: { value: 'f2_2', alignment: alignRightTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(1) } } ], [ - { excelCell: { value: 'Max: f1_2', alignment: alignRightTopWrap, font: { bold: true } }, gridCell: { rowType: 'totalFooter', column: dataGrid.columnOption(0), value: ds[1].f1, totalSummaryItemName: 'TotalSummary 1' } }, - { excelCell: { value: 'Max: f2_2', alignment: alignRightTopWrap, font: { bold: true } }, gridCell: { rowType: 'totalFooter', column: dataGrid.columnOption(1), value: ds[1].f2, totalSummaryItemName: 'TotalSummary 3' } } + { excelCell: { value: 'Max: f1_2', alignment: alignRightTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'totalFooter', column: dataGrid.columnOption(0), value: ds[1].f1, totalSummaryItemName: 'TotalSummary 1' } }, + { excelCell: { value: 'Max: f2_2', alignment: alignRightTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'totalFooter', column: dataGrid.columnOption(1), value: ds[1].f2, totalSummaryItemName: 'TotalSummary 3' } } ], [ - { excelCell: { value: 'Min: f1_1', alignment: alignRightTopWrap, font: { bold: true } }, gridCell: { rowType: 'totalFooter', column: dataGrid.columnOption(0), value: ds[0].f1, totalSummaryItemName: 'TotalSummary 2' } }, - { excelCell: { value: 'Min: f2_1', alignment: alignRightTopWrap, font: { bold: true } }, gridCell: { rowType: 'totalFooter', column: dataGrid.columnOption(1), value: ds[0].f2, totalSummaryItemName: 'TotalSummary 4' } } + { excelCell: { value: 'Min: f1_1', alignment: alignRightTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'totalFooter', column: dataGrid.columnOption(0), value: ds[0].f1, totalSummaryItemName: 'TotalSummary 2' } }, + { excelCell: { value: 'Min: f2_1', alignment: alignRightTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'totalFooter', column: dataGrid.columnOption(1), value: ds[0].f2, totalSummaryItemName: 'TotalSummary 4' } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells, { keepColumnWidths: false })).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells, { keepColumnWidths: false })).then((cellRange) => { helper.checkFont(expectedCells); helper.checkAlignment(expectedCells); helper.checkValues(expectedCells); @@ -4956,7 +4811,7 @@ const moduleConfig = { }); }); - QUnit.test('TODO: not supported - Total summary, export.excelWrapTextEnabled: true, totalItems.alignment, total_2.alignment: center, total_3: right', function(assert) { + QUnit.test('TODO: not supported - Total summary, grid.wordWrapEnabled: true, totalItems.alignment, total_2.alignment: center, total_3: right', function(assert) { const done = assert.async(); const ds = [ { f1: 'f1_1', f2: 'f2_1' }, @@ -4977,30 +4832,28 @@ const moduleConfig = { { name: 'TotalSummary 4', column: 'f2', summaryType: 'min' } ] }, - export: { - excelWrapTextEnabled: true - }, + wordWrapEnabled: true, showColumnHeaders: false, loadingTimeout: undefined }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: 'f1_1', alignment: alignLeftWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, - { excelCell: { value: 'f2_1', alignment: alignLeftWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } } + { excelCell: { value: 'f1_1', alignment: alignLeftTopWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, + { excelCell: { value: 'f2_1', alignment: alignLeftTopWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } } ], [ - { excelCell: { value: 'f1_2', alignment: alignLeftWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(0) } }, - { excelCell: { value: 'f2_2', alignment: alignLeftWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(1) } } + { excelCell: { value: 'f1_2', alignment: alignLeftTopWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(0) } }, + { excelCell: { value: 'f2_2', alignment: alignLeftTopWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(1) } } ], [ - { excelCell: { value: 'Max: f1_2', alignment: alignLeftWrap, font: { bold: true } }, gridCell: { rowType: 'totalFooter', column: dataGrid.columnOption(0), value: ds[1].f1, totalSummaryItemName: 'TotalSummary 1' } }, - { excelCell: { value: 'Max: f2_2', alignment: alignLeftWrap, font: { bold: true } }, gridCell: { rowType: 'totalFooter', column: dataGrid.columnOption(1), value: ds[1].f2, totalSummaryItemName: 'TotalSummary 3' } } + { excelCell: { value: 'Max: f1_2', alignment: alignLeftTopWrap, font: { bold: true } }, gridCell: { rowType: 'totalFooter', column: dataGrid.columnOption(0), value: ds[1].f1, totalSummaryItemName: 'TotalSummary 1' } }, + { excelCell: { value: 'Max: f2_2', alignment: alignLeftTopWrap, font: { bold: true } }, gridCell: { rowType: 'totalFooter', column: dataGrid.columnOption(1), value: ds[1].f2, totalSummaryItemName: 'TotalSummary 3' } } ], [ - { excelCell: { value: 'Min: f1_1', alignment: alignLeftWrap, font: { bold: true } }, gridCell: { rowType: 'totalFooter', column: dataGrid.columnOption(0), value: ds[0].f1, totalSummaryItemName: 'TotalSummary 2' } }, - { excelCell: { value: 'Min: f2_1', alignment: alignLeftWrap, font: { bold: true } }, gridCell: { rowType: 'totalFooter', column: dataGrid.columnOption(1), value: ds[0].f2, totalSummaryItemName: 'TotalSummary 4' } } + { excelCell: { value: 'Min: f1_1', alignment: alignLeftTopWrap, font: { bold: true } }, gridCell: { rowType: 'totalFooter', column: dataGrid.columnOption(0), value: ds[0].f1, totalSummaryItemName: 'TotalSummary 2' } }, + { excelCell: { value: 'Min: f2_1', alignment: alignLeftTopWrap, font: { bold: true } }, gridCell: { rowType: 'totalFooter', column: dataGrid.columnOption(1), value: ds[0].f2, totalSummaryItemName: 'TotalSummary 4' } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells, { keepColumnWidths: false })).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells, { keepColumnWidths: false })).then((cellRange) => { helper.checkFont(expectedCells); helper.checkAlignment(expectedCells); helper.checkValues(expectedCells); @@ -5035,19 +4888,19 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: 'f1_2', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(0) } }, - { excelCell: { value: 'f2_2', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(1) } } + { excelCell: { value: 'f1_2', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(0) } }, + { excelCell: { value: 'f2_2', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(1) } } ], [ - { excelCell: { value: 'Max: f1_2', alignment: alignLeftWrap, font: { bold: true } }, gridCell: { rowType: 'totalFooter', column: dataGrid.columnOption(0), value: ds[1].f1, totalSummaryItemName: 'TotalSummary 1' } }, - { excelCell: { value: 'Max: f2_2', alignment: alignLeftWrap, font: { bold: true } }, gridCell: { rowType: 'totalFooter', column: dataGrid.columnOption(1), value: ds[1].f2, totalSummaryItemName: 'TotalSummary 3' } } + { excelCell: { value: 'Max: f1_2', alignment: alignLeftTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'totalFooter', column: dataGrid.columnOption(0), value: ds[1].f1, totalSummaryItemName: 'TotalSummary 1' } }, + { excelCell: { value: 'Max: f2_2', alignment: alignLeftTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'totalFooter', column: dataGrid.columnOption(1), value: ds[1].f2, totalSummaryItemName: 'TotalSummary 3' } } ], [ - { excelCell: { value: 'Min: f1_2', alignment: alignLeftWrap, font: { bold: true } }, gridCell: { rowType: 'totalFooter', column: dataGrid.columnOption(0), value: ds[1].f1, totalSummaryItemName: 'TotalSummary 2' } }, - { excelCell: { value: 'Min: f2_2', alignment: alignLeftWrap, font: { bold: true } }, gridCell: { rowType: 'totalFooter', column: dataGrid.columnOption(1), value: ds[1].f2, totalSummaryItemName: 'TotalSummary 4' } } + { excelCell: { value: 'Min: f1_2', alignment: alignLeftTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'totalFooter', column: dataGrid.columnOption(0), value: ds[1].f1, totalSummaryItemName: 'TotalSummary 2' } }, + { excelCell: { value: 'Min: f2_2', alignment: alignLeftTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'totalFooter', column: dataGrid.columnOption(1), value: ds[1].f2, totalSummaryItemName: 'TotalSummary 4' } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells, { selectedRowsOnly: true })).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells, { selectedRowsOnly: true })).then((cellRange) => { helper.checkRowAndColumnCount({ row: 3, column: 2 }, { row: 3, column: 2 }, topLeft); helper.checkAutoFilter(autoFilterEnabled, null); helper.checkFont(expectedCells); @@ -5055,7 +4908,7 @@ const moduleConfig = { helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0, 0, 0], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 3, column: 2 }, topLeft); + helper.checkCellRange(cellRange, { row: 3, column: 2 }, topLeft); done(); }); }); @@ -5084,11 +4937,11 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: 'f2_1', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } }, - { excelCell: { value: 'f3_1', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } } + { excelCell: { value: 'f2_1', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } }, + { excelCell: { value: 'f3_1', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } } ], [ - { excelCell: { value: 'f2_2', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(1) } }, - { excelCell: { value: 'f3_2', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(2) } } + { excelCell: { value: 'f2_2', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(1) } }, + { excelCell: { value: 'f3_2', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(2) } } ], [ { excelCell: { value: null }, gridCell: { value: undefined, rowType: 'totalFooter', column: dataGrid.columnOption(1) } }, { excelCell: { value: null }, gridCell: { value: undefined, rowType: 'totalFooter', column: dataGrid.columnOption(2) } } @@ -5096,7 +4949,7 @@ const moduleConfig = { helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 2, column: 2 }, { row: 3, column: 2 }, topLeft); helper.checkAutoFilter(autoFilterEnabled, null); helper.checkFont(expectedCells); @@ -5104,7 +4957,7 @@ const moduleConfig = { helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0, 0, 0], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 3, column: 2 }, topLeft); + helper.checkCellRange(cellRange, { row: 3, column: 2 }, topLeft); done(); }); }); @@ -5133,19 +4986,19 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: 'f2_1', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } }, - { excelCell: { value: 'f3_1', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } } + { excelCell: { value: 'f2_1', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } }, + { excelCell: { value: 'f3_1', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } } ], [ - { excelCell: { value: 'f2_2', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(1) } }, - { excelCell: { value: 'f3_2', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(2) } } + { excelCell: { value: 'f2_2', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(1) } }, + { excelCell: { value: 'f3_2', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(2) } } ], [ - { excelCell: { value: 'Max: f2_2', alignment: alignLeftWrap, font: { bold: true } }, gridCell: { rowType: 'totalFooter', column: dataGrid.columnOption(1), value: ds[1].f2 } }, + { excelCell: { value: 'Max: f2_2', alignment: alignLeftTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'totalFooter', column: dataGrid.columnOption(1), value: ds[1].f2 } }, { excelCell: { value: null }, gridCell: { value: undefined, rowType: 'totalFooter', column: dataGrid.columnOption(2) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 3, column: 2 }, { row: 3, column: 2 }, topLeft); helper.checkAutoFilter(autoFilterEnabled, null); helper.checkFont(expectedCells); @@ -5153,7 +5006,7 @@ const moduleConfig = { helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0, 0, 0], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 3, column: 2 }, topLeft); + helper.checkCellRange(cellRange, { row: 3, column: 2 }, topLeft); done(); }); }); @@ -5181,19 +5034,19 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: 'f2_1', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } }, - { excelCell: { value: 'f3_1', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } } + { excelCell: { value: 'f2_1', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } }, + { excelCell: { value: 'f3_1', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } } ], [ - { excelCell: { value: 'f2_2', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(1) } }, - { excelCell: { value: 'f3_2', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(2) } } + { excelCell: { value: 'f2_2', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(1) } }, + { excelCell: { value: 'f3_2', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(2) } } ], [ { excelCell: { value: null, alignment: undefined }, gridCell: { value: undefined, rowType: 'totalFooter', column: dataGrid.columnOption(1) } }, - { excelCell: { value: 'Max: f3_2', alignment: alignLeftWrap, font: { bold: true } }, gridCell: { rowType: 'totalFooter', column: dataGrid.columnOption(2), value: ds[1].f3 } } + { excelCell: { value: 'Max: f3_2', alignment: alignLeftTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'totalFooter', column: dataGrid.columnOption(2), value: ds[1].f3 } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 3, column: 2 }, { row: 3, column: 2 }, topLeft); helper.checkAutoFilter(autoFilterEnabled, null); helper.checkFont(expectedCells); @@ -5201,7 +5054,7 @@ const moduleConfig = { helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0, 0, 0], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 3, column: 2 }, topLeft); + helper.checkCellRange(cellRange, { row: 3, column: 2 }, topLeft); done(); }); }); @@ -5230,19 +5083,19 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: 'f1_1', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, - { excelCell: { value: 'f3_1', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } } + { excelCell: { value: 'f1_1', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, + { excelCell: { value: 'f3_1', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } } ], [ - { excelCell: { value: 'f1_2', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(0) } }, - { excelCell: { value: 'f3_2', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(2) } } + { excelCell: { value: 'f1_2', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(0) } }, + { excelCell: { value: 'f3_2', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(2) } } ], [ - { excelCell: { value: 'Max: f1_2', alignment: alignLeftWrap, font: { bold: true } }, gridCell: { rowType: 'totalFooter', column: dataGrid.columnOption(0), value: ds[1].f1 } }, + { excelCell: { value: 'Max: f1_2', alignment: alignLeftTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'totalFooter', column: dataGrid.columnOption(0), value: ds[1].f1 } }, { excelCell: { value: null }, gridCell: { value: undefined, rowType: 'totalFooter', column: dataGrid.columnOption(2) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 3, column: 2 }, { row: 3, column: 2 }, topLeft); helper.checkAutoFilter(autoFilterEnabled, null); helper.checkFont(expectedCells); @@ -5250,7 +5103,7 @@ const moduleConfig = { helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0, 0, 0], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 3, column: 2 }, topLeft); + helper.checkCellRange(cellRange, { row: 3, column: 2 }, topLeft); done(); }); }); @@ -5279,11 +5132,11 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: 'f1_1', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, - { excelCell: { value: 'f3_1', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } } + { excelCell: { value: 'f1_1', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, + { excelCell: { value: 'f3_1', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } } ], [ - { excelCell: { value: 'f1_2', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(0) } }, - { excelCell: { value: 'f3_2', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(2) } } + { excelCell: { value: 'f1_2', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(0) } }, + { excelCell: { value: 'f3_2', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(2) } } ], [ { excelCell: { value: null }, gridCell: { value: undefined, rowType: 'totalFooter', column: dataGrid.columnOption(0) } }, { excelCell: { value: null }, gridCell: { value: undefined, rowType: 'totalFooter', column: dataGrid.columnOption(2) } } @@ -5291,7 +5144,7 @@ const moduleConfig = { helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 2, column: 2 }, { row: 3, column: 2 }, topLeft); helper.checkAutoFilter(autoFilterEnabled, null); helper.checkFont(expectedCells); @@ -5299,7 +5152,7 @@ const moduleConfig = { helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0, 0, 0], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 3, column: 2 }, topLeft); + helper.checkCellRange(cellRange, { row: 3, column: 2 }, topLeft); done(); }); }); @@ -5328,26 +5181,26 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: 'f1_1', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, - { excelCell: { value: 'f3_1', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } } + { excelCell: { value: 'f1_1', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, + { excelCell: { value: 'f3_1', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } } ], [ - { excelCell: { value: 'f1_2', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(0) }, }, - { excelCell: { value: 'f3_2', alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(2) }, } + { excelCell: { value: 'f1_2', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(0) }, }, + { excelCell: { value: 'f3_2', alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[1], column: dataGrid.columnOption(2) }, } ], [ { excelCell: { value: null }, gridCell: { value: undefined, rowType: 'totalFooter', column: dataGrid.columnOption(0) } }, - { excelCell: { value: 'Max: f3_2', alignment: alignLeftWrap, font: { bold: true } }, gridCell: { rowType: 'totalFooter', column: dataGrid.columnOption(2), value: ds[1].f3 } } + { excelCell: { value: 'Max: f3_2', alignment: alignLeftTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'totalFooter', column: dataGrid.columnOption(2), value: ds[1].f3 } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 3, column: 2 }, { row: 3, column: 2 }, topLeft); helper.checkAutoFilter(autoFilterEnabled, null); helper.checkFont(expectedCells); helper.checkAlignment(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0, 0, 0], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 3, column: 2 }, topLeft); + helper.checkCellRange(cellRange, { row: 3, column: 2 }, topLeft); done(); }); }); @@ -5368,16 +5221,16 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: 'F1', alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } }, - { excelCell: { value: 'Band1', alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(1) } } + { excelCell: { value: 'F1', alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } }, + { excelCell: { value: 'Band1', alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(1) } } ], [ - { excelCell: { value: ds[0].f1, alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, + { excelCell: { value: ds[0].f1, alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, { excelCell: { value: null }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } }, ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 2, column: 2 }, { row: 2, column: 2 }, topLeft); helper.checkAutoFilter(autoFilterEnabled, { from: topLeft, to: { row: topLeft.row + 1, column: topLeft.column + 1 } }, { state: 'frozen', ySplit: topLeft.row }); helper.checkColumnWidths([excelColumnWidthFromColumn100Pixels, excelColumnWidthFromColumn200Pixels], topLeft.column); @@ -5385,7 +5238,7 @@ const moduleConfig = { helper.checkAlignment(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 2, column: 2 }, topLeft); + helper.checkCellRange(cellRange, { row: 2, column: 2 }, topLeft); done(); }); }); @@ -5408,16 +5261,16 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: 'Band1', alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } } + { excelCell: { value: 'Band1', alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } } ], [ - { excelCell: { value: 'F1', alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(1) } } + { excelCell: { value: 'F1', alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(1) } } ], [ - { excelCell: { value: ds[0].f1, alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } } + { excelCell: { value: ds[0].f1, alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 3, column: 1 }, { row: 3, column: 1 }, topLeft); helper.checkAutoFilter(autoFilterEnabled, { from: topLeft, to: { row: topLeft.row + 2, column: topLeft.column } }, { state: 'frozen', ySplit: topLeft.row + 1 }); helper.checkColumnWidths([excelColumnWidthFromColumn100Pixels], topLeft.column); @@ -5426,7 +5279,7 @@ const moduleConfig = { helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0, 0, 0], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 3, column: 1 }, topLeft); + helper.checkCellRange(cellRange, { row: 3, column: 1 }, topLeft); done(); }); }); @@ -5451,22 +5304,22 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: 'F1', master: [1, 1], alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } }, - { excelCell: { value: 'Band1', master: [1, 2], alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(1) } }, - { excelCell: { value: 'Band1', master: [1, 2], alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(1) } } + { excelCell: { value: 'F1', master: [1, 1], alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } }, + { excelCell: { value: 'Band1', master: [1, 2], alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(1) } }, + { excelCell: { value: 'Band1', master: [1, 2], alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(1) } } ], [ - { excelCell: { value: 'F1', master: [1, 1], alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } }, - { excelCell: { value: 'F2', alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(2) } }, - { excelCell: { value: 'F3', alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(3) } } + { excelCell: { value: 'F1', master: [1, 1], alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } }, + { excelCell: { value: 'F2', alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(2) } }, + { excelCell: { value: 'F3', alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(3) } } ], [ - { excelCell: { value: ds[0].f1, alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, - { excelCell: { value: '', alignment: alignLeftNoWrap }, gridCell: { value: undefined, rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } }, - { excelCell: { value: '', alignment: alignLeftNoWrap }, gridCell: { value: undefined, rowType: 'data', data: ds[0], column: dataGrid.columnOption(3) } } + { excelCell: { value: ds[0].f1, alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, + { excelCell: { value: '', alignment: alignLeftTopNoWrap }, gridCell: { value: undefined, rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } }, + { excelCell: { value: '', alignment: alignLeftTopNoWrap }, gridCell: { value: undefined, rowType: 'data', data: ds[0], column: dataGrid.columnOption(3) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 3, column: 3 }, { row: 3, column: 3 }, topLeft); helper.checkAutoFilter(autoFilterEnabled, { from: topLeft, to: { row: topLeft.row + 2, column: topLeft.column + 2 } }, { state: 'frozen', ySplit: topLeft.row + 1 }); helper.checkFont(expectedCells); @@ -5474,7 +5327,7 @@ const moduleConfig = { helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0, 0, 0], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 3, column: 3 }, topLeft); + helper.checkCellRange(cellRange, { row: 3, column: 3 }, topLeft); done(); }); }); @@ -5500,20 +5353,20 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: 'F1', master: [1, 1], alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } }, - { excelCell: { value: 'Band1', master: [1, 2], alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(1) } }, - { excelCell: { value: 'Band1', master: [1, 2], alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(1) } }, - { excelCell: { value: 'Band1', master: [1, 2], alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(1) } } + { excelCell: { value: 'F1', master: [1, 1], alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } }, + { excelCell: { value: 'Band1', master: [1, 2], alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(1) } }, + { excelCell: { value: 'Band1', master: [1, 2], alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(1) } }, + { excelCell: { value: 'Band1', master: [1, 2], alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(1) } } ], [ - { excelCell: { value: 'F1', master: [1, 1], alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } }, - { excelCell: { value: 'F2', alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(2) } }, - { excelCell: { value: 'F3', alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(3) } }, - { excelCell: { value: 'F4', alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(4) } } + { excelCell: { value: 'F1', master: [1, 1], alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } }, + { excelCell: { value: 'F2', alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(2) } }, + { excelCell: { value: 'F3', alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(3) } }, + { excelCell: { value: 'F4', alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(4) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 2, column: 4 }, { row: 2, column: 4 }, topLeft); helper.checkAutoFilter(autoFilterEnabled, { from: topLeft, to: { row: topLeft.row + 1, column: topLeft.column + 3 } }, { state: 'frozen', ySplit: topLeft.row + 1 }); helper.checkColumnWidths([excelColumnWidthFromColumn100Pixels, excelColumnWidthFromColumn150Pixels, excelColumnWidthFromColumn200Pixels, excelColumnWidthFromColumn200Pixels], topLeft.column); @@ -5522,7 +5375,7 @@ const moduleConfig = { helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0, 0], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 2, column: 4 }, topLeft); + helper.checkCellRange(cellRange, { row: 2, column: 4 }, topLeft); done(); }); }); @@ -5554,28 +5407,28 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: 'F1', master: [1, 1], alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } }, - { excelCell: { value: 'Band1', master: [1, 2], alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(1) } }, - { excelCell: { value: 'Band1', master: [1, 2], alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(1) } }, - { excelCell: { value: 'Band2', master: [1, 4], alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(4) } }, - { excelCell: { value: 'Band2', master: [1, 4], alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(4) } } + { excelCell: { value: 'F1', master: [1, 1], alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } }, + { excelCell: { value: 'Band1', master: [1, 2], alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(1) } }, + { excelCell: { value: 'Band1', master: [1, 2], alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(1) } }, + { excelCell: { value: 'Band2', master: [1, 4], alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(4) } }, + { excelCell: { value: 'Band2', master: [1, 4], alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(4) } } ], [ - { excelCell: { value: 'F1', master: [1, 1], alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } }, - { excelCell: { value: 'F2', alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(2) } }, - { excelCell: { value: 'F3', alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(3) } }, - { excelCell: { value: 'F4', alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(5) } }, - { excelCell: { value: 'F5', alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(6) } } + { excelCell: { value: 'F1', master: [1, 1], alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } }, + { excelCell: { value: 'F2', alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(2) } }, + { excelCell: { value: 'F3', alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(3) } }, + { excelCell: { value: 'F4', alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(5) } }, + { excelCell: { value: 'F5', alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(6) } } ], [ - { excelCell: { value: ds[0].f1, alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, - { excelCell: { value: '', alignment: alignLeftNoWrap }, gridCell: { value: undefined, rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } }, - { excelCell: { value: '', alignment: alignLeftNoWrap }, gridCell: { value: undefined, rowType: 'data', data: ds[0], column: dataGrid.columnOption(3) } }, - { excelCell: { value: '', alignment: alignLeftNoWrap }, gridCell: { value: undefined, rowType: 'data', data: ds[0], column: dataGrid.columnOption(5) } }, - { excelCell: { value: '', alignment: alignLeftNoWrap }, gridCell: { value: undefined, rowType: 'data', data: ds[0], column: dataGrid.columnOption(6) } } + { excelCell: { value: ds[0].f1, alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, + { excelCell: { value: '', alignment: alignLeftTopNoWrap }, gridCell: { value: undefined, rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } }, + { excelCell: { value: '', alignment: alignLeftTopNoWrap }, gridCell: { value: undefined, rowType: 'data', data: ds[0], column: dataGrid.columnOption(3) } }, + { excelCell: { value: '', alignment: alignLeftTopNoWrap }, gridCell: { value: undefined, rowType: 'data', data: ds[0], column: dataGrid.columnOption(5) } }, + { excelCell: { value: '', alignment: alignLeftTopNoWrap }, gridCell: { value: undefined, rowType: 'data', data: ds[0], column: dataGrid.columnOption(6) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 3, column: 5 }, { row: 3, column: 5 }, topLeft); helper.checkAutoFilter(autoFilterEnabled, { from: topLeft, to: { row: topLeft.row + 2, column: topLeft.column + 4 } }, { state: 'frozen', ySplit: topLeft.row + 1 }); helper.checkColumnWidths([excelColumnWidthFromColumn100Pixels, excelColumnWidthFromColumn150Pixels, excelColumnWidthFromColumn200Pixels, excelColumnWidthFromColumn100Pixels, excelColumnWidthFromColumn200Pixels], topLeft.column); @@ -5584,7 +5437,7 @@ const moduleConfig = { helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0, 0, 0], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 3, column: 5 }, topLeft); + helper.checkCellRange(cellRange, { row: 3, column: 5 }, topLeft); done(); }); }); @@ -5618,28 +5471,28 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: 'F1', master: [1, 1], alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } }, - { excelCell: { value: 'Band1', master: [1, 2], alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(1) } }, - { excelCell: { value: 'Band1', master: [1, 2], alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(1) } }, - { excelCell: { value: 'Band2', master: [1, 4], alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(5) } }, - { excelCell: { value: 'Band2', master: [1, 4], alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(5) } } + { excelCell: { value: 'F1', master: [1, 1], alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } }, + { excelCell: { value: 'Band1', master: [1, 2], alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(1) } }, + { excelCell: { value: 'Band1', master: [1, 2], alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(1) } }, + { excelCell: { value: 'Band2', master: [1, 4], alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(5) } }, + { excelCell: { value: 'Band2', master: [1, 4], alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(5) } } ], [ - { excelCell: { value: 'F1', master: [1, 1], alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } }, - { excelCell: { value: 'F2', alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(2) } }, - { excelCell: { value: 'F4', alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(4) } }, - { excelCell: { value: 'F6', alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(7) } }, - { excelCell: { value: 'F7', alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(8) } } + { excelCell: { value: 'F1', master: [1, 1], alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } }, + { excelCell: { value: 'F2', alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(2) } }, + { excelCell: { value: 'F4', alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(4) } }, + { excelCell: { value: 'F6', alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(7) } }, + { excelCell: { value: 'F7', alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(8) } } ], [ - { excelCell: { value: ds[0].f1, alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, - { excelCell: { value: '', alignment: alignLeftNoWrap }, gridCell: { value: undefined, rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } }, - { excelCell: { value: '', alignment: alignLeftNoWrap }, gridCell: { value: undefined, rowType: 'data', data: ds[0], column: dataGrid.columnOption(4) } }, - { excelCell: { value: '', alignment: alignLeftNoWrap }, gridCell: { value: undefined, rowType: 'data', data: ds[0], column: dataGrid.columnOption(7) } }, - { excelCell: { value: '', alignment: alignLeftNoWrap }, gridCell: { value: undefined, rowType: 'data', data: ds[0], column: dataGrid.columnOption(8) } } + { excelCell: { value: ds[0].f1, alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, + { excelCell: { value: '', alignment: alignLeftTopNoWrap }, gridCell: { value: undefined, rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } }, + { excelCell: { value: '', alignment: alignLeftTopNoWrap }, gridCell: { value: undefined, rowType: 'data', data: ds[0], column: dataGrid.columnOption(4) } }, + { excelCell: { value: '', alignment: alignLeftTopNoWrap }, gridCell: { value: undefined, rowType: 'data', data: ds[0], column: dataGrid.columnOption(7) } }, + { excelCell: { value: '', alignment: alignLeftTopNoWrap }, gridCell: { value: undefined, rowType: 'data', data: ds[0], column: dataGrid.columnOption(8) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 3, column: 5 }, { row: 3, column: 5 }, topLeft); helper.checkAutoFilter(autoFilterEnabled, { from: topLeft, to: { row: topLeft.row + 2, column: topLeft.column + 4 } }, { state: 'frozen', ySplit: topLeft.row + 1 }); helper.checkColumnWidths([excelColumnWidthFromColumn100Pixels, excelColumnWidthFromColumn150Pixels, excelColumnWidthFromColumn100Pixels, excelColumnWidthFromColumn150Pixels, excelColumnWidthFromColumn200Pixels], topLeft.column); @@ -5648,7 +5501,7 @@ const moduleConfig = { helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0, 0, 0], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 3, column: 5 }, topLeft); + helper.checkCellRange(cellRange, { row: 3, column: 5 }, topLeft); done(); }); }); @@ -5675,15 +5528,15 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: ds[0].f1, alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, - { excelCell: { value: ds[0].f2, alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } }, - { excelCell: { value: ds[0].f3, alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(3) } }, - { excelCell: { value: ds[0].f4, alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(4) } } + { excelCell: { value: ds[0].f1, alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, + { excelCell: { value: ds[0].f2, alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } }, + { excelCell: { value: ds[0].f3, alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(3) } }, + { excelCell: { value: ds[0].f4, alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(4) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 1, column: 4 }, { row: 1, column: 4 }, topLeft); helper.checkAutoFilter(autoFilterEnabled, null); helper.checkColumnWidths([excelColumnWidthFromColumn100Pixels, excelColumnWidthFromColumn150Pixels, excelColumnWidthFromColumn200Pixels, excelColumnWidthFromColumn200Pixels], topLeft.column); @@ -5692,7 +5545,7 @@ const moduleConfig = { helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0, 0], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 1, column: 4 }, topLeft); + helper.checkCellRange(cellRange, { row: 1, column: 4 }, topLeft); done(); }); }); @@ -5719,14 +5572,14 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: ds[0].f1, alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, - { excelCell: { value: ds[0].f3, alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(3) } }, - { excelCell: { value: ds[0].f4, alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(4) } } + { excelCell: { value: ds[0].f1, alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, + { excelCell: { value: ds[0].f3, alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(3) } }, + { excelCell: { value: ds[0].f4, alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(4) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 1, column: 3 }, { row: 1, column: 3 }, topLeft); helper.checkAutoFilter(autoFilterEnabled, null); helper.checkColumnWidths([excelColumnWidthFromColumn100Pixels, excelColumnWidthFromColumn200Pixels, excelColumnWidthFromColumn200Pixels], topLeft.column); @@ -5735,7 +5588,7 @@ const moduleConfig = { helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0, 0], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 1, column: 3 }, topLeft); + helper.checkCellRange(cellRange, { row: 1, column: 3 }, topLeft); done(); }); }); @@ -5762,14 +5615,14 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: ds[0].f1, alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, - { excelCell: { value: ds[0].f3, alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(3) } }, - { excelCell: { value: ds[0].f4, alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(4) } } + { excelCell: { value: ds[0].f1, alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, + { excelCell: { value: ds[0].f3, alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(3) } }, + { excelCell: { value: ds[0].f4, alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(4) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 1, column: 3 }, { row: 1, column: 3 }, topLeft); helper.checkAutoFilter(autoFilterEnabled, null); helper.checkColumnWidths([excelColumnWidthFromColumn100Pixels, excelColumnWidthFromColumn200Pixels, excelColumnWidthFromColumn100Pixels], topLeft.column); @@ -5778,7 +5631,7 @@ const moduleConfig = { helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0, 0], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 1, column: 3 }, topLeft); + helper.checkCellRange(cellRange, { row: 1, column: 3 }, topLeft); done(); }); }); @@ -5805,16 +5658,16 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: 'F1', alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } }, - { excelCell: { value: 'F4', alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(4) } } + { excelCell: { value: 'F1', alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } }, + { excelCell: { value: 'F4', alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(4) } } ], [ - { excelCell: { value: ds[0].f1, alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, - { excelCell: { value: ds[0].f4, alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(4) } } + { excelCell: { value: ds[0].f1, alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, + { excelCell: { value: ds[0].f4, alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(4) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 2, column: 2 }, { row: 2, column: 2 }, topLeft); helper.checkAutoFilter(autoFilterEnabled, { from: topLeft, to: { row: topLeft.row + 1, column: topLeft.column + 1 } }, { state: 'frozen', ySplit: topLeft.row }); helper.checkColumnWidths([excelColumnWidthFromColumn100Pixels, excelColumnWidthFromColumn200Pixels], topLeft.column); @@ -5823,7 +5676,7 @@ const moduleConfig = { helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0, 0, 0], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 2, column: 2 }, topLeft); + helper.checkCellRange(cellRange, { row: 2, column: 2 }, topLeft); done(); }); }); @@ -5850,19 +5703,19 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: 'F1', master: [1, 1], alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } }, - { excelCell: { value: 'F4', master: [1, 2], alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(4) } } + { excelCell: { value: 'F1', master: [1, 1], alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } }, + { excelCell: { value: 'F4', master: [1, 2], alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(4) } } ], [ - { excelCell: { value: 'F1', master: [1, 1], alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } }, - { excelCell: { value: 'F4', master: [1, 2], alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(4) } } + { excelCell: { value: 'F1', master: [1, 1], alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } }, + { excelCell: { value: 'F4', master: [1, 2], alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(4) } } ], [ - { excelCell: { value: ds[0].f1, alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, - { excelCell: { value: ds[0].f4, alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(4) } } + { excelCell: { value: ds[0].f1, alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, + { excelCell: { value: ds[0].f4, alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(4) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 3, column: 2 }, { row: 3, column: 2 }, topLeft); helper.checkAutoFilter(autoFilterEnabled, { from: topLeft, to: { row: topLeft.row + 2, column: topLeft.column + 1 } }, { state: 'frozen', ySplit: topLeft.row + 1 }); helper.checkColumnWidths([excelColumnWidthFromColumn100Pixels, excelColumnWidthFromColumn200Pixels], topLeft.column); @@ -5871,7 +5724,7 @@ const moduleConfig = { helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0, 0, 0], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 3, column: 2 }, topLeft); + helper.checkCellRange(cellRange, { row: 3, column: 2 }, topLeft); done(); }); }); @@ -5898,16 +5751,16 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: 'F1', alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } }, - { excelCell: { value: 'Band1', alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(1) } } + { excelCell: { value: 'F1', alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } }, + { excelCell: { value: 'Band1', alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(1) } } ], [ - { excelCell: { value: ds[0].f1, alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, + { excelCell: { value: ds[0].f1, alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, { excelCell: { value: null }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 2, column: 2 }, { row: 2, column: 2 }, topLeft); helper.checkAutoFilter(autoFilterEnabled, { from: topLeft, to: { row: topLeft.row + 1, column: topLeft.column + 1 } }, { state: 'frozen', ySplit: topLeft.row }); helper.checkColumnWidths([excelColumnWidthFromColumn100Pixels, excelColumnWidthFromColumn250Pixels], topLeft.column); @@ -5916,7 +5769,7 @@ const moduleConfig = { helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0, 0, 0], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 2, column: 2 }, topLeft); + helper.checkCellRange(cellRange, { row: 2, column: 2 }, topLeft); done(); }); }); @@ -5942,16 +5795,16 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: 'F1', alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } }, - { excelCell: { value: 'Band1', alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(1) } } + { excelCell: { value: 'F1', alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } }, + { excelCell: { value: 'Band1', alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(1) } } ], [ - { excelCell: { value: ds[0].f1, alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, + { excelCell: { value: ds[0].f1, alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, { excelCell: { value: null }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 2, column: 2 }, { row: 2, column: 2 }, topLeft); helper.checkAutoFilter(autoFilterEnabled, { from: topLeft, to: { row: topLeft.row + 1, column: topLeft.column + 1 } }, { state: 'frozen', ySplit: topLeft.row }); helper.checkColumnWidths([excelColumnWidthFromColumn100Pixels, excelColumnWidthFromColumn200Pixels], topLeft.column); @@ -5960,7 +5813,7 @@ const moduleConfig = { helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0, 0, 0], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 2, column: 2 }, topLeft); + helper.checkCellRange(cellRange, { row: 2, column: 2 }, topLeft); done(); }); }); @@ -5986,22 +5839,22 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: 'F1', master: [1, 1], alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } }, - { excelCell: { value: 'Band1', master: [1, 2], alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(1) } }, - { excelCell: { value: 'Band1', master: [1, 2], alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(1) } } + { excelCell: { value: 'F1', master: [1, 1], alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } }, + { excelCell: { value: 'Band1', master: [1, 2], alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(1) } }, + { excelCell: { value: 'Band1', master: [1, 2], alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(1) } } ], [ - { excelCell: { value: 'F1', master: [1, 1], alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } }, - { excelCell: { value: 'F3', alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(3) } }, - { excelCell: { value: 'F4', alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(4) } } + { excelCell: { value: 'F1', master: [1, 1], alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } }, + { excelCell: { value: 'F3', alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(3) } }, + { excelCell: { value: 'F4', alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(4) } } ], [ - { excelCell: { value: ds[0].f1, alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, - { excelCell: { value: ds[0].f3, alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(3) } }, - { excelCell: { value: ds[0].f4, alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(4) } } + { excelCell: { value: ds[0].f1, alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, + { excelCell: { value: ds[0].f3, alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(3) } }, + { excelCell: { value: ds[0].f4, alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(4) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 3, column: 3 }, { row: 3, column: 3 }, topLeft); helper.checkAutoFilter(autoFilterEnabled, { from: topLeft, to: { row: topLeft.row + 2, column: topLeft.column + 2 } }, { state: 'frozen', ySplit: topLeft.row + 1 }); helper.checkColumnWidths([excelColumnWidthFromColumn100Pixels, excelColumnWidthFromColumn200Pixels, excelColumnWidthFromColumn250Pixels], topLeft.column); @@ -6010,7 +5863,7 @@ const moduleConfig = { helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0, 0, 0], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 3, column: 3 }, topLeft); + helper.checkCellRange(cellRange, { row: 3, column: 3 }, topLeft); done(); }); }); @@ -6036,22 +5889,22 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: 'F1', master: [1, 1], alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } }, - { excelCell: { value: 'Band1', master: [1, 2], alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(1) } }, - { excelCell: { value: 'Band1', master: [1, 2], alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(1) } } + { excelCell: { value: 'F1', master: [1, 1], alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } }, + { excelCell: { value: 'Band1', master: [1, 2], alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(1) } }, + { excelCell: { value: 'Band1', master: [1, 2], alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(1) } } ], [ - { excelCell: { value: 'F1', master: [1, 1], alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } }, - { excelCell: { value: 'F3', alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(3) } }, - { excelCell: { value: 'F4', alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(4) } } + { excelCell: { value: 'F1', master: [1, 1], alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } }, + { excelCell: { value: 'F3', alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(3) } }, + { excelCell: { value: 'F4', alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(4) } } ], [ - { excelCell: { value: ds[0].f1, alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, - { excelCell: { value: ds[0].f3, alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(3) } }, - { excelCell: { value: ds[0].f4, alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(4) } } + { excelCell: { value: ds[0].f1, alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(0) } }, + { excelCell: { value: ds[0].f3, alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(3) } }, + { excelCell: { value: ds[0].f4, alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(4) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 3, column: 3 }, { row: 3, column: 3 }, topLeft); helper.checkAutoFilter(autoFilterEnabled, { from: topLeft, to: { row: topLeft.row + 2, column: topLeft.column + 2 } }, { state: 'frozen', ySplit: topLeft.row + 1 }); helper.checkColumnWidths([excelColumnWidthFromColumn100Pixels, excelColumnWidthFromColumn200Pixels, excelColumnWidthFromColumn150Pixels], topLeft.column); @@ -6060,7 +5913,7 @@ const moduleConfig = { helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0, 0, 0], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 3, column: 3 }, topLeft); + helper.checkCellRange(cellRange, { row: 3, column: 3 }, topLeft); done(); }); }); @@ -6090,26 +5943,26 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: 'Band1', master: [1, 1], alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } }, - { excelCell: { value: 'Band1', master: [1, 1], alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } }, - { excelCell: { value: 'Band1', master: [1, 1], alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } } + { excelCell: { value: 'Band1', master: [1, 1], alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } }, + { excelCell: { value: 'Band1', master: [1, 1], alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } }, + { excelCell: { value: 'Band1', master: [1, 1], alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } } ], [ - { excelCell: { value: 'Band1_1', master: [2, 1], alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(1) } }, - { excelCell: { value: 'Band1_1', master: [2, 1], alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(1) } }, - { excelCell: { value: 'Band1_1', master: [2, 1], alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(1) } } + { excelCell: { value: 'Band1_1', master: [2, 1], alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(1) } }, + { excelCell: { value: 'Band1_1', master: [2, 1], alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(1) } }, + { excelCell: { value: 'Band1_1', master: [2, 1], alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(1) } } ], [ - { excelCell: { value: 'F1', alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(2) } }, - { excelCell: { value: 'F2', alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(3) } }, - { excelCell: { value: 'F3', alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(4) } } + { excelCell: { value: 'F1', alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(2) } }, + { excelCell: { value: 'F2', alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(3) } }, + { excelCell: { value: 'F3', alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(4) } } ], [ - { excelCell: { value: ds[0].f1, alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } }, - { excelCell: { value: ds[0].f2, alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(3) } }, - { excelCell: { value: ds[0].f3, alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(4) } } + { excelCell: { value: ds[0].f1, alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } }, + { excelCell: { value: ds[0].f2, alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(3) } }, + { excelCell: { value: ds[0].f3, alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(4) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 4, column: 3 }, { row: 4, column: 3 }, topLeft); helper.checkAutoFilter(autoFilterEnabled, { from: topLeft, to: { row: topLeft.row + 3, column: topLeft.column + 2 } }, { state: 'frozen', ySplit: topLeft.row + 2 }); helper.checkColumnWidths([excelColumnWidthFromColumn100Pixels, excelColumnWidthFromColumn150Pixels, excelColumnWidthFromColumn200Pixels], topLeft.column); @@ -6118,7 +5971,7 @@ const moduleConfig = { helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0, 0, 0], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 4, column: 3 }, topLeft); + helper.checkCellRange(cellRange, { row: 4, column: 3 }, topLeft); done(); }); }); @@ -6148,22 +6001,22 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: 'Band1', master: [1, 1], alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } }, - { excelCell: { value: 'Band1', master: [1, 1], alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } } + { excelCell: { value: 'Band1', master: [1, 1], alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } }, + { excelCell: { value: 'Band1', master: [1, 1], alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } } ], [ - { excelCell: { value: 'Band1_1', master: [2, 1], alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(1) } }, - { excelCell: { value: 'Band1_1', master: [2, 1], alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(1) } } + { excelCell: { value: 'Band1_1', master: [2, 1], alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(1) } }, + { excelCell: { value: 'Band1_1', master: [2, 1], alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(1) } } ], [ - { excelCell: { value: 'F2', alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(3) } }, - { excelCell: { value: 'F3', alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(4) } } + { excelCell: { value: 'F2', alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(3) } }, + { excelCell: { value: 'F3', alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(4) } } ], [ - { excelCell: { value: ds[0].f2, alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(3) } }, - { excelCell: { value: ds[0].f3, alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(4) } } + { excelCell: { value: ds[0].f2, alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(3) } }, + { excelCell: { value: ds[0].f3, alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(4) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 4, column: 2 }, { row: 4, column: 2 }, topLeft); helper.checkAutoFilter(autoFilterEnabled, { from: topLeft, to: { row: topLeft.row + 3, column: topLeft.column + 1 } }, { state: 'frozen', ySplit: topLeft.row + 2 }); helper.checkColumnWidths([excelColumnWidthFromColumn150Pixels, excelColumnWidthFromColumn200Pixels], topLeft.column); @@ -6172,7 +6025,7 @@ const moduleConfig = { helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0, 0, 0], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 4, column: 2 }, topLeft); + helper.checkCellRange(cellRange, { row: 4, column: 2 }, topLeft); done(); }); }); @@ -6202,18 +6055,18 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: 'Band1', alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } } + { excelCell: { value: 'Band1', alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } } ], [ - { excelCell: { value: 'Band1_1', alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(1) } } + { excelCell: { value: 'Band1_1', alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(1) } } ], [ - { excelCell: { value: 'F1', alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(2) } } + { excelCell: { value: 'F1', alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(2) } } ], [ - { excelCell: { value: ds[0].f1, alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } } + { excelCell: { value: ds[0].f1, alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 4, column: 1 }, { row: 4, column: 1 }, topLeft); helper.checkAutoFilter(autoFilterEnabled, { from: topLeft, to: { row: topLeft.row + 3, column: topLeft.column } }, { state: 'frozen', ySplit: topLeft.row + 2 }); helper.checkColumnWidths([excelColumnWidthFromColumn100Pixels], topLeft.column); @@ -6222,7 +6075,7 @@ const moduleConfig = { helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0, 0, 0], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 4, column: 1 }, topLeft); + helper.checkCellRange(cellRange, { row: 4, column: 1 }, topLeft); done(); }); }); @@ -6252,26 +6105,26 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: 'Band1', master: [1, 1], alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } }, - { excelCell: { value: 'Band1', master: [1, 1], alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } }, - { excelCell: { value: 'Band1', master: [1, 1], alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } } + { excelCell: { value: 'Band1', master: [1, 1], alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } }, + { excelCell: { value: 'Band1', master: [1, 1], alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } }, + { excelCell: { value: 'Band1', master: [1, 1], alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } } ], [ - { excelCell: { value: 'F1', master: [2, 1], alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(1) } }, - { excelCell: { value: 'Band1_1', master: [2, 2], alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(2) } }, - { excelCell: { value: 'Band1_1', master: [2, 2], alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(2) } } + { excelCell: { value: 'F1', master: [2, 1], alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(1) } }, + { excelCell: { value: 'Band1_1', master: [2, 2], alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(2) } }, + { excelCell: { value: 'Band1_1', master: [2, 2], alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(2) } } ], [ - { excelCell: { value: 'F1', master: [2, 1], alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(1) } }, - { excelCell: { value: 'F2', alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(3) } }, - { excelCell: { value: 'F3', alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(4) } } + { excelCell: { value: 'F1', master: [2, 1], alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(1) } }, + { excelCell: { value: 'F2', alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(3) } }, + { excelCell: { value: 'F3', alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(4) } } ], [ - { excelCell: { value: ds[0].f1, alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } }, - { excelCell: { value: ds[0].f2, alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(3) } }, - { excelCell: { value: ds[0].f3, alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(4) } } + { excelCell: { value: ds[0].f1, alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(1) } }, + { excelCell: { value: ds[0].f2, alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(3) } }, + { excelCell: { value: ds[0].f3, alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(4) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 4, column: 3 }, { row: 4, column: 3 }, topLeft); helper.checkAutoFilter(autoFilterEnabled, { from: topLeft, to: { row: topLeft.row + 3, column: topLeft.column + 2 } }, { state: 'frozen', ySplit: topLeft.row + 2 }); helper.checkColumnWidths([excelColumnWidthFromColumn100Pixels, excelColumnWidthFromColumn150Pixels, excelColumnWidthFromColumn200Pixels], topLeft.column); @@ -6280,7 +6133,7 @@ const moduleConfig = { helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0, 0, 0], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 4, column: 3 }, topLeft); + helper.checkCellRange(cellRange, { row: 4, column: 3 }, topLeft); done(); }); }); @@ -6310,22 +6163,22 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: 'Band1', master: [1, 1], alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } }, - { excelCell: { value: 'Band1', master: [1, 1], alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } } + { excelCell: { value: 'Band1', master: [1, 1], alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } }, + { excelCell: { value: 'Band1', master: [1, 1], alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } } ], [ - { excelCell: { value: 'Band1_1', master: [2, 1], alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(2) } }, - { excelCell: { value: 'Band1_1', master: [2, 1], alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(2) } } + { excelCell: { value: 'Band1_1', master: [2, 1], alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(2) } }, + { excelCell: { value: 'Band1_1', master: [2, 1], alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(2) } } ], [ - { excelCell: { value: 'F2', alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(3) } }, - { excelCell: { value: 'F3', alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(4) } } + { excelCell: { value: 'F2', alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(3) } }, + { excelCell: { value: 'F3', alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(4) } } ], [ - { excelCell: { value: ds[0].f2, alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(3) } }, - { excelCell: { value: ds[0].f3, alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(4) } } + { excelCell: { value: ds[0].f2, alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(3) } }, + { excelCell: { value: ds[0].f3, alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(4) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 4, column: 2 }, { row: 4, column: 2 }, topLeft); helper.checkAutoFilter(autoFilterEnabled, { from: topLeft, to: { row: topLeft.row + 3, column: topLeft.column + 1 } }, { state: 'frozen', ySplit: topLeft.row + 2 }); helper.checkColumnWidths([excelColumnWidthFromColumn150Pixels, excelColumnWidthFromColumn200Pixels], topLeft.column); @@ -6334,7 +6187,7 @@ const moduleConfig = { helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0, 0, 0], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 4, column: 2 }, topLeft); + helper.checkCellRange(cellRange, { row: 4, column: 2 }, topLeft); done(); }); }); @@ -6364,18 +6217,18 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: 'Band1', alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } } + { excelCell: { value: 'Band1', alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } } ], [ - { excelCell: { value: 'Band1_1', alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(1) } } + { excelCell: { value: 'Band1_1', alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(1) } } ], [ - { excelCell: { value: 'F1', alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(2) } } + { excelCell: { value: 'F1', alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(2) } } ], [ - { excelCell: { value: ds[0].f1, alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } } + { excelCell: { value: ds[0].f1, alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 4, column: 1 }, { row: 4, column: 1 }, topLeft); helper.checkAutoFilter(autoFilterEnabled, { from: topLeft, to: { row: topLeft.row + 3, column: topLeft.column } }, { state: 'frozen', ySplit: topLeft.row + 2 }); helper.checkColumnWidths([excelColumnWidthFromColumn100Pixels], topLeft.column); @@ -6384,7 +6237,7 @@ const moduleConfig = { helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0, 0, 0], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 4, column: 1 }, topLeft); + helper.checkCellRange(cellRange, { row: 4, column: 1 }, topLeft); done(); }); }); @@ -6414,26 +6267,26 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: 'Band1', master: [1, 1], alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } }, - { excelCell: { value: 'Band1', master: [1, 1], alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } }, - { excelCell: { value: 'Band1', master: [1, 1], alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } } + { excelCell: { value: 'Band1', master: [1, 1], alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } }, + { excelCell: { value: 'Band1', master: [1, 1], alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } }, + { excelCell: { value: 'Band1', master: [1, 1], alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } } ], [ - { excelCell: { value: 'Band1_1', master: [2, 1], alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(1) } }, - { excelCell: { value: 'Band1_1', master: [2, 1], alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(1) } }, - { excelCell: { value: 'F3', master: [2, 3], alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(4) } } + { excelCell: { value: 'Band1_1', master: [2, 1], alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(1) } }, + { excelCell: { value: 'Band1_1', master: [2, 1], alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(1) } }, + { excelCell: { value: 'F3', master: [2, 3], alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(4) } } ], [ - { excelCell: { value: 'F1', alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(2) } }, - { excelCell: { value: 'F2', alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(3) } }, - { excelCell: { value: 'F3', master: [2, 3], alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(4) } } + { excelCell: { value: 'F1', alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(2) } }, + { excelCell: { value: 'F2', alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(3) } }, + { excelCell: { value: 'F3', master: [2, 3], alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(4) } } ], [ - { excelCell: { value: ds[0].f1, alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } }, - { excelCell: { value: ds[0].f2, alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(3) } }, - { excelCell: { value: ds[0].f3, alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(4) } } + { excelCell: { value: ds[0].f1, alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } }, + { excelCell: { value: ds[0].f2, alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(3) } }, + { excelCell: { value: ds[0].f3, alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(4) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 4, column: 3 }, { row: 4, column: 3 }, topLeft); helper.checkAutoFilter(autoFilterEnabled, { from: topLeft, to: { row: topLeft.row + 3, column: topLeft.column + 2 } }, { state: 'frozen', ySplit: topLeft.row + 2 }); helper.checkColumnWidths([excelColumnWidthFromColumn150Pixels, excelColumnWidthFromColumn200Pixels, excelColumnWidthFromColumn100Pixels], topLeft.column); @@ -6442,7 +6295,7 @@ const moduleConfig = { helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0, 0, 0], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 4, column: 3 }, topLeft); + helper.checkCellRange(cellRange, { row: 4, column: 3 }, topLeft); done(); }); }); @@ -6472,22 +6325,22 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: 'Band1', master: [1, 1], alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } }, - { excelCell: { value: 'Band1', master: [1, 1], alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } } + { excelCell: { value: 'Band1', master: [1, 1], alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } }, + { excelCell: { value: 'Band1', master: [1, 1], alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } } ], [ - { excelCell: { value: 'Band1_1', master: [2, 1], alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(1) } }, - { excelCell: { value: 'Band1_1', master: [2, 1], alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(1) } } + { excelCell: { value: 'Band1_1', master: [2, 1], alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(1) } }, + { excelCell: { value: 'Band1_1', master: [2, 1], alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(1) } } ], [ - { excelCell: { value: 'F1', alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(2) } }, - { excelCell: { value: 'F2', alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(3) } } + { excelCell: { value: 'F1', alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(2) } }, + { excelCell: { value: 'F2', alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(3) } } ], [ - { excelCell: { value: ds[0].f1, alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } }, - { excelCell: { value: ds[0].f2, alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(3) } } + { excelCell: { value: ds[0].f1, alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } }, + { excelCell: { value: ds[0].f2, alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(3) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 4, column: 2 }, { row: 4, column: 2 }, topLeft); helper.checkAutoFilter(autoFilterEnabled, { from: topLeft, to: { row: topLeft.row + 3, column: topLeft.column + 1 } }, { state: 'frozen', ySplit: topLeft.row + 2 }); helper.checkColumnWidths([excelColumnWidthFromColumn150Pixels, excelColumnWidthFromColumn200Pixels], topLeft.column); @@ -6496,7 +6349,7 @@ const moduleConfig = { helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0, 0, 0], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 4, column: 2 }, topLeft); + helper.checkCellRange(cellRange, { row: 4, column: 2 }, topLeft); done(); }); }); @@ -6526,22 +6379,22 @@ const moduleConfig = { }).dxDataGrid('instance'); const expectedCells = [[ - { excelCell: { value: 'Band1', master: [1, 1], alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } }, - { excelCell: { value: 'Band1', master: [1, 1], alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } } + { excelCell: { value: 'Band1', master: [1, 1], alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } }, + { excelCell: { value: 'Band1', master: [1, 1], alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(0) } } ], [ - { excelCell: { value: 'Band1_1', master: [2, 1], alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(1) } }, - { excelCell: { value: 'Band1_1', master: [2, 1], alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(1) } } + { excelCell: { value: 'Band1_1', master: [2, 1], alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(1) } }, + { excelCell: { value: 'Band1_1', master: [2, 1], alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(1) } } ], [ - { excelCell: { value: 'F1', alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(2) } }, - { excelCell: { value: 'F2', alignment: alignCenterWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(3) } } + { excelCell: { value: 'F1', alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(2) } }, + { excelCell: { value: 'F2', alignment: alignCenterTopNoWrap, font: { bold: true } }, gridCell: { rowType: 'header', column: dataGrid.columnOption(3) } } ], [ - { excelCell: { value: ds[0].f1, alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } }, - { excelCell: { value: ds[0].f2, alignment: alignLeftNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(3) } } + { excelCell: { value: ds[0].f1, alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(2) } }, + { excelCell: { value: ds[0].f2, alignment: alignLeftTopNoWrap }, gridCell: { rowType: 'data', data: ds[0], column: dataGrid.columnOption(3) } } ]]; helper._extendExpectedCells(expectedCells, topLeft); - exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellsRange) => { + exportDataGrid(getOptions(this, dataGrid, expectedCells)).then((cellRange) => { helper.checkRowAndColumnCount({ row: 4, column: 2 }, { row: 4, column: 2 }, topLeft); helper.checkAutoFilter(autoFilterEnabled, { from: topLeft, to: { row: topLeft.row + 3, column: topLeft.column + 1 } }, { state: 'frozen', ySplit: topLeft.row + 2 }); helper.checkColumnWidths([excelColumnWidthFromColumn150Pixels, excelColumnWidthFromColumn200Pixels], topLeft.column); @@ -6550,7 +6403,7 @@ const moduleConfig = { helper.checkValues(expectedCells); helper.checkMergeCells(expectedCells, topLeft); helper.checkOutlineLevel([0, 0, 0], topLeft.row); - helper.checkCellsRange(cellsRange, { row: 4, column: 2 }, topLeft); + helper.checkCellRange(cellRange, { row: 4, column: 2 }, topLeft); done(); }); }); @@ -6585,19 +6438,12 @@ QUnit.module('_getFullOptions', () => { }); QUnit.test('autoFilterEnabled', function(assert) { - function _getComponent(exportExcelFilterEnabled) { return { option: function() { return exportExcelFilterEnabled; } }; } - - assert.deepEqual(_getFullOptions({ component: _getComponent(undefined) }).autoFilterEnabled, false, 'no member && grid.exportExcelFilterEnabled: undefined'); - assert.deepEqual(_getFullOptions({ component: _getComponent(false) }).autoFilterEnabled, false, 'no member && grid.exportExcelFilterEnabled: false'); - assert.deepEqual(_getFullOptions({ component: _getComponent(true) }).autoFilterEnabled, true, 'no member && grid.exportExcelFilterEnabled: true'); - - assert.deepEqual(_getFullOptions({ autoFilterEnabled: false, component: _getComponent(undefined) }).autoFilterEnabled, false, 'false && grid.exportExcelFilterEnabled: undefined'); - assert.deepEqual(_getFullOptions({ autoFilterEnabled: false, component: _getComponent(false) }).autoFilterEnabled, false, 'false && grid.exportExcelFilterEnabled: false'); - assert.deepEqual(_getFullOptions({ autoFilterEnabled: false, component: _getComponent(true) }).autoFilterEnabled, false, 'false && grid.exportExcelFilterEnabled: true'); + assert.deepEqual(_getFullOptions({}).autoFilterEnabled, false, 'no member'); + assert.deepEqual(_getFullOptions({ autoFilterEnabled: undefined }).autoFilterEnabled, false, 'undefined'); + assert.deepEqual(_getFullOptions({ autoFilterEnabled: null }).autoFilterEnabled, false, 'null'); - assert.deepEqual(_getFullOptions({ autoFilterEnabled: true, component: _getComponent(undefined) }).autoFilterEnabled, true, 'true && grid.exportExcelFilterEnabled: undefined'); - assert.deepEqual(_getFullOptions({ autoFilterEnabled: true, component: _getComponent(false) }).autoFilterEnabled, true, 'true && grid.exportExcelFilterEnabled: false'); - assert.deepEqual(_getFullOptions({ autoFilterEnabled: true, component: _getComponent(true) }).autoFilterEnabled, true, 'true && grid.exportExcelFilterEnabled: true'); + assert.deepEqual(_getFullOptions({ autoFilterEnabled: false }).autoFilterEnabled, false, 'false'); + assert.deepEqual(_getFullOptions({ autoFilterEnabled: true }).autoFilterEnabled, true, 'true'); }); QUnit.test('loadPanel', function(assert) { diff --git a/testing/tests/DevExpress.knockout/form.tests.js b/testing/tests/DevExpress.knockout/form.tests.js index 0e35569f8ddb..961ad9730fe6 100644 --- a/testing/tests/DevExpress.knockout/form.tests.js +++ b/testing/tests/DevExpress.knockout/form.tests.js @@ -5,6 +5,7 @@ import fx from 'animation/fx'; import 'ui/text_area'; import 'ui/select_box'; +import 'ui/tag_box'; import 'integration/knockout'; QUnit.testStart(() => { @@ -46,7 +47,6 @@ const moduleSetup = { } }; - QUnit.module('Knockout integration', moduleSetup); QUnit.test('Generate items from layoutData with unacceptable data', function(assert) { @@ -95,6 +95,32 @@ QUnit.test('Change formData -> observable value changed', function(assert) { assert.equal(viewModel.formData.famousPirate(), 'Cpt. Jack Sparrow', 'Values is synchronized'); }); +QUnit.test('Change formData -> observable array changed', function(assert) { + const itemsData = ko.observableArray([]); + const viewModel = { + formData: { + items: itemsData + }, + items: [{ + dataField: 'items', + editorType: 'dxTagBox', + editorOptions: { + dataSource: ['item1', 'items2'] + } + }] + }; + + const $form = $('#formWithItems'); + ko.applyBindings(viewModel, $form.get(0)); + + const form = $form.dxForm('instance'); + const tagBox = form.getEditor('items'); + + tagBox.option('value', ['item2']); + + assert.deepEqual(itemsData(), ['item2'], 'value of the observable array'); +}); + QUnit.test('Change observable -> formData changed', function(assert) { const viewModel = { formData: @@ -121,6 +147,32 @@ QUnit.test('Change observable -> formData changed', function(assert) { assert.equal(viewModel.formData.famousPirate(), 'Cpt. Jack Sparrow', 'famousPirate is changed'); }); +QUnit.test('Change observable array -> formData changed', function(assert) { + const itemsData = ko.observableArray([]); + const viewModel = { + formData: { + items: itemsData + }, + items: [{ + dataField: 'items', + editorType: 'dxTagBox', + editorOptions: { + dataSource: ['item1', 'items2'] + } + }] + }; + + const $form = $('#formWithItems'); + ko.applyBindings(viewModel, $form.get(0)); + + itemsData(['item2']); + + const form = $form.dxForm('instance'); + const tagBox = form.getEditor('items'); + + assert.deepEqual(tagBox.option('value'), ['item2'], 'value of the TagBox'); +}); + QUnit.test('Must unwrap visible option when render', function(assert) { const viewModel = { formOptions: { @@ -148,7 +200,6 @@ QUnit.test('Must unwrap visible option when render', function(assert) { assert.equal($form.find(visibleEditorSelector).length, 2, 'Both editors are visible'); }); - QUnit.test('Change formData field and other observable', function(assert) { const viewModel = { formData: @@ -417,7 +468,6 @@ QUnit.test('Form is not crashed when numberbox is used (T369550)', function(asse assert.ok(true, 'error is not threw'); }); - QUnit.test('Form items should have correct model', function(assert) { assert.expect(1); const viewModel = { diff --git a/testing/tests/DevExpress.localization/localization.globalize.widgets.tests.js b/testing/tests/DevExpress.localization/localization.globalize.widgets.tests.js index d894398dea69..c157dba2d9db 100644 --- a/testing/tests/DevExpress.localization/localization.globalize.widgets.tests.js +++ b/testing/tests/DevExpress.localization/localization.globalize.widgets.tests.js @@ -86,6 +86,28 @@ QUnit.test('DateBox should localize whole date in arabic locale', function(asser } }); +QUnit.test('DateBox should not raise error when digits are not default arabic digits', function(assert) { + const originalCulture = Globalize.locale().locale; + + try { + Globalize.locale('ar'); + + const $dateBox = $('#dateBox').dxDateBox({ + value: new Date(2015, 10, 10), + type: 'date', + pickerType: 'calendar', + useMaskBehavior: true + }); + + const date = $dateBox.find(TEXTEDITOR_INPUT_SELECTOR).val(); + assert.equal(date, '١٠/١١/٢٠١٥', 'date is localized'); + } catch(e) { + assert.ok(false, 'Error occured: ' + e.message); + } finally { + Globalize.locale(originalCulture); + } +}); + QUnit.test('dxDateBox rollers localize years and days', function(assert) { const originalCulture = Globalize.locale().locale; diff --git a/testing/tests/DevExpress.localization/localization.intl.tests.js b/testing/tests/DevExpress.localization/localization.intl.tests.js index 17a18f56f10b..41104fdce8b7 100644 --- a/testing/tests/DevExpress.localization/localization.intl.tests.js +++ b/testing/tests/DevExpress.localization/localization.intl.tests.js @@ -1,3 +1,4 @@ +import Intl from 'intl'; import sharedTests from './sharedParts/localization.shared.js'; import dateLocalization from 'localization/date'; import numberLocalization from 'localization/number'; diff --git a/testing/tests/DevExpress.localization/localization.intl.widgets.tests.js b/testing/tests/DevExpress.localization/localization.intl.widgets.tests.js new file mode 100644 index 000000000000..74c99b602ace --- /dev/null +++ b/testing/tests/DevExpress.localization/localization.intl.widgets.tests.js @@ -0,0 +1,46 @@ +import 'intl'; +import 'localization/date'; +import 'localization/number'; +import { locale } from 'localization/core'; + +import $ from 'jquery'; +import 'ui/date_box'; + +const TEXTEDITOR_INPUT_SELECTOR = '.dx-texteditor-input'; + +const commonEnvironment = { + beforeEach: function() { + const markup = '
'; + + $('#qunit-fixture').append(markup); + }, + + afterEach: function() { + $('#qunit-fixture').empty(); + } +}; + + +QUnit.module('Intl localization', () => { + QUnit.module('DateBox', commonEnvironment, () => { + QUnit.test('DateBox should not raise error when digits are not default arabic digits', function(assert) { + const currentLocale = locale(); + try { + locale('ar-u-nu-arab'); + const $dateBox = $('#dateBox').dxDateBox({ + value: new Date(2015, 10, 10), + type: 'date', + pickerType: 'calendar', + useMaskBehavior: true + }); + + const date = $dateBox.find(TEXTEDITOR_INPUT_SELECTOR).val(); + assert.equal(date, '١٠/١١/٢٠١٥', 'date is localized'); + } catch(e) { + assert.ok(false, 'Error occured: ' + e.message); + } finally { + locale(currentLocale); + } + }); + }); +}); diff --git a/testing/tests/DevExpress.serverSide/diagram.tests.js b/testing/tests/DevExpress.serverSide/diagram.tests.js new file mode 100644 index 000000000000..eb389507dc88 --- /dev/null +++ b/testing/tests/DevExpress.serverSide/diagram.tests.js @@ -0,0 +1,30 @@ +import $ from 'jquery'; +import 'ui/diagram'; +import 'common.css!'; + +QUnit.testStart(function() { + const markup = + '
'; + + $('#qunit-fixture').html(markup); +}); + +const DIAGRAM_CLASS = 'dx-diagram'; +const DIAGRAM_CORE_CLASS = 'dxdi-control'; + +QUnit.module('rendering', { + beforeEach: function() { + this.element = $('
').appendTo('body'); + }, + afterEach: function() { + this.element.remove(); + } +}, () => { + QUnit.test('base elements should be rendered correctly', function(assert) { + const $element = this.element.dxDiagram(); + + assert.ok($element.hasClass(DIAGRAM_CLASS), 'Element has a widget-specific class'); + assert.equal($element.find('.' + DIAGRAM_CORE_CLASS).length, 0, 'Diagram core must not be created in server-side'); + }); +}); + diff --git a/testing/tests/DevExpress.ui.events/drag.tests.js b/testing/tests/DevExpress.ui.events/drag.tests.js index f7f625417c3c..2d0cb356c479 100644 --- a/testing/tests/DevExpress.ui.events/drag.tests.js +++ b/testing/tests/DevExpress.ui.events/drag.tests.js @@ -61,7 +61,7 @@ QUnit.test('dragstart should be fired', function(assert) { const pointer = pointerMock($element); $element.on(dragEvents.start, function(e) { - assert.ok(e.target === $element[0]); + assert.strictEqual(e.target, $element[0]); }); pointer.start().down().move(10).up(); @@ -86,7 +86,7 @@ QUnit.test('drag should be fired', function(assert) { let lastDragOffset; $element.on(dragEvents.move, function(e) { - assert.ok(e.target === $element[0]); + assert.strictEqual(e.target, $element[0]); lastDragOffset = e.offset; }); @@ -112,7 +112,7 @@ QUnit.test('dragend should be fired', function(assert) { const pointer = pointerMock($element); $element.on(dragEvents.end, function(e) { - assert.ok(e.target === $element[0]); + assert.strictEqual(e.target, $element[0]); assert.deepEqual(e.offset, { x: 10, diff --git a/testing/tests/DevExpress.ui.events/eventsInteraction.tests.js b/testing/tests/DevExpress.ui.events/eventsInteraction.tests.js index 49f7d2560c04..72aa02dd1c53 100644 --- a/testing/tests/DevExpress.ui.events/eventsInteraction.tests.js +++ b/testing/tests/DevExpress.ui.events/eventsInteraction.tests.js @@ -15,6 +15,8 @@ const dragEvents = require('events/drag'); const dblclickEvent = require('events/dblclick'); const pointerMock = require('../../helpers/pointerMock.js'); +const GESTURE_COVER_CLASS = 'dx-gesture-cover'; + QUnit.testStart(function() { const markup = '
\ @@ -36,7 +38,6 @@ const moduleConfig = { GestureEmitter.touchBoundary(GestureEmitter.initialTouchBoundary); - QUnit.module('events unsubscribing', { beforeEach: function() { @@ -281,134 +282,6 @@ QUnit.test('minimum distance for gesture should be 10 pixels', function(assert) assert.ok(scrollStarted, 'scroll started'); }); -const GESTURE_COVER_CLASS = 'dx-gesture-cover'; -const $gestureCover = $('.' + GESTURE_COVER_CLASS); - -const gestureCoverExists = function() { - return devices.real().deviceType === 'desktop' && $gestureCover.css('pointerEvents') !== undefined; -}; - -QUnit.test('wheel should be prevented on gesture cover (T319068)', function(assert) { - if(!gestureCoverExists()) { - assert.expect(0); - return; - } - - const event = $.Event('dxmousewheel'); - $('.' + GESTURE_COVER_CLASS).trigger(event); - assert.equal(event.isDefaultPrevented(), true, 'scroll prevented'); -}); - -QUnit.test('selection shouldn\'t be prevented in native scroll', function(assert) { - if(!gestureCoverExists()) { - assert.expect(0); - return; - } - - const $element = $('#element'); - const pointer = pointerMock($element); - - $element.on('dxscrollstart', { isNative: true }, $.noop); - - pointer.start().down().move(20); - assert.equal($gestureCover.css('pointerEvents'), 'none', 'gestureCover is disabled'); -}); - -$.each([ - ['hover', 'pointer-events', 'all', true], - ['cursor', 'cursor', 'move', false] -], function(_, config) { - const name = config[0]; - const prop = config[1]; - const propValue = config[2]; - const needReset = config[3]; - - if(!gestureCoverExists()) { - return; - } - - QUnit.test('gesture should set ' + name + ' if needed with pointer', function(assert) { - assert.expect(2); - - const originalProp = $gestureCover.css(prop); - const $element = $('#element'); - const pointer = pointerMock($element); - - $element.on({ - 'dxscrollstart': function(e) { - assert.equal($gestureCover.css(prop), propValue, name + ' is disabled'); - }, - 'dxscrollend': function() { - assert.equal($gestureCover.css(prop), needReset ? originalProp : propValue, name + ' is enabled'); - } - }); - - pointer.start().down().move(20).up(); - }); - - QUnit.test('gesture should set ' + name + ' if needed with mousewheel', function(assert) { - assert.expect(2); - - const originalProp = $gestureCover.css(prop); - const $element = $('#element'); - const pointer = pointerMock($element); - - $element.on({ - 'dxscrollstart': function(e) { - assert.equal($gestureCover.css(prop), propValue, name + ' is disabled'); - }, - 'dxscrollend': function() { - assert.equal($gestureCover.css(prop), needReset ? originalProp : propValue, name + ' is enabled'); - } - }); - - pointer.start().wheel(20); - }); - - QUnit.test('cancel gesture should reset ' + name + ' on desktop', function(assert) { - const originalProp = $gestureCover.css(prop); - const $element = $('#element'); - const pointer = pointerMock($element); - - $element.on({ - 'dxscrollstart': function(e) { - e.cancel = true; - } - }); - - pointer.start().down().move(20).up(); - assert.equal($gestureCover.css(prop), needReset ? originalProp : propValue, name + ' is enabled'); - }); - - QUnit.test('dispose gesture should reset ' + name + ' if locked by current emitter', function(assert) { - const originalProp = $gestureCover.css(prop); - const $element = $('#element'); - const pointer = pointerMock($element); - - $element.on({ - 'dxscrollstart.TEST': noop - }); - - pointer.start().down().move(20); - $element.off('.TEST'); - assert.equal($gestureCover.css(prop), needReset ? originalProp : propValue, name + ' is enabled'); - }); - - QUnit.test('dispose gesture should not reset ' + name + ' if locked by another emitter', function(assert) { - const $child = $('#child'); - const $parent = $('#parent'); - const pointer = pointerMock($child); - - $child.on('dxscrollstart', noop); - $parent.on('dxscrollstart.TEST', noop); - - pointer.start().down().move(20); - const assignedProp = $gestureCover.css(prop); - $parent.off('.TEST'); - assert.equal($gestureCover.css(prop), assignedProp, name + ' is enabled'); - }); -}); - QUnit.test('gesture should be canceled if event should be skipped', function(assert) { assert.expect(1); @@ -1129,3 +1002,130 @@ QUnit.test('active emitter should not be reset if inactive emitter was unsubscri pointer.up(); }); + +QUnit.module('gesture cover', { + before: function() { + const $element = $('#element'); + const pointer = pointerMock($element); + + $element.on('dxscrollstart', noop); + pointer.start().down().move(20).up(); + $element.off('dxscrollstart'); + } +}, function() { + const getGestureCover = () => $(`.${GESTURE_COVER_CLASS}`); + + if(devices.real().deviceType === 'desktop') { + QUnit.test('wheel should be prevented on gesture cover (T319068)', function(assert) { + const event = $.Event('dxmousewheel'); + getGestureCover().trigger(event); + assert.equal(event.isDefaultPrevented(), true, 'scroll prevented'); + }); + + QUnit.test('selection shouldn\'t be prevented in native scroll', function(assert) { + const $element = $('#element'); + const pointer = pointerMock($element); + + $element.on('dxscrollstart', { isNative: true }, noop); + + pointer.start().down().move(20); + assert.equal(getGestureCover().css('pointerEvents'), 'none', 'gestureCover is disabled'); + }); + + $.each([ + ['hover', 'pointer-events', 'all', true], + ['cursor', 'cursor', 'move', false] + ], function(_, config) { + const name = config[0]; + const prop = config[1]; + const propValue = config[2]; + const needReset = config[3]; + + QUnit.test('gesture should set ' + name + ' if needed with pointer', function(assert) { + assert.expect(2); + + const $gestureCover = getGestureCover(); + const originalProp = $gestureCover.css(prop); + const $element = $('#element'); + const pointer = pointerMock($element); + + $element.on({ + 'dxscrollstart': function(e) { + assert.equal($gestureCover.css(prop), propValue, name + ' is disabled'); + }, + 'dxscrollend': function() { + assert.equal($gestureCover.css(prop), needReset ? originalProp : propValue, name + ' is enabled'); + } + }); + + pointer.start().down().move(20).up(); + }); + + QUnit.test('gesture should set ' + name + ' if needed with mousewheel', function(assert) { + assert.expect(2); + + const $gestureCover = getGestureCover(); + const originalProp = $gestureCover.css(prop); + const $element = $('#element'); + const pointer = pointerMock($element); + + $element.on({ + 'dxscrollstart': function(e) { + assert.equal($gestureCover.css(prop), propValue, name + ' is disabled'); + }, + 'dxscrollend': function() { + assert.equal($gestureCover.css(prop), needReset ? originalProp : propValue, name + ' is enabled'); + } + }); + + pointer.start().wheel(20); + }); + + QUnit.test('cancel gesture should reset ' + name + ' on desktop', function(assert) { + const $gestureCover = getGestureCover(); + const originalProp = $gestureCover.css(prop); + const $element = $('#element'); + const pointer = pointerMock($element); + + $element.on({ + 'dxscrollstart': function(e) { + e.cancel = true; + } + }); + + pointer.start().down().move(20).up(); + assert.equal($gestureCover.css(prop), needReset ? originalProp : propValue, name + ' is enabled'); + }); + + QUnit.test('dispose gesture should reset ' + name + ' if locked by current emitter', function(assert) { + const $gestureCover = getGestureCover(); + const originalProp = $gestureCover.css(prop); + const $element = $('#element'); + const pointer = pointerMock($element); + + $element.on({ + 'dxscrollstart.TEST': noop + }); + + pointer.start().down().move(20); + $element.off('.TEST'); + assert.equal($gestureCover.css(prop), needReset ? originalProp : propValue, name + ' is enabled'); + }); + + QUnit.test('dispose gesture should not reset ' + name + ' if locked by another emitter', function(assert) { + const $gestureCover = getGestureCover(); + const $child = $('#child'); + const $parent = $('#parent'); + const pointer = pointerMock($child); + + $child.on('dxscrollstart', noop); + $parent.on('dxscrollstart.TEST', noop); + + pointer.start().down().move(20); + const assignedProp = $gestureCover.css(prop); + $parent.off('.TEST'); + assert.equal($gestureCover.css(prop), assignedProp, name + ' is enabled'); + }); + }); + } +}); diff --git a/testing/tests/DevExpress.ui.widgets.dataGrid/adaptiveColumns.tests.js b/testing/tests/DevExpress.ui.widgets.dataGrid/adaptiveColumns.tests.js index f5131fa0cbd7..4b144922a8ea 100644 --- a/testing/tests/DevExpress.ui.widgets.dataGrid/adaptiveColumns.tests.js +++ b/testing/tests/DevExpress.ui.widgets.dataGrid/adaptiveColumns.tests.js @@ -486,7 +486,7 @@ QUnit.test('Show the form when an adaptive row is expanded', function(assert) { // assert const form = $('.dx-master-detail-row .dx-form').dxForm('instance'); - assert.ok(form !== undefined, 'form is initialized'); + assert.notStrictEqual(form, undefined, 'form is initialized'); assert.equal(form.option('items')[0].column.dataField, 'lastName', 'dataField of column'); assert.equal(form.option('items')[0].dataField, 'lastName', 'dataField of item'); assert.equal($('.dx-field-item-content').text(), 'Psy', 'text of item'); @@ -771,7 +771,7 @@ QUnit.test('Show the form with cellTemplate when an adaptive row is expanded', f // assert const form = $('.dx-master-detail-row .dx-form').dxForm('instance'); - assert.ok(form !== undefined, 'form is initialized'); + assert.notStrictEqual(form, undefined, 'form is initialized'); assert.equal(form.option('items')[0].column.dataField, 'lastName', 'dataField of column'); assert.equal(form.option('items')[0].dataField, 'lastName', 'dataField of item'); assert.equal($('.dx-field-item-content').text(), 'Psy template', 'template text of item'); @@ -1823,6 +1823,44 @@ QUnit.test('The adaptive cell should be empty in a grouped row with a summary', assert.strictEqual($(this.rowsView.getRowElement(0)).children('.dx-command-adaptive').html(), ' ', 'adaptive cell'); }); +// T857506 +QUnit.test('The group cell content should not be hidden when the hidingPriority property is specified for a first column', function(assert) { + // arrange, act + $('.dx-datagrid').width(400); + this.items = [ + { firstName: 'Blablablablablablablablablabla', lastName: 'Psy', sex: true }, + { firstName: 'Super', lastName: 'Star', sex: false } + ]; + this.options = { + columns: [ + { dataField: 'firstName', hidingPriority: 1 }, + { dataField: 'lastName', groupIndex: 0 }, + { dataField: 'sex' } + ], + grouping: { + autoExpandAll: true + } + }; + setupDataGrid(this); + this.rowsView.render($('#container')); + this.resizingController.updateDimensions(); + + // assert + let $rowElement = $(this.getRowElement(0)); + let $cellElements = $rowElement.children(); + + assert.ok($rowElement.hasClass('dx-group-row'), 'group row'); + assert.ok($cellElements.eq(1).hasClass('dx-group-cell'), 'group cell'); + assert.notOk($cellElements.eq(1).hasClass('dx-datagrid-hidden-column'), 'group cell content is visible'); + + $rowElement = $(this.getRowElement(1)); + $cellElements = $rowElement.children(); + + assert.ok($rowElement.hasClass('dx-data-row'), 'data row'); + assert.ok($cellElements.eq(1).hasClass('dx-datagrid-hidden-column'), 'firstName column is hidden'); +}); + + QUnit.module('API', { beforeEach: function() { this.clock = sinon.useFakeTimers(); @@ -2033,7 +2071,7 @@ QUnit.test('Hide the adaptive and master detail row', function(assert) { // assert assert.equal($rows.length, 1, 'master detail rows count'); - assert.ok($rows.eq(0).css('display') === 'none', 'master detail row'); + assert.strictEqual($rows.eq(0).css('display'), 'none', 'master detail row'); }); QUnit.test('Expand adaptive row when row as tbody', function(assert) { @@ -2099,13 +2137,13 @@ QUnit.test('Edit form. Check that adaptive form is hidden', function(assert) { this.clock.tick(); let adaptiveDetailForm = $('.dx-adaptive-detail-row .dx-form').dxForm('instance'); - assert.ok(adaptiveDetailForm !== undefined, 'adaptive detail form is initialized'); + assert.notStrictEqual(adaptiveDetailForm, undefined, 'adaptive detail form is initialized'); this.editingController.editRow(0); this.clock.tick(); adaptiveDetailForm = $('.dx-adaptive-detail-row .dx-form').dxForm('instance'); - assert.ok(adaptiveDetailForm === undefined, 'adaptive detail form is not initialized'); + assert.strictEqual(adaptiveDetailForm, undefined, 'adaptive detail form is not initialized'); }); // T458653 @@ -2213,9 +2251,9 @@ QUnit.test('Edit row', function(assert) { const editor1 = $editors.eq(0).dxTextBox('instance'); const editor2 = $editors.eq(2).dxTextBox('instance'); - assert.ok(form !== undefined, 'form is initialized'); - assert.equal($editors.length, 3, 'editors count'); - assert.equal(editor2.option('value'), 'Psy', 'editor\'s value'); + assert.notStrictEqual(form, undefined, 'form is initialized'); + assert.strictEqual($editors.length, 3, 'editors count'); + assert.strictEqual(editor2.option('value'), 'Psy', 'editor\'s value'); // act editor1.option('value', 'Man'); @@ -2226,7 +2264,7 @@ QUnit.test('Edit row', function(assert) { form = $('.dx-master-detail-row .dx-form').dxForm('instance'); $editors = $('.dx-texteditor'); - assert.ok(form === undefined, 'form is not initialized'); + assert.strictEqual(form, undefined, 'form is not initialized'); assert.equal($editors.length, 0, 'editors count'); assert.equal($('.dx-editor-cell').length, 0, 'the editor cell class is not applied'); }); @@ -2338,7 +2376,7 @@ QUnit.test('Edit row. Check repeat edit', function(assert) { form = $('.dx-master-detail-row .dx-form').dxForm('instance'); $editors = $('.dx-texteditor'); - assert.ok(form !== undefined, 'form is initialized'); + assert.notStrictEqual(form, undefined, 'form is initialized'); assert.equal($editors.length, 3, 'editors count'); }); @@ -2403,7 +2441,7 @@ QUnit.test('Edit row. Editor is not rendered inside the form widget when clicked $($itemContent).trigger('dxclick'); // assert - assert.ok(form !== undefined, 'form is initialized'); + assert.notStrictEqual(form, undefined, 'form is initialized'); assert.equal($('.dx-texteditor').length, 0, 'editors count'); }); @@ -2513,7 +2551,7 @@ QUnit.test('Edit row. Editors are rendered inside the form widget when the adapt const form = $('.dx-master-detail-row .dx-form').dxForm('instance'); // assert - assert.ok(form !== undefined, 'form is initialized'); + assert.notStrictEqual(form, undefined, 'form is initialized'); assert.equal($('.dx-texteditor').length, 3, 'editors count'); }); diff --git a/testing/tests/DevExpress.ui.widgets.dataGrid/columnsResizingReorderingModule.tests.js b/testing/tests/DevExpress.ui.widgets.dataGrid/columnsResizingReorderingModule.tests.js index d47003cd68f5..84630dd5e585 100644 --- a/testing/tests/DevExpress.ui.widgets.dataGrid/columnsResizingReorderingModule.tests.js +++ b/testing/tests/DevExpress.ui.widgets.dataGrid/columnsResizingReorderingModule.tests.js @@ -1474,7 +1474,7 @@ function getEvent(options) { })); // assert - assert.ok(resizeController._columnsController.updateOptions.length === 0, 'cancel moving'); + assert.strictEqual(resizeController._columnsController.updateOptions.length, 0, 'cancel moving'); }); QUnit.test('Headers element is null in startResizing_B239012', function(assert) { @@ -1560,7 +1560,7 @@ function getEvent(options) { this.renderViews($container); // assert - assert.ok($container.find('.dx-datagrid-columns-separator').length === 0, 'columnsSeparator is null'); + assert.strictEqual($container.find('.dx-datagrid-columns-separator').length, 0, 'columnsSeparator is null'); }); QUnit.test('Update height of separator when caption of header is wrapped', function(assert) { @@ -2323,7 +2323,7 @@ function getEvent(options) { // assert assert.ok(isPointsUpdated, 'points by columns is updated'); assert.ok(!resizeController._columnsSeparatorView._isShown, 'columnsSeparator is hidden'); - assert.ok(resizeController._columnsSeparatorView._testCursorName === '', 'cursor is down'); + assert.strictEqual(resizeController._columnsSeparatorView._testCursorName, '', 'cursor is down'); assert.ok(!resizeController._isResizing, 'columnsResizer is not resized'); assert.ok(!resizeController._isReadyResizing, 'columnsResizer is not ready resized'); }); @@ -3360,7 +3360,7 @@ function getEvent(options) { $draggingHeader = testElement.find('.dx-datagrid-drag-header'); // assert - assert.ok($draggingHeader.length === 1, 'draggingHeader element'); + assert.strictEqual($draggingHeader.length, 1, 'draggingHeader element'); assert.strictEqual($draggingHeader.css('display'), 'none', 'display is none'); assert.ok($draggingHeader.hasClass('dx-widget'), 'Widget class'); }); @@ -3384,7 +3384,7 @@ function getEvent(options) { $draggingHeader = testElement.find('.dx-datagrid-drag-header'); // assert - assert.ok($draggingHeader.length === 1, 'draggingHeader element'); + assert.strictEqual($draggingHeader.length, 1, 'draggingHeader element'); assert.strictEqual($draggingHeader.css('display'), 'none', 'display is none'); }); @@ -3407,7 +3407,7 @@ function getEvent(options) { $draggingHeader = testElement.find('.dx-datagrid-drag-header'); // assert - assert.ok($draggingHeader.length === 1, 'draggingHeader element'); + assert.strictEqual($draggingHeader.length, 1, 'draggingHeader element'); assert.strictEqual($draggingHeader.css('display'), 'none', 'display is none'); }); @@ -4523,15 +4523,15 @@ function getEvent(options) { // assert assert.equal(moveHeaderDataSelfArgs.length, 1); - assert.ok(moveHeaderDataSelfArgs[0] === controller1._draggingHeaderView); + assert.strictEqual(moveHeaderDataSelfArgs[0], controller1._draggingHeaderView); // act $(controller2._columnHeadersView.element().find('td').first()).trigger(dragEvents.move + '.dxDataGridResizingReordering'); // assert assert.equal(moveHeaderDataSelfArgs.length, 2); - assert.ok(moveHeaderDataSelfArgs[0] === controller1._draggingHeaderView); - assert.ok(moveHeaderDataSelfArgs[1] === controller2._draggingHeaderView); + assert.strictEqual(moveHeaderDataSelfArgs[0], controller1._draggingHeaderView); + assert.strictEqual(moveHeaderDataSelfArgs[1], controller2._draggingHeaderView); }); QUnit.test('setRowsOpacity method of views should called only once for begin dragging', function(assert) { diff --git a/testing/tests/DevExpress.ui.widgets.dataGrid/dataGrid.export.customizeExcelCell.tests.js b/testing/tests/DevExpress.ui.widgets.dataGrid/dataGrid.export.customizeExcelCell.tests.js index d1b6a87c814a..ccb52b2a4680 100644 --- a/testing/tests/DevExpress.ui.widgets.dataGrid/dataGrid.export.customizeExcelCell.tests.js +++ b/testing/tests/DevExpress.ui.widgets.dataGrid/dataGrid.export.customizeExcelCell.tests.js @@ -24,7 +24,7 @@ QUnit.test('Check e.component', function(assert) { export: { customizeExcelCell: e => { assert.ok(isDefined(onCellPreparedComponent)); - assert.ok(e.component === onCellPreparedComponent); + assert.strictEqual(e.component, onCellPreparedComponent); } }, } diff --git a/testing/tests/DevExpress.ui.widgets.dataGrid/dataGrid.tests.js b/testing/tests/DevExpress.ui.widgets.dataGrid/dataGrid.tests.js index 7fe7096029e0..1570a3c878fe 100644 --- a/testing/tests/DevExpress.ui.widgets.dataGrid/dataGrid.tests.js +++ b/testing/tests/DevExpress.ui.widgets.dataGrid/dataGrid.tests.js @@ -75,6 +75,9 @@ import ajaxMock from '../../helpers/ajaxMock.js'; import themes from 'ui/themes'; import DataGridWrapper from '../../helpers/wrappers/dataGridWrappers.js'; import { checkDxFontIcon, DX_ICON_XLSX_FILE_CONTENT_CODE, DX_ICON_EXPORT_SELECTED_CONTENT_CODE } from '../../helpers/checkDxFontIconHelper.js'; +import 'ui/scroll_view'; +import { CLICK_EVENT } from '../../helpers/grid/keyboardNavigationHelper.js'; + const DX_STATE_HOVER_CLASS = 'dx-state-hover'; const TEXTEDITOR_INPUT_SELECTOR = '.dx-texteditor-input'; @@ -3819,7 +3822,7 @@ QUnit.test('Horizontal scrollbar is not displayed when columns width has float v const dataGrid = $dataGrid.dxDataGrid('instance'); // assert - assert.ok(dataGrid.getView('rowsView').getScrollbarWidth(true) === 0); + assert.strictEqual(dataGrid.getView('rowsView').getScrollbarWidth(true), 0); }); // T386755 @@ -4452,16 +4455,14 @@ QUnit.test('Cell should not be unfocused after click on it while editing with ro QUnit.test('onFocusedCellChanged event should contains correct row object if scrolling, rowRenderingMode are virtual', function(assert) { // arrange const data = []; - let dataGrid; let focusedCellChangedCount = 0; - let scrollable; for(let i = 0; i < 50; i++) { data.push({ id: i + 1 }); } // arrange - dataGrid = $('#dataGrid').dxDataGrid({ + const dataGrid = $('#dataGrid').dxDataGrid({ height: 150, keyExpr: 'id', dataSource: data, @@ -4484,11 +4485,11 @@ QUnit.test('onFocusedCellChanged event should contains correct row object if scr this.clock.tick(); // act - scrollable = dataGrid.getScrollable(); + const scrollable = dataGrid.getScrollable(); scrollable.scrollTo({ y: 600 }); $(scrollable._container()).trigger('scroll'); this.clock.tick(); - $(dataGrid.getCellElement(0, 0)).trigger(pointerEvents.up); + $(dataGrid.getCellElement(0, 0)).trigger(CLICK_EVENT); this.clock.tick(); // assert @@ -4554,9 +4555,9 @@ QUnit.test('Row should be focused after click on readonly cell if editor is open }).dxDataGrid('instance'); // act - $(dataGrid.getCellElement(0, 1)).trigger(pointerEvents.up); + $(dataGrid.getCellElement(0, 1)).trigger(CLICK_EVENT); dataGrid.editCell(0, 1); - $(dataGrid.getCellElement(1, 0)).trigger(pointerEvents.up); + $(dataGrid.getCellElement(1, 0)).trigger(CLICK_EVENT); // assert assert.equal(dataGrid.option('focusedRowIndex'), 1, 'focusedRowIndex'); @@ -4636,7 +4637,6 @@ QUnit.test('focusedRowKey should not overwrite dataSource field', function(asser QUnit.test('DataGrid should not scroll back to the focusedRow after paging if virtual scrolling (T718905, T719205)', function(assert) { // arrange - let isReady; const data = [ { name: 'Alex', phone: '111111', room: 6 }, { name: 'Dan', phone: '2222222', room: 5 }, @@ -4652,18 +4652,14 @@ QUnit.test('DataGrid should not scroll back to the focusedRow after paging if vi focusedRowEnabled: true, focusedRowIndex: 0, scrolling: { mode: 'virtual' }, - paging: { pageSize: 2 }, - onContentReady: function(e) { - if(!isReady) { - // act - e.component.pageIndex(1); - isReady = true; - } - } + paging: { pageSize: 2 } }).dxDataGrid('instance'); this.clock.tick(); + dataGrid.pageIndex(1); + this.clock.tick(); + // assert assert.equal(dataGrid.pageIndex(), 1, 'pageIndex'); }); @@ -4948,6 +4944,98 @@ QUnit.testInActiveWindow('Data cell in group column with showWhenGrouped=true sh assert.deepEqual(keyboardController._focusedCellPosition, { rowIndex: 1, columnIndex: 3 }, 'focused cell position'); }); +// T859208 +QUnit.test('Sort indicators should not be rendered if grouping is applied and showWhenGrouped = true (single sorting)', function(assert) { + // arrange + const dataGrid = $('#dataGrid').dxDataGrid({ + dataSource: [{ }], + sorting: { + mode: 'single' + }, + columns: [{ + dataField: 'field1' + }, { + dataField: 'field3', + sortOrder: 'desc', + showWhenGrouped: true + }], + groupPanel: { + visible: true + } + }).dxDataGrid('instance'); + + this.clock.tick(); + + // act + dataGrid.columnOption(1, 'groupIndex', 0); + this.clock.tick(); + + // assert + const $dataGrid = $(dataGrid.$element()); + const $headers = $dataGrid.find('.dx-header-row > td'); + const $groupPanelItem = $dataGrid.find('.dx-group-panel-item'); + + assert.notOk($headers.eq(2).find('.dx-sort').length, 'no element with dx-sort class'); + assert.notOk($headers.eq(2).find('.dx-sort-indicator').length, 'no element with dx-sort-indicator class'); + + assert.ok($groupPanelItem.find('.dx-sort').length, 'group item sort indicator'); + assert.notOk($groupPanelItem.find('.dx-sort-indicator').length, 'no element with dx-sort-indicator class'); +}); + +function groupingWithSortingTest(that, assert, sortIndexes) { + // arrange + const dataGrid = $('#dataGrid').dxDataGrid({ + dataSource: [{ }], + sorting: { + mode: 'multiple' + }, + columns: [{ + dataField: 'field1', + sortOrder: 'desc', + sortIndex: sortIndexes[0] + }, { + dataField: 'field3', + sortOrder: 'desc', + sortIndex: sortIndexes[1], + showWhenGrouped: true + }], + groupPanel: { + visible: true + } + }).dxDataGrid('instance'); + + that.clock.tick(); + + // act + dataGrid.columnOption(1, 'groupIndex', 0); + that.clock.tick(); + + // assert + const $dataGrid = $(dataGrid.$element()); + const $headers = $dataGrid.find('.dx-header-row > td'); + const $groupPanelItem = $dataGrid.find('.dx-group-panel-item'); + + assert.notOk($headers.eq(2).find('.dx-sort').length, 'no element with dx-sort class'); + assert.notOk($headers.eq(2).find('.dx-sort-indicator').length, 'no element with dx-sort-indicator class'); + assert.notOk($headers.eq(2).find('.dx-sort-index-indicator').length, 'no element with dx-sort-index-indicator class'); + + assert.ok($groupPanelItem.find('.dx-sort').length, 'group item sort indicator'); + assert.notOk($groupPanelItem.find('.dx-sort-indicator').length, 'no element with dx-sort-indicator class'); + assert.notOk($groupPanelItem.find('.dx-sort-index-indicator').length, 'no element with dx-sort-index-indicator class'); + + assert.equal($headers.eq(1).find('.dx-sort-index-icon').text(), `${sortIndexes[0] + 1}`, 'has sort index icon'); + assert.notOk($headers.eq(2).find('.dx-sort-index-icon').length, 'no sort index icon'); + assert.notOk($groupPanelItem.find('.dx-sort-index-icon').length, 'no sort index icon'); + + dataGrid.dispose(); +} + +// T859208 +QUnit.test('Sort indicators should not be rendered if grouping is applied and showWhenGrouped = true (multiple sorting)', function(assert) { + groupingWithSortingTest(this, assert, [0, 1]); + groupingWithSortingTest(this, assert, [1, 0]); +}); + QUnit.test('Enable rows hover via option method', function(assert) { if(devices.real().deviceType !== 'desktop') { assert.ok(true, 'hover is disabled for not desktop devices'); @@ -5824,6 +5912,21 @@ QUnit.test('max-height from styles', function(assert) { assert.ok($dataGrid.find('.dx-datagrid').height() < 400, 'height is less then max-height'); }); +// T849902 +QUnit.test('max-height as float number from styles', function(assert) { + // arrange, act + const dataGrid = $('#dataGrid').css('maxHeight', '100.2px').dxDataGrid({ + loadingTimeout: undefined, + dataSource: [{}, {}, {}, {}, {}, {}, {}, {}, {}, {}], + columns: ['field1'] + }).dxDataGrid('instance'); + + // assert + const scrollable = dataGrid.getScrollable(); + assert.ok(scrollable, 'scrollable is created'); + assert.ok(scrollable.$content().height() > scrollable._container().height(), 'scroll is exists'); +}); + // T820186 QUnit.test('width 100% should be applied if container width is zero on render', function(assert) { // arrange @@ -5937,7 +6040,7 @@ QUnit.test('native scrollBars layout should be correct after width change if fix assert.ok(dataGrid.getView('rowsView').getScrollbarWidth() > 0, 'vertical scrollBar exists'); } else { assert.equal($('#dataGrid').find('.dx-datagrid-content-fixed').eq(1).css('margin-right'), '0px', 'margin-right is zero'); - assert.ok(dataGrid.getView('rowsView').getScrollbarWidth() === 0, 'vertical scrollBar not exists'); + assert.strictEqual(dataGrid.getView('rowsView').getScrollbarWidth(), 0, 'vertical scrollBar not exists'); } assert.notEqual($('#dataGrid').find('.dx-datagrid-content-fixed').eq(1).css('margin-bottom'), '0px', 'margin-bottom is not zero'); }); @@ -7686,7 +7789,7 @@ QUnit.test('contentReady should not be raised on row click', function(assert) { assert.equal(contentReadyCallCount, 1, 'one contentReady on start'); // act - $(dataGrid.getCellElement(0, 0)).trigger(pointerEvents.up); + $(dataGrid.getCellElement(0, 0)).trigger(CLICK_EVENT); // assert assert.ok(dataGrid); @@ -7732,7 +7835,7 @@ QUnit.test('contentReady should not be raised on row click if focusedRowEnabled' assert.equal(contentReadyCallCount, 1, 'one contentReady on start'); // act - $(dataGrid.getCellElement(0, 0)).trigger(pointerEvents.up); + $(dataGrid.getCellElement(0, 0)).trigger(CLICK_EVENT); // assert assert.ok(dataGrid); @@ -7768,7 +7871,7 @@ QUnit.test('onFocusedRowChanged event should fire only once if paging and init p assert.equal(focusedRowChangedCallCount, 1, 'focusedRowChangedCallCount'); }); -QUnit.test('onFocusedRowChanged event should not fire on init if focusedRowEnabled is true and focusedRowIndex, focusedRowKey aren\'t set', function(assert) { +QUnit.test('onFocusedRowChanged event should not fire on init if focusedRowEnabled is true and focusedRowIndex, focusedRowKey are not set', function(assert) { let focusedRowChangedCallCount = 0; const dataGrid = createDataGrid({ onFocusedRowChanged: function() { @@ -7785,7 +7888,7 @@ QUnit.test('onFocusedRowChanged event should not fire on init if focusedRowEnabl assert.equal(focusedRowChangedCallCount, 0, 'focusedRowChangedCallCount'); // act - $(dataGrid.getCellElement(0, 0)).trigger(pointerEvents.up); + $(dataGrid.getCellElement(0, 0)).trigger(CLICK_EVENT); // assert assert.equal(focusedRowChangedCallCount, 1, 'focusedRowChangedCallCount'); }); @@ -7810,7 +7913,7 @@ QUnit.test('Click by the first row on the next page should focus it without grid sinon.spy(dataSource, 'load'); // act - $(dataGrid.getCellElement(2, 1)).trigger(pointerEvents.up); + $(dataGrid.getCellElement(2, 1)).trigger(CLICK_EVENT); // assert assert.equal(dataGrid.option('focusedRowIndex'), 2, 'focusedRowIndex'); @@ -9043,6 +9146,47 @@ QUnit.test('Editor should be rendered for hidden columns while editing in row mo }); }); +QUnit.test('Scrollable should have the correct padding when the grid inside the ScrollView', function(assert) { + // arrange, act + $('#container').dxScrollView({ + showScrollbar: 'always' + }); + const dataGrid = createDataGrid({ + dataSource: [{ field1: 1 }], + columnAutoWidth: true, + scrolling: { + showScrollbar: 'always' + } + }); + this.clock.tick(30); + + // assert + const $scrollableContent = $(dataGrid.getScrollable().content()); + assert.strictEqual($scrollableContent.css('paddingRight'), '0px', 'paddingRight'); + assert.strictEqual($scrollableContent.css('paddingLeft'), '0px', 'paddingLeft'); +}); + +QUnit.test('Scrollable should have the correct padding when the grid inside the ScrollView in RTL', function(assert) { + // arrange, act + $('#container').dxScrollView({ + showScrollbar: 'always' + }); + const dataGrid = createDataGrid({ + dataSource: [{ field1: 1 }], + columnAutoWidth: true, + rtlEnabled: true, + scrolling: { + showScrollbar: 'always' + } + }); + this.clock.tick(30); + + // assert + const $scrollableContent = $(dataGrid.getScrollable().content()); + assert.strictEqual($scrollableContent.css('paddingRight'), '0px', 'paddingRight'); + assert.strictEqual($scrollableContent.css('paddingLeft'), '0px', 'paddingLeft'); +}); + QUnit.module('Virtual row rendering', baseModuleConfig); QUnit.test('editing should starts correctly if scrolling mode is virtual', function(assert) { @@ -10020,6 +10164,51 @@ QUnit.test('cellTemplate should be rendered, asynchronously if column renderAsyn assert.equal(cellTemplateArgs[0].column.dataField, 'template', 'cell template column'); }); +// T857205 +QUnit.test(' if renderAsync is true and state storing is used', function(assert) { + let selectedRowKeys = [1, 2]; + + const customLoad = sinon.spy(() => { + return { + selectedRowKeys: selectedRowKeys + }; + }); + + // act + const grid = createDataGrid({ + dataSource: [{ id: 1 }, { id: 2 }, { id: 3 }], + keyExpr: 'id', + loadingTimeout: undefined, + renderAsync: true, + filterRow: { + visible: true + }, + selection: { + mode: 'multiple' + }, + stateStoring: { + enabled: true, + type: 'custom', + customLoad + } + }); + + const $grid = grid.$element(); + this.clock.tick(); + + const $selectCheckboxes = $grid.find('.dx-select-checkbox'); + const $inputs = $selectCheckboxes.find('input'); + + // assert + assert.equal(customLoad.callCount, 1, 'customLoad was called once'); + + assert.deepEqual(grid.getSelectedRowKeys(), selectedRowKeys, 'selected row keys'); + + assert.equal($inputs.eq(1).prop('value'), 'true', 'first row checkbox'); + assert.equal($inputs.eq(2).prop('value'), 'true', 'second row checkbox'); + assert.equal($inputs.eq(3).prop('value'), 'false', 'third row checkbox'); +}); + QUnit.module('Assign options', baseModuleConfig); // B232542 @@ -11642,7 +11831,7 @@ QUnit.test('Reset last non-command column width when width 100% in style', funct assert.equal($cols.length, 3); assert.equal($cols.get(0).style.width, '50px', 'first column width is not reset'); assert.equal($cols.get(1).style.width, 'auto', 'second column width is reset - this is last non-command column'); - assert.ok($cols.get(2).style.width !== 'auto', 'command column width is not reset'); + assert.notStrictEqual($cols.get(2).style.width, 'auto', 'command column width is not reset'); assert.equal($dataGrid.width(), $dataGrid.parent().width()); }); @@ -13882,7 +14071,7 @@ QUnit.test('Focused cell position has correct value when focus grouping row cell }; // act - $(dataGrid.getCellElement(2, 2)).trigger(pointerEvents.up); + $(dataGrid.getCellElement(2, 2)).trigger(CLICK_EVENT); assert.deepEqual(keyboardNavigationController._focusedCellPosition, { columnIndex: 2, @@ -13952,7 +14141,7 @@ QUnit.test('Focused cell position has correct value when focus grouping row with }; // act - $(dataGrid.getCellElement(1, 1)).trigger(pointerEvents.up); + $(dataGrid.getCellElement(1, 1)).trigger(CLICK_EVENT); // assert assert.deepEqual(keyboardNavigationController._focusedCellPosition, { @@ -18359,6 +18548,38 @@ QUnit.testInActiveWindow('DataGrid - Master grid should not render it\'s overlay assert.ok(detailRowsViewWrapper.isFocusOverlayVisible(), 'Detail grid focus overlay is visible'); }); +QUnit.testInActiveWindow('Not highlight cell if isHighlighted set false in the onFocusedCellChanging event by Tab key (T853599)', function(assert) { + // arrange + let focusedCellChangingCount = 0; + this.dataGrid.option({ + dataSource: [{ name: 'Alex', phone: '111111', room: 6 }], + keyExpr: 'name', + onFocusedCellChanging: function(e) { + ++focusedCellChangingCount; + e.isHighlighted = false; + } + }); + this.clock.tick(); + + $(this.dataGrid.getCellElement(0, 0)) + .trigger(CLICK_EVENT) + .click(); + this.clock.tick(); + + // assert + assert.equal(this.dataGrid.option('focusedRowIndex'), 0, 'focusedRowIndex'); + assert.equal(this.dataGrid.option('focusedColumnIndex'), 0, 'focusedColumnIndex'); + + // act + const navigationController = this.dataGrid.getController('keyboardNavigation'); + navigationController._keyDownHandler({ key: 'Tab', keyName: 'tab', originalEvent: $.Event('keydown', { target: $(this.dataGrid.getCellElement(0, 0)) }) }); + this.clock.tick(); + + // assert + assert.equal(focusedCellChangingCount, 2, 'onFocusedCellChanging fires count'); + assert.notOk($(this.dataGrid.getCellElement(0, 1)).hasClass('dx-focused'), 'cell is not focused'); +}); + QUnit.test('Focus row element should support native DOM', function(assert) { // arrange let $focusedCell; @@ -18723,7 +18944,7 @@ QUnit.test('The edited cell should be closed on click inside another dataGrid', this.clock.tick(100); // assert - assert.ok($(dataGrid1.getCellElement(0, 0)).find('input').length === 0, 'hasn\'t input'); + assert.strictEqual($(dataGrid1.getCellElement(0, 0)).find('input').length, 0, 'hasn\'t input'); assert.notOk($(dataGrid1.getCellElement(0, 0)).hasClass('dx-editor-cell'), 'cell of the first grid isn\'t editable'); assert.ok($(dataGrid2.getCellElement(0, 0)).find('input').length > 0, 'has input'); }); @@ -18791,7 +19012,7 @@ QUnit.test('onFocusedRowChanging, onFocusedRowChanged event if click selection c }); // act - rowsViewWrapper.getSelectionCheckBoxElement(1).trigger(pointerEvents.up); + rowsViewWrapper.getSelectionCheckBoxElement(1).trigger(CLICK_EVENT); this.clock.tick(); // assert @@ -18827,7 +19048,7 @@ QUnit.test('Cancel focused row if click selection checkBox (T812681)', function( assert.equal(dataGrid.option('focusedRowIndex'), -1, 'focusedRowIndex'); // act - rowsViewWrapper.getSelectionCheckBoxElement(1).trigger(pointerEvents.up); + rowsViewWrapper.getSelectionCheckBoxElement(1).trigger(CLICK_EVENT); this.clock.tick(); // assert @@ -18837,84 +19058,47 @@ QUnit.test('Cancel focused row if click selection checkBox (T812681)', function( assert.equal(dataGrid.option('focusedRowIndex'), -1, 'focusedRowIndex'); }); -QUnit.test('DataGrid - Focus updating on refresh should be correct for focused row if editing mode is cell (T830334)', function(assert) { - // arrange - let counter = 0; - const rowsViewWrapper = dataGridWrapper.rowsView; - const dataGrid = createDataGrid({ - loadingTimeout: undefined, - height: 100, - dataSource: [ - { name: 'Alex', phone: '111111', room: 1 }, - { name: 'Dan', phone: '2222222', room: 2 }, - { name: 'Ben', phone: '333333', room: 3 }, - { name: 'Sean', phone: '4545454', room: 4 }, - { name: 'Smith', phone: '555555', room: 5 }, - { name: 'Zeb', phone: '6666666', room: 6 } - ], - editing: { - mode: 'cell', - allowUpdating: true - }, - keyExpr: 'name', - focusedRowEnabled: true - }); - dataGrid.getView('rowsView').scrollToElementVertically = function($row) { - ++counter; - assert.equal($row.find('td').eq(0).text(), 'Zeb', 'Row'); - }; +['batch', 'cell'].forEach(editMode => { + QUnit.test(`DataGrid - Focus updating on refresh should be correct for focused row if ${editMode} edit mode (T830334)`, function(assert) { + // arrange + let counter = 0; + const rowsViewWrapper = dataGridWrapper.rowsView; + const dataGrid = createDataGrid({ + loadingTimeout: undefined, + height: 100, + dataSource: [ + { name: 'Alex', phone: '111111', room: 1 }, + { name: 'Dan', phone: '2222222', room: 2 }, + { name: 'Ben', phone: '333333', room: 3 }, + { name: 'Sean', phone: '4545454', room: 4 }, + { name: 'Smith', phone: '555555', room: 5 }, + { name: 'Zeb', phone: '6666666', room: 6 } + ], + editing: { + mode: editMode, + allowUpdating: true + }, + keyExpr: 'name', + focusedRowEnabled: true + }); - // act - dataGrid.getScrollable().scrollBy({ y: 400 }); - $(dataGrid.getCellElement(5, 1)) - .trigger(pointerEvents.up) - .trigger('dxclick'); + dataGrid.getView('rowsView').scrollToElementVertically = function($row) { + ++counter; + assert.equal($row.find('td').eq(0).text(), 'Zeb', 'Row'); + }; - // assert - assert.ok(rowsViewWrapper.getEditorInput(5, 1).length, 'Cell[5, 1] is in editing mode'); - assert.ok(rowsViewWrapper.isFocusedRow(5), 'Row 5 is focused'); - assert.equal(counter, 2, 'scrollToElementVertically called twice'); -}); + // act + dataGrid.getScrollable().scrollBy({ y: 400 }); + $(dataGrid.getCellElement(5, 1)) + .trigger(CLICK_EVENT) + .trigger('dxclick'); -QUnit.test('DataGrid - Focus updating on refresh should be correct for focused row if editing mode is batch (T830334)', function(assert) { - // arrange - let counter = 0; - const rowsViewWrapper = dataGridWrapper.rowsView; - const dataGrid = createDataGrid({ - loadingTimeout: undefined, - height: 100, - dataSource: [ - { name: 'Alex', phone: '111111', room: 1 }, - { name: 'Dan', phone: '2222222', room: 2 }, - { name: 'Ben', phone: '333333', room: 3 }, - { name: 'Sean', phone: '4545454', room: 4 }, - { name: 'Smith', phone: '555555', room: 5 }, - { name: 'Zeb', phone: '6666666', room: 6 } - ], - editing: { - mode: 'batch', - allowUpdating: true - }, - keyExpr: 'name', - focusedRowEnabled: true + // assert + assert.ok(rowsViewWrapper.getEditorInput(5, 1).length, 'Cell[5, 1] is in editing mode'); + assert.ok(rowsViewWrapper.isFocusedRow(5), 'Row 5 is focused'); + assert.equal(counter, 2, 'scrollToElementVertically called twice'); }); - - dataGrid.getView('rowsView').scrollToElementVertically = function($row) { - ++counter; - assert.equal($row.find('td').eq(0).text(), 'Zeb', 'Row'); - }; - - // act - dataGrid.getScrollable().scrollBy({ y: 400 }); - $(dataGrid.getCellElement(5, 1)) - .trigger(pointerEvents.up) - .trigger('dxclick'); - - // assert - assert.ok(rowsViewWrapper.getEditorInput(5, 1).length, 'Cell[5, 1] is in editing mode'); - assert.ok(rowsViewWrapper.isFocusedRow(5), 'Row 5 is focused'); - assert.equal(counter, 2, 'scrollToElementVertically called twice'); }); QUnit.test('Popup should apply data changes after editorOptions changing (T817880)', function(assert) { @@ -19081,8 +19265,7 @@ QUnit.test('The draggable row should have correct markup when defaultOptions is } }); -// T827960 -QUnit.test('The onFocusedRowChanged should be fired if change focusedRowKey to same page and loadPanel in onContentReady', function(assert) { +QUnit.test('The onFocusedRowChanged should be fired if change focusedRowKey to same page and loadPanel in onContentReady (T827960)', function(assert) { // arrange const onFocusedRowChangedSpy = sinon.spy(); const dataGrid = createDataGrid({ diff --git a/testing/tests/DevExpress.ui.widgets.dataGrid/dataSource.tests.js b/testing/tests/DevExpress.ui.widgets.dataGrid/dataSource.tests.js index 39d6e569d81c..8134cb44783c 100644 --- a/testing/tests/DevExpress.ui.widgets.dataGrid/dataSource.tests.js +++ b/testing/tests/DevExpress.ui.widgets.dataGrid/dataSource.tests.js @@ -2561,7 +2561,7 @@ QUnit.test('Update group offset for expanded grouped row of the first level when // act source.group([{ selector: 'field1', desc: true, isExpanded: true }, { selector: 'field2', isExpanded: true }]); source.reload(); - window.test = source; + // assert assert.equal(source.totalItemsCount(), 5); assert.deepEqual(source.items(), [{ diff --git a/testing/tests/DevExpress.ui.widgets.dataGrid/editing.tests.js b/testing/tests/DevExpress.ui.widgets.dataGrid/editing.tests.js index fd85d4a992bd..2590e89d523e 100644 --- a/testing/tests/DevExpress.ui.widgets.dataGrid/editing.tests.js +++ b/testing/tests/DevExpress.ui.widgets.dataGrid/editing.tests.js @@ -14930,6 +14930,48 @@ QUnit.test('The edit form should not be rerendered when setCellValue is set for assert.strictEqual($editForm.find('.dx-datagrid-edit-form-item').first().find('.dx-texteditor-input').val(), 'Test', 'first cell value is changed'); }); +// T848729 +QUnit.test('The onRowClick event should not be fired when clicking on a save button in the edit form', function(assert) { + // arrange + this.options.loadingTimeout = 30; + this.options.repaintChangesOnly = true; + this.options.editing.texts = { + saveRowChanges: 'Save' + }; + const onRowClick = this.options.onRowClick = sinon.spy((e) => { + this.editRow(e.rowIndex); + }); + this.options.rowTemplate = function(container) { + $('
')).appendTo('#container'); // act - navigationController = new KeyboardNavigationController(this.component); + const navigationController = new KeyboardNavigationController(this.component); navigationController.init(); callViewsRenderCompleted(this.component._views); - $cell = $rowsElement.find('td')[0]; + const $cell = $rowsElement.find('td')[0]; $cell.focus = function() { isFocused = true; @@ -362,8 +356,6 @@ QUnit.module('Keyboard controller', { QUnit.testInActiveWindow('Interactive element is focused when edit mode is enabled (T403964)', function(assert) { // arrange - let navigationController; - let view; const $rowsElement = $('
').appendTo('#container').append($(` " @@ -373,7 +365,7 @@ QUnit.module('Keyboard controller', { ')).appendTo('#container'); const rowsView = this.getView('rowsView'); @@ -456,7 +446,7 @@ QUnit.module('Keyboard controller', { }; // act - navigationController = new KeyboardNavigationController(this.component); + const navigationController = new KeyboardNavigationController(this.component); navigationController.init(); navigationController._focusedView = rowsView; @@ -666,9 +656,7 @@ QUnit.module('Keyboard controller', { QUnit.testInActiveWindow('Cell is not focused when view is renderCompleted without keydown event', function(assert) { // arrange - let navigationController; let isFocused = false; - let $cell; const rowsView = this.getView('rowsView'); const $rowsElement = $('
').append($('
')); @@ -677,14 +665,14 @@ QUnit.module('Keyboard controller', { }; // act - navigationController = new KeyboardNavigationController(this.component); + const navigationController = new KeyboardNavigationController(this.component); navigationController.init(); navigationController._focusedView = rowsView; navigationController._focus = function() { isFocused = true; }; - $cell = $rowsElement.find('td').eq(0); + const $cell = $rowsElement.find('td').eq(0); $($cell).trigger(CLICK_EVENT); @@ -698,7 +686,6 @@ QUnit.module('Keyboard controller', { QUnit.test('Element is not focused when it is html tag is not cell', function(assert) { // arrange - let navigationController; let _$focusElement; const rowsView = this.getView('rowsView'); const $rowsElement = $('
').append($('
')); @@ -711,7 +698,7 @@ QUnit.module('Keyboard controller', { }; // act - navigationController = new KeyboardNavigationController(this.component); + const navigationController = new KeyboardNavigationController(this.component); navigationController.init(); navigationController._focusedView = rowsView; navigationController._focus($('
')); diff --git a/testing/tests/DevExpress.ui.widgets.dataGrid/keyboardNavigation.keyboardKeys.tests.js b/testing/tests/DevExpress.ui.widgets.dataGrid/keyboardNavigation.keyboardKeys.tests.js index e191b7b097d0..588a3e5929b1 100644 --- a/testing/tests/DevExpress.ui.widgets.dataGrid/keyboardNavigation.keyboardKeys.tests.js +++ b/testing/tests/DevExpress.ui.widgets.dataGrid/keyboardNavigation.keyboardKeys.tests.js @@ -283,43 +283,6 @@ QUnit.module('Keyboard keys', { assert.strictEqual(this.dataController.expandRow.callCount, 0, 'grid does not open master detail'); }); - /* test("Down arrow for master detail", function () { - // act - this.options.masterDetail = { - enabled: true, - template: function(container){ - $(container).append($("").text("TEST")); - } - }; - this.gridView.render($("#container")); - this.focusFirstCell(); - this.triggerKeyDown("rightArrow") - this.triggerKeyDown("downArrow"); - this.triggerKeyDown("downArrow"); - this.triggerKeyDown("downArrow"); - this.triggerKeyDown("downArrow"); - this.triggerKeyDown("downArrow"); - - // assert - assert.equal(this.keyboardNavigationController._focusedCellPosition.columnIndex, 1, "cellIndex"); - assert.equal(this.keyboardNavigationController._focusedCellPosition.rowIndex, 5, "rowIndex"); - }); - - QUnit.testInActiveWindow("Up arrow for master detail", function (assert) { - // act - this.gridView.render($("#container")); - - this.focusFirstCell(); - - this.triggerKeyDown("downArrow"); - this.triggerKeyDown("downArrow"); - this.triggerKeyDown("downArrow"); - - // assert - assert.equal(this.keyboardNavigationController._focusedCellPosition.columnIndex, 0, "cellIndex"); - assert.equal(this.keyboardNavigationController._focusedCellPosition.rowIndex, 2, "rowIndex"); - }); */ - QUnit.testInActiveWindow('Update focus when row is editing with form_T306378', function(assert) { // arrange this.$element = function() { @@ -1844,7 +1807,6 @@ QUnit.module('Keyboard keys', { const $container = $('#container'); let isStoreUpdated; - let $input; this.$element = function() { return $container; @@ -1871,7 +1833,7 @@ QUnit.module('Keyboard keys', { this.triggerKeyDown('enter'); this.clock.tick(); - $input = $('.dx-row input').eq(1); + const $input = $('.dx-row input').eq(1); assert.ok($input.length, 'input found'); $input.val('Test update cell'); @@ -1945,7 +1907,6 @@ QUnit.module('Keyboard keys', { QUnit.testInActiveWindow('Escape for cancel row editing', function(assert) { // arrange const $container = $('#container'); - let isPreventDefaultCalled; setupModules(this); @@ -1958,7 +1919,8 @@ QUnit.module('Keyboard keys', { this.triggerKeyDown('enter'); this.keyboardNavigationController._focusedCellPosition = null; - isPreventDefaultCalled = this.triggerKeyDown('escape', false, false, $container.find('input')[0]).preventDefault; + + const isPreventDefaultCalled = this.triggerKeyDown('escape', false, false, $container.find('input')[0]).preventDefault; // assert assert.ok(isPreventDefaultCalled, 'PreventDefault'); @@ -2073,7 +2035,6 @@ QUnit.module('Keyboard keys', { QUnit.testInActiveWindow('Edit cell should not lose focus after enter key', function(assert) { let inputBlurFired = false; let inputChangeFired = false; - let $input; // arrange setupModules(this); @@ -2089,7 +2050,7 @@ QUnit.module('Keyboard keys', { this.clock.tick(); // arrange - $input = dataGridWrapper.rowsView.getEditorInput(0, 0); + const $input = dataGridWrapper.rowsView.getEditorInput(0, 0); // assert assert.ok($input.is(':focus'), 'input is focused'); @@ -2252,8 +2213,6 @@ QUnit.module('Keyboard keys', { QUnit.testInActiveWindow('DataGrid should skip group rows after tab navigation from the editing cell (T714142, T715092)', function(assert) { // arrange - let $cell; - this.columns = [ { visible: true, command: 'expand' }, { caption: 'Column 1', visible: true, dataField: 'Column1', allowEditing: true }, @@ -2288,7 +2247,7 @@ QUnit.module('Keyboard keys', { this.editCell(0, 1); this.clock.tick(); - $cell = $('#container').find('.dx-data-row').eq(0).find('td:nth-child(2)').eq(0); + const $cell = $('#container').find('.dx-data-row').eq(0).find('td:nth-child(2)').eq(0); // assert assert.ok(this.editingController.isEditing(), 'is editing'); @@ -2644,8 +2603,8 @@ QUnit.module('Keyboard keys', { // act - const $cell = $(this.rowsView.element()).find('.dx-row').filter(':visible').eq(0).find('td').eq(0); - $cell.focus().trigger(pointerEvents.up); + let $cell = $(this.rowsView.getCellElement(0, 0)); + $cell.focus().trigger(CLICK_EVENT); let isPreventDefaultCalled = this.triggerKeyDown('tab', false, false, $cell).preventDefault; @@ -2664,8 +2623,9 @@ QUnit.module('Keyboard keys', { isPreventDefaultCalled = this.triggerKeyDown('tab', false, false, $link2).preventDefault; // assert + $cell = $(this.rowsView.getCellElement(0, 2)); assert.ok(isPreventDefaultCalled, 'preventDefault is called'); - assert.ok(this.rowsView.element().find('.dx-row').filter(':visible').eq(0).find('td').eq(2).is(':focus'), 'last cell is focused'); + assert.ok($cell.is(':focus'), 'last cell is focused'); }); // T342637 @@ -2704,8 +2664,10 @@ QUnit.module('Keyboard keys', { // act - const $cell = $(this.rowsView.element()).find('.dx-row').filter(':visible').eq(0).find('td').eq(2); - $cell.focus().trigger(pointerEvents.up); + let $cell = $(this.rowsView.getCellElement(0, 2)); + $cell + .focus() + .trigger(CLICK_EVENT); let isPreventDefaultCalled = this.triggerKeyDown('tab', false, true, $cell).preventDefault; this.clock.tick(); @@ -2728,8 +2690,9 @@ QUnit.module('Keyboard keys', { this.clock.tick(); // assert + $cell = $(this.rowsView.getCellElement(0, 0)); assert.ok(isPreventDefaultCalled, 'preventDefault is called'); - assert.ok(this.rowsView.element().find('.dx-row').filter(':visible').eq(0).find('td').eq(0).is(':focus'), 'first cell is focused'); + assert.ok($cell.is(':focus'), 'first cell is focused'); assert.ok($('#container .dx-datagrid-focus-overlay').is(':visible'), 'focus overlay is visible'); }); @@ -2762,8 +2725,8 @@ QUnit.module('Keyboard keys', { // act - const $cell = $(this.rowsView.element()).find('.dx-row').filter(':visible').eq(0).find('td').eq(0); - $cell.focus().trigger(pointerEvents.up); + const $cell = $(this.rowsView.getCellElement(0, 0)); + $cell.focus().trigger(CLICK_EVENT); const isPreventDefaultCalled = this.triggerKeyDown('tab', false, false, $cell).preventDefault; this.clock.tick(); @@ -2830,8 +2793,6 @@ QUnit.module('Keyboard keys', { QUnit.testInActiveWindow('Edit next cell after tab key when edit disabled and row edited via API', function(assert) { // arrange - let $editRow; - setupModules(this); this.keyboardNavigationController._focusedView = this.rowsView; @@ -2840,7 +2801,8 @@ QUnit.module('Keyboard keys', { this.editingController.editRow(0); this.clock.tick(); - $editRow = $('#container').find('.dx-data-row').first(); + + const $editRow = $('#container').find('.dx-data-row').first(); assert.equal(this.editingController._editRowIndex, 0, 'edit row index'); @@ -2857,8 +2819,6 @@ QUnit.module('Keyboard keys', { if(device.deviceType === 'desktop') { QUnit.testInActiveWindow('Focus on first cell when insert Row', function(assert) { - let $newRow; - setupModules(this); this.keyboardNavigationController._focusedView = this.rowsView; @@ -2872,7 +2832,7 @@ QUnit.module('Keyboard keys', { this.editingController.addRow(); this.clock.tick(); - $newRow = $('#container').find('.dx-data-row').first(); + const $newRow = $('#container').find('.dx-data-row').first(); assert.equal(this.editingController._editRowIndex, 0, 'edit row index'); assert.ok($newRow.find('input').first().parents('.dx-editor-cell').hasClass('dx-focused')); @@ -2888,8 +2848,6 @@ QUnit.module('Keyboard keys', { }); QUnit.testInActiveWindow('Focus on first cell when insert Row via API when not editing', function(assert) { - let $newRow; - setupModules(this); this.keyboardNavigationController._focusedView = this.rowsView; @@ -2902,7 +2860,8 @@ QUnit.module('Keyboard keys', { this.editingController.addRow(); this.clock.tick(); - $newRow = $('#container').find('.dx-data-row').first(); + + const $newRow = $('#container').find('.dx-data-row').first(); assert.equal(this.editingController._editRowIndex, 0, 'edit row index'); assert.ok($newRow.find('input').first().parents('.dx-editor-cell').hasClass('dx-focused')); @@ -3238,7 +3197,6 @@ QUnit.module('Keyboard keys', { // act const $container = $('#container'); - let $groupRow; this.gridView.render($container); @@ -3248,7 +3206,7 @@ QUnit.module('Keyboard keys', { this.clock.tick(); // assert - $groupRow = $container.find('.dx-group-row').first(); + const $groupRow = $container.find('.dx-group-row').first(); assert.ok($groupRow.attr('tabindex'), 'tab index'); }); @@ -3318,9 +3276,13 @@ QUnit.module('Keyboard keys', { QUnit.testInActiveWindow('Enter on grouped row with isContinuation is true, is not worked', function(assert) { // arrange + this.options = { + grouping: { allowCollapsing: true }, + editing: {} + }; + setupModules(this); - this.options = { grouping: { allowCollapsing: true }, editing: {} }; this.keyboardNavigationController._focusedView = this.rowsView; this.keyboardNavigationController._focusedCellPosition = { @@ -3818,9 +3780,6 @@ QUnit.module('Keyboard keys', { // T680076 QUnit.testInActiveWindow('Down arrow key should work correctly after page down key press', function(assert) { // arrange - let scrollable; - let $scrollContainer; - this.dataControllerOptions = { pageCount: 4, pageIndex: 0, @@ -3844,8 +3803,8 @@ QUnit.module('Keyboard keys', { this.gridView.render($('#container')); this.rowsView.height(70); this.rowsView.resize(); - scrollable = this.rowsView.getScrollable(); - $scrollContainer = $(scrollable._container()); + const scrollable = this.rowsView.getScrollable(); + const $scrollContainer = $(scrollable._container()); this.focusFirstCell(); @@ -3866,8 +3825,6 @@ QUnit.module('Keyboard keys', { QUnit.testInActiveWindow('DataGrid should not scroll back to the focused editing cell after append rows in virtual scrolling (T715091)', function(assert) { // arrange - let $cell; - this.dataControllerOptions = { pageCount: 4, pageIndex: 0, @@ -3902,7 +3859,7 @@ QUnit.module('Keyboard keys', { this.clock.tick(); // act - $cell = $(this.getCellElement(0, 0)); + const $cell = $(this.getCellElement(0, 0)); this.triggerKeyDown('tab', false, false, $cell); this.keyboardNavigationController._updateFocus = function() { // assert @@ -3937,11 +3894,10 @@ QUnit.module('Keyboard keys', { that.rowsView.height(400); that.rowsView.resize(); - this.focusCell(0, 1); // focus the first cell of the first data row + this.focusCell(0, 0); // focus the first cell of the first data row that.clock.tick(); // act - this.triggerKeyDown('upArrow'); $(that.rowsView.getScrollable()._container()).trigger('scroll'); that.clock.tick(); @@ -3958,9 +3914,6 @@ QUnit.module('Keyboard keys', { // T680076 QUnit.testInActiveWindow('The page must be correct after several the \'Page Down\' key presses', function(assert) { // arrange - let scrollable; - let $scrollContainer; - this.options = { dataSource: generateItems(10), scrolling: { @@ -3976,8 +3929,8 @@ QUnit.module('Keyboard keys', { this.gridView.render($('#container')); this.rowsView.height(70); this.rowsView.resize(); - scrollable = this.rowsView.getScrollable(); - $scrollContainer = $(scrollable._container()); + const scrollable = this.rowsView.getScrollable(); + const $scrollContainer = $(scrollable._container()); this.focusFirstCell(); this.clock.tick(); diff --git a/testing/tests/DevExpress.ui.widgets.dataGrid/keyboardNavigation.realControllers.tests.js b/testing/tests/DevExpress.ui.widgets.dataGrid/keyboardNavigation.realControllers.tests.js index 0356727be743..3f21e17ff801 100644 --- a/testing/tests/DevExpress.ui.widgets.dataGrid/keyboardNavigation.realControllers.tests.js +++ b/testing/tests/DevExpress.ui.widgets.dataGrid/keyboardNavigation.realControllers.tests.js @@ -75,10 +75,6 @@ QUnit.module('Real DataController and ColumnsController', { }, function() { QUnit.testInActiveWindow('Must navigate after click by expand column of master detail', function(assert) { // arrange - let keyboardController; - let rowsView; - let $expandCell; - this.options = { masterDetail: { enabled: true, @@ -94,9 +90,9 @@ QUnit.module('Real DataController and ColumnsController', { this.gridView.render($('#container')); this.clock.tick(); - keyboardController = this.getController('keyboardNavigation'); - rowsView = this.gridView.getView('rowsView'); - $expandCell = $(rowsView.element().find('td').first()); + const keyboardController = this.getController('keyboardNavigation'); + const rowsView = this.gridView.getView('rowsView'); + const $expandCell = $(rowsView.element().find('td').first()); // act $expandCell.trigger(CLICK_EVENT); @@ -118,11 +114,9 @@ QUnit.module('Real DataController and ColumnsController', { QUnit.testInActiveWindow('Cell is focused when clicked on self', function(assert) { // arrange - let $cell; - this.setupAndRender(); - $cell = $(this.getCellElement(1, 1)); + const $cell = $(this.getCellElement(1, 1)); $cell.trigger(CLICK_EVENT); // assert @@ -131,9 +125,6 @@ QUnit.module('Real DataController and ColumnsController', { QUnit.testInActiveWindow('Cell is focused when clicked on input in cell (T667278)', function(assert) { // arrange - let $cell; - let $input; - this.options = { columns: [ 'name', { @@ -147,9 +138,9 @@ QUnit.module('Real DataController and ColumnsController', { this.setupAndRender(); // act - $input = $(this.getCellElement(1, 1)).find('input'); + const $input = $(this.getCellElement(1, 1)).find('input'); $input.focus().trigger(CLICK_EVENT); - $cell = $input.parent(); + const $cell = $input.parent(); // assert assert.ok($input.is(':focus'), 'input is focused'); @@ -159,19 +150,16 @@ QUnit.module('Real DataController and ColumnsController', { QUnit.testInActiveWindow('Cell is not focused when clicked on invalid self', function(assert) { // arrange - let navigationController; - let $cell; - this.setupAndRender(); // act - navigationController = this.getController('keyboardNavigation'); + const navigationController = this.getController('keyboardNavigation'); navigationController._isCellValid = () => false; navigationController._focusedCellPosition = { columnIndex: 0, rowIndex: 0 }; navigationController._isNeedFocus = true; // arrange - $cell = $(this.getCellElement(1, 1)); + const $cell = $(this.getCellElement(1, 1)); $cell.trigger(CLICK_EVENT); // assert @@ -182,9 +170,6 @@ QUnit.module('Real DataController and ColumnsController', { QUnit.testInActiveWindow('Focus valid cell in a rows with data', function(assert) { // arrange - let navigationController; - let rowsView; - this.options = { editing: { mode: 'cell', @@ -197,8 +182,8 @@ QUnit.module('Real DataController and ColumnsController', { $(this.getCellElement(1, 1)).trigger(CLICK_EVENT); this.clock.tick(); - navigationController = this.getController('keyboardNavigation'); - rowsView = this.getView('rowsView'); + const navigationController = this.getController('keyboardNavigation'); + const rowsView = this.getView('rowsView'); navigationController.getFocusedView = () => rowsView; navigationController._editingController.isEditing = () => true; navigationController._isNeedFocus = true; @@ -211,8 +196,6 @@ QUnit.module('Real DataController and ColumnsController', { QUnit.testInActiveWindow('Only visible input element is focused when edit mode is enabled (T403964)', function(assert) { // arrange - let navigationController; - this.options = { editing: { mode: 'row', @@ -235,7 +218,7 @@ QUnit.module('Real DataController and ColumnsController', { this.setupAndRender(); // arrange - navigationController = this.getController('keyboardNavigation'); + const navigationController = this.getController('keyboardNavigation'); // act this.editRow(1); @@ -330,8 +313,6 @@ QUnit.module('Real DataController and ColumnsController', { QUnit.testInActiveWindow('Master-detail cell should not has tabindex', function(assert) { // arrange - let masterDetailCell; - this.$element = function() { return $('#container'); }; @@ -354,7 +335,8 @@ QUnit.module('Real DataController and ColumnsController', { this.option('focusedRowIndex', 1); this.getView('rowsView').renderFocusState(); - masterDetailCell = $(this.gridView.getView('rowsView').element().find('.dx-master-detail-cell').eq(0)); + + const masterDetailCell = $(this.gridView.getView('rowsView').element().find('.dx-master-detail-cell').eq(0)); // assert assert.notOk(masterDetailCell.attr('tabindex'), 'master-detail cell has no tabindex'); @@ -382,8 +364,8 @@ QUnit.module('Real DataController and ColumnsController', { // act const $cell = $(this.getCellElement(0, 1)); - $cell.trigger(pointerEvents.up); - $cell.trigger(pointerEvents.up); + $cell.trigger(CLICK_EVENT); + $cell.trigger(CLICK_EVENT); // assert assert.equal($(this.getCellElement(0, 1)).attr('tabIndex'), 0, 'cell has tab index'); @@ -421,7 +403,6 @@ QUnit.module('Real DataController and ColumnsController', { QUnit.testInActiveWindow('DataGrid should not moved back to the edited cell if the next clicked cell canceled editing process (T718459, T812546)', function(assert) { // arrange - let keyboardNavigationController; let editingStartFiresCount = 0; let focusedCellChangingFiresCount = 0; let focusedCellChangedFiresCount = 0; @@ -450,7 +431,7 @@ QUnit.module('Real DataController and ColumnsController', { // act this.gridView.render($('#container')); - keyboardNavigationController = this.gridView.component.keyboardNavigationController; + const keyboardNavigationController = this.gridView.component.keyboardNavigationController; $cell = $(this.getCellElement(1, 1)); $cell.trigger(CLICK_EVENT); this.editCell(1, 1); @@ -486,8 +467,6 @@ QUnit.module('Real DataController and ColumnsController', { QUnit.testInActiveWindow('DataGrid should preserve fosused overlay after cancel editing (T812546)', function(assert) { // arrange let editingStartFiresCount = 0; - let keyboardNavigation; - this.$element = () => $('#container'); this.options = { @@ -505,11 +484,12 @@ QUnit.module('Real DataController and ColumnsController', { }; this.setupModule(); - keyboardNavigation = this.getController('keyboardNavigation'); + + const keyboardNavigation = this.getController('keyboardNavigation'); // act this.gridView.render($('#container')); - $(this.getCellElement(1, 1)).trigger(pointerEvents.up); + $(this.getCellElement(1, 1)).trigger(CLICK_EVENT); this.clock.tick(); this.triggerKeyDown('upArrow', false, false, $(':focus')); this.clock.tick(); @@ -527,7 +507,6 @@ QUnit.module('Real DataController and ColumnsController', { QUnit.testInActiveWindow('DataGrid should cancel editing cell if cell focusing canceled (T718459)', function(assert) { // arrange - let keyboardNavigationController; let editingStartCount = 0; let focusedCellChangingFiresCount = 0; let focusedCellChangedFiresCount = 0; @@ -558,7 +537,7 @@ QUnit.module('Real DataController and ColumnsController', { // act this.gridView.render($('#container')); - keyboardNavigationController = this.gridView.component.keyboardNavigationController; + const keyboardNavigationController = this.gridView.component.keyboardNavigationController; $cell = $(this.rowsView.element().find('.dx-row').eq(1).find('td').eq(1)); $cell.trigger(CLICK_EVENT); this.editCell(1, 1); @@ -633,7 +612,7 @@ QUnit.module('Real DataController and ColumnsController', { // act this.refresh(); // assert - assert.equal(focusedRowChangedFiresCount, 2, 'onFocusedRowChanged fires count'); + assert.equal(focusedRowChangedFiresCount, 1, 'onFocusedRowChanged fires count'); }); // T804439 @@ -655,7 +634,8 @@ QUnit.module('Real DataController and ColumnsController', { // act $(this.getCellElement(0, 0)) - .trigger('dxpointerup') + .trigger(CLICK_EVENT) + .trigger(pointerEvents.up) .trigger('dxclick'); // assert @@ -693,9 +673,6 @@ QUnit.module('Real DataController and ColumnsController', { }); QUnit.testInActiveWindow('Focus must be after enter key pressed if \'cell\' edit mode (T653709)', function(assert) { - let rowsView; - let $cell; - // arrange this.$element = function() { return $('#container'); @@ -714,7 +691,7 @@ QUnit.module('Real DataController and ColumnsController', { // arrange this.gridView.render($('#container')); - rowsView = this.gridView.getView('rowsView'); + const rowsView = this.gridView.getView('rowsView'); // act this.editCell(0, 1); @@ -723,7 +700,7 @@ QUnit.module('Real DataController and ColumnsController', { this.gridView.component.editorFactoryController._$focusedElement = undefined; this.clock.tick(); - $cell = $(this.rowsView.element().find('.dx-data-row:nth-child(1) td:nth-child(2)')); + const $cell = $(this.rowsView.element().find('.dx-data-row:nth-child(1) td:nth-child(2)')); // assert assert.ok($cell.hasClass('dx-focused'), 'cell is focused'); @@ -815,7 +792,7 @@ QUnit.module('Real DataController and ColumnsController', { const rowsView = this.gridView.getView('rowsView'); const $expandCell = $(rowsView.element().find('td').first()); - $expandCell.trigger(pointerEvents.up); + $expandCell.trigger(CLICK_EVENT); this.clock.tick(); @@ -1092,7 +1069,6 @@ QUnit.module('Real DataController and ColumnsController', { // arrange const that = this; - let $testElement; that.$element = function() { return $('#container'); @@ -1119,7 +1095,7 @@ QUnit.module('Real DataController and ColumnsController', { that.gridView.render($('#container')); // arrange, act - $testElement = that.$element().find('.template td').eq(0); + const $testElement = that.$element().find('.template td').eq(0); $testElement.find('input').focus(); $testElement.trigger(CLICK_EVENT); @@ -1133,7 +1109,6 @@ QUnit.module('Real DataController and ColumnsController', { QUnit.test('After apply the edit value with the ENTER key do not display the revert button when the save process, if editing mode is cell (T657148)', function(assert) { // arrange const that = this; - let $input; that.$element = function() { return $('#container'); @@ -1165,7 +1140,7 @@ QUnit.module('Real DataController and ColumnsController', { that.editCell(0, 0); that.clock.tick(); - $input = $(that.getCellElement(0, 0)).find('input'); + const $input = $(that.getCellElement(0, 0)).find('input'); $input.val('test').trigger('change'); that.clock.tick(); @@ -1274,4 +1249,98 @@ QUnit.module('Real DataController and ColumnsController', { assert.strictEqual($testElement.find('.dx-datagrid-rowsview td').eq(2).text(), 'Bob John', 'text of the third column of the first row'); assert.ok(that.editingController.isEditCell(1, 0), 'the first cell of the second row is editable'); }); + + ['click', 'dblClick'].forEach(startEditAction => { + ['cell', 'batch'].forEach(editMode => { + QUnit.test(`Focus overlay should not be hidden after click the save editor cell if editing.mode: ${editMode}, editing.startEditAction is ${startEditAction}`, function(assert) { + // arrange + const $testElement = $('#container'); + + this.data = [{ name: 'Alex', lastName: 'John' }], + this.options = { + editing: { + allowUpdating: true, + mode: editMode, + startEditAction: startEditAction + } + }; + + this.setupModule(); + this.gridView.render($testElement); + + const editingController = this.getController('editing'); + const startEditClickEventName = startEditAction === 'click' ? 'dxclick' : 'dxdblclick'; + + // act + $(this.getCellElement(0, 1)).trigger(startEditClickEventName); + this.clock.tick(); + // assert + assert.ok(editingController.isEditCell(0, 1), 'Cell[0, 1] is in edit mode'); + + // act + $(this.getCellElement(0, 1)).trigger(CLICK_EVENT); + // assert + assert.ok(editingController.isEditCell(0, 1), 'Cell[0, 1] is in edit mode'); + assert.notOk($(this.getCellElement(0, 1)).hasClass('dx-cell-focus-disabled'), 'Cell[0, 1] focus overlay is not disabled'); + }); + + QUnit.test(`Click by command select cell should not highlight focus if editing.mode: ${editMode}, editing.startEditAction is ${startEditAction}`, function(assert) { + // arrange + const rowsViewWrapper = dataGridWrapper.rowsView; + const $testElement = $('#container'); + + this.data = [{ name: 'Alex', lastName: 'John' }], + this.options = { + loadingTimeout: undefined, + selection: { + mode: 'multiple', + showCheckBoxesMode: 'always' + }, + editing: { + allowUpdating: true, + mode: editMode, + startEditAction: startEditAction + } + }; + + this.setupModule(); + this.gridView.render($testElement); + + // act + const $selectCell = rowsViewWrapper.getCellElement(0, 0); + $selectCell + .focus() + .removeClass('dx-cell-focus-disabled'); + this.getController('editorFactory')._updateFocusCore(); + this.clock.tick(); + + $selectCell + .trigger(pointerEvents.down) + .trigger(pointerEvents.up) + .trigger('dxclick'); + this.clock.tick(); + + // assert + assert.notOk($selectCell.hasClass('dx-focused'), 'Cell has no .dx-focused'); + assert.ok($selectCell.hasClass('dx-cell-focus-disabled'), 'Cell has disable focus class'); + + const $selectCheckBox = rowsViewWrapper.getSelectCheckBox(0, 0); + $selectCheckBox + .focus() + .removeClass('dx-cell-focus-disabled'); + this.getController('editorFactory')._updateFocusCore(); + this.clock.tick(); + + $selectCheckBox + .trigger(pointerEvents.down) + .trigger(pointerEvents.up) + .trigger('dxclick'); + this.clock.tick(); + + // assert + assert.notOk($selectCell.hasClass('dx-focused'), 'Cell has no .dx-focused'); + assert.ok($selectCell.hasClass('dx-cell-focus-disabled'), 'Cell has disable focus class'); + }); + }); + }); }); diff --git a/testing/tests/DevExpress.ui.widgets.dataGrid/pagerView.tests.js b/testing/tests/DevExpress.ui.widgets.dataGrid/pagerView.tests.js index 58991a43f9f3..81aa2e330bb9 100644 --- a/testing/tests/DevExpress.ui.widgets.dataGrid/pagerView.tests.js +++ b/testing/tests/DevExpress.ui.widgets.dataGrid/pagerView.tests.js @@ -235,7 +235,7 @@ QUnit.test('Visible is changed from dataController', function(assert) { this.dataController.updatePagesCount(20); // assert - assert.ok(testElement.find('.dx-pager').css('display') !== 'none', 'pager visible'); + assert.notStrictEqual(testElement.find('.dx-pager').css('display'), 'none', 'pager visible'); }); QUnit.test('Pager is not rendered on partial update', function(assert) { diff --git a/testing/tests/DevExpress.ui.widgets.dataGrid/rowsView.tests.js b/testing/tests/DevExpress.ui.widgets.dataGrid/rowsView.tests.js index eee9fda12be9..f81d10d944d2 100644 --- a/testing/tests/DevExpress.ui.widgets.dataGrid/rowsView.tests.js +++ b/testing/tests/DevExpress.ui.widgets.dataGrid/rowsView.tests.js @@ -85,7 +85,7 @@ function createRowsView(rows, dataController, columns, initDefaultOptions, userO return true; }, $element: function() { - return $('.dx-datagrid'); + return $('.dx-datagrid').parent(); } }; @@ -1106,7 +1106,7 @@ QUnit.test('All rows are not isSelected by default', function(assert) { rowsSelected = testElement.find('.dx-selection'); // assert - assert.ok(rowsSelected.length === 0, 'rows are not isSelected by default'); + assert.strictEqual(rowsSelected.length, 0, 'rows are not isSelected by default'); }); QUnit.test('Click on row call changeItemSelection', function(assert) { @@ -3250,7 +3250,7 @@ QUnit.test('Rows with option rowAlternationEnabled true', function(assert) { assert.ok(!rows.eq(0).hasClass('dx-row-alt'), 'not has class dx-row-alt'); assert.ok(rows.eq(1).hasClass('dx-row-alt'), 'has class dx-row-alt'); - assert.ok(rows.eq(1).find('td').css('backgroundColor') !== 'rgba(0, 0, 0, 0)', 'background color row'); + assert.notStrictEqual(rows.eq(1).find('td').css('backgroundColor'), 'rgba(0, 0, 0, 0)', 'background color row'); assert.ok(!rows.eq(2).hasClass('dx-row-alt'), 'not has class dx-row-alt'); }); @@ -3283,7 +3283,7 @@ QUnit.test('Rows with option rowAlternationEnabled true when grouping', function assert.ok(!rows.eq(0).hasClass('dx-row-alt'), 'not has class dx-row-alt'); assert.ok(!rows.eq(1).hasClass('dx-row-alt'), 'not has class dx-row-alt'); assert.ok(rows.eq(2).hasClass('dx-row-alt'), 'has class dx-row-alt'); - assert.ok(rows.eq(2).find('td').css('backgroundColor') !== 'rgba(0, 0, 0, 0)', 'background color row'); + assert.notStrictEqual(rows.eq(2).find('td').css('backgroundColor'), 'rgba(0, 0, 0, 0)', 'background color row'); }); QUnit.test('Rows with option rowAlternationEnabled false', function(assert) { @@ -3808,7 +3808,7 @@ QUnit.test('Summary items are not displayed in a group row', function(assert) { QUnit.test('Scroll to element by focus', function(assert) { // arrange - const testElement = $('#container'); + const $testElement = $('#container'); const rowsView = this.createRowsView(this.items, null, null, null, { keyboardNavigation: { enabled: true @@ -3818,16 +3818,18 @@ QUnit.test('Scroll to element by focus', function(assert) { let isScrollTo; const keyboardNavigationController = this.dataGrid.keyboardNavigationController; - rowsView.render(testElement); keyboardNavigationController._isNeedFocus = true; keyboardNavigationController._isNeedScroll = true; keyboardNavigationController._focusedView = rowsView; + + rowsView.render($testElement); + rowsView._scrollable.scrollToElement = function() { isScrollTo = true; }; // act - this.dataGrid.editorFactoryController.focus(testElement.find('.dx-data-row td').eq(0)); + this.dataGrid.editorFactoryController.focus($testElement.find('.dx-data-row td').eq(0)); this.clock.tick(1); // assert diff --git a/testing/tests/DevExpress.ui.widgets.dataGrid/selection.tests.js b/testing/tests/DevExpress.ui.widgets.dataGrid/selection.tests.js index 358905fa80ef..6a272ffe7bf4 100644 --- a/testing/tests/DevExpress.ui.widgets.dataGrid/selection.tests.js +++ b/testing/tests/DevExpress.ui.widgets.dataGrid/selection.tests.js @@ -1335,7 +1335,7 @@ QUnit.test('redundant load after refresh when the grid restores its selection', this.dataController.refresh(); const selectedRowsData = this.selectionController.getSelectedRowsData(); - assert.ok(oldSelectedRowsData !== selectedRowsData, 'selectedRowsData instance is changed'); + assert.notStrictEqual(oldSelectedRowsData, selectedRowsData, 'selectedRowsData instance is changed'); assert.deepEqual(selectedRowsData, [{ name: 'Dan1', pay: 999 }, { name: 'Dan3', pay: 153 }]); assert.equal(loadingCount, 1, 'one loading after refresh with selection'); }); diff --git a/testing/tests/DevExpress.ui.widgets.editors/actionButtons.test.js b/testing/tests/DevExpress.ui.widgets.editors/actionButtons.test.js index 62991ce93148..bc15a2e8f993 100644 --- a/testing/tests/DevExpress.ui.widgets.editors/actionButtons.test.js +++ b/testing/tests/DevExpress.ui.widgets.editors/actionButtons.test.js @@ -929,7 +929,7 @@ module('collection updating', () => { textBox.option('stylingMode', 'filled'); customButton = textBox.getButton('custom'); - assert.notOk(customButton.option('stylingMode') === 'text'); + assert.notStrictEqual(customButton.option('stylingMode'), 'text'); }); }); diff --git a/testing/tests/DevExpress.ui.widgets.editors/calendar.markup.tests.js b/testing/tests/DevExpress.ui.widgets.editors/calendar.markup.tests.js index 9910b50fa93a..665dc7da13c9 100644 --- a/testing/tests/DevExpress.ui.widgets.editors/calendar.markup.tests.js +++ b/testing/tests/DevExpress.ui.widgets.editors/calendar.markup.tests.js @@ -23,7 +23,7 @@ const toSelector = function(className) { QUnit.module('Calendar markup', { beforeEach: function() { - this.$element = $('
').appendTo('body'); + this.$element = $('
').appendTo('#qunit-fixture'); this.calendar = this.$element.dxCalendar({ value: new Date(2013, 9, 15), firstDayOfWeek: 1, @@ -51,7 +51,7 @@ QUnit.module('Calendar markup', { }); QUnit.test('Calendar must render with dx-rtl class', function(assert) { - const $element = $('
').appendTo('body'); + const $element = $('
').appendTo('#qunit-fixture'); $element.dxCalendar({ value: new Date(2013, 9, 15), rtlEnabled: true @@ -64,7 +64,7 @@ QUnit.module('Calendar markup', { QUnit.module('Hidden input', { beforeEach: function() { - this.$element = $('
').appendTo('body'); + this.$element = $('
').appendTo('#qunit-fixture'); this.calendar = this.$element.dxCalendar({ value: new Date(2013, 9, 15) }).dxCalendar('instance'); @@ -94,7 +94,7 @@ QUnit.module('Hidden input', { QUnit.module('The \'name\' option', { beforeEach: function() { - this.$element = $('
').appendTo('body'); + this.$element = $('
').appendTo('#qunit-fixture'); }, afterEach: function() { this.$element.remove(); @@ -113,7 +113,7 @@ QUnit.module('The \'name\' option', { QUnit.module('Navigator', { beforeEach: function() { - this.$element = $('
').appendTo('body'); + this.$element = $('
').appendTo('#qunit-fixture'); this.calendar = this.$element.dxCalendar({ value: new Date(2015, 5, 13) }).dxCalendar('instance'); @@ -139,7 +139,7 @@ QUnit.module('Navigator', { QUnit.module('Calendar footer', { beforeEach: function() { - this.$element = $('
').appendTo('body'); + this.$element = $('
').appendTo('#qunit-fixture'); }, afterEach: function() { this.$element.remove(); @@ -166,12 +166,12 @@ QUnit.module('Calendar footer', { QUnit.module('CellTemplate option', { beforeEach: function() { - this.$element = $('
').appendTo('body'); + this.$element = $('
').appendTo('#qunit-fixture'); this.calendar = this.$element.dxCalendar().dxCalendar('instance'); }, reinit: function(options) { this.$element.remove(); - this.$element = $('
').appendTo('body'); + this.$element = $('
').appendTo('#qunit-fixture'); this.calendar = this.$element.dxCalendar(options).dxCalendar('instance'); }, afterEach: function() { @@ -232,19 +232,24 @@ QUnit.module('CellTemplate option', { QUnit.module('Aria accessibility', { beforeEach: function() { - this.$element = $('
').appendTo('body'); + this.$element = $('
').appendTo('#qunit-fixture'); }, afterEach: function() { this.$element.remove(); } }, () => { QUnit.test('role for calendar widget', function(assert) { - const $element = this.$element; + this.$element.dxCalendar(); + + const $tables = this.$element.find('table'); - $element.dxCalendar(); + $tables.each((index, tableElement) => { + const role = tableElement.getAttribute('role'); + const label = tableElement.getAttribute('aria-label'); - assert.equal($element.attr('role'), 'listbox', 'role is correct'); - assert.equal($element.attr('aria-label'), 'Calendar', 'label is correct'); + assert.strictEqual(role, 'grid', 'role is correct'); + assert.equal(label, 'Calendar', 'label is correct'); + }); }); }); diff --git a/testing/tests/DevExpress.ui.widgets.editors/calendar.tests.js b/testing/tests/DevExpress.ui.widgets.editors/calendar.tests.js index abd8709b916a..b69f1099a973 100644 --- a/testing/tests/DevExpress.ui.widgets.editors/calendar.tests.js +++ b/testing/tests/DevExpress.ui.widgets.editors/calendar.tests.js @@ -88,7 +88,7 @@ QUnit.module('Hidden input', { beforeEach: function() { fx.off = true; - this.$element = $('
').appendTo('body'); + this.$element = $('
').appendTo('#qunit-fixture'); this.calendar = this.$element.dxCalendar({ value: new Date(2013, 9, 15) }).dxCalendar('instance'); @@ -115,7 +115,7 @@ QUnit.module('Hidden input', { QUnit.module('Navigator', { beforeEach: function() { fx.off = true; - this.$element = $('
').appendTo('body'); + this.$element = $('
').appendTo('#qunit-fixture'); this.calendar = this.$element.dxCalendar({ value: new Date(2015, 5, 13) }).dxCalendar('instance'); @@ -136,7 +136,7 @@ QUnit.module('Navigator', { }; let actualScrollTop; try { - brick.appendTo('body'); + brick.appendTo('#qunit-fixture'); brick.insertBefore(this.$element); $window.scrollTop(50000); actualScrollTop = $window.scrollTop(); @@ -161,7 +161,7 @@ QUnit.module('Navigator', { QUnit.module('Navigator integration', { beforeEach: function() { fx.off = true; - this.$element = $('
').appendTo('body'); + this.$element = $('
').appendTo('#qunit-fixture'); this.calendar = this.$element.dxCalendar({ value: new Date(2015, 5, 13) }).dxCalendar('instance'); @@ -172,7 +172,7 @@ QUnit.module('Navigator integration', { this.reinit = (options) => { this.$element.remove(); - this.$element = $('
').appendTo('body'); + this.$element = $('
').appendTo('#qunit-fixture'); this.calendar = this.$element.dxCalendar(options).dxCalendar('instance'); this.$navigatorCaption = this.$element.find(toSelector(CALENDAR_CAPTION_BUTTON_CLASS)); @@ -457,12 +457,12 @@ QUnit.module('Navigator integration', { QUnit.module('Views initial positions', { beforeEach: function() { - this.$element = $('
').appendTo('body'); + this.$element = $('
').appendTo('#qunit-fixture'); this.instance = this.$element.dxCalendar().dxCalendar('instance'); this.reinit = (options) => { this.$element.remove(); - this.$element = $('
').appendTo('body'); + this.$element = $('
').appendTo('#qunit-fixture'); this.instance = this.$element.dxCalendar(options).dxCalendar('instance'); }; }, @@ -523,7 +523,7 @@ QUnit.module('Views initial positions', { QUnit.module('Views integration', { beforeEach: function() { fx.off = true; - this.$element = $('
').appendTo('body'); + this.$element = $('
').appendTo('#qunit-fixture'); this.calendar = this.$element.dxCalendar({ value: new Date(2015, 5, 13), focusStateEnabled: true @@ -531,7 +531,7 @@ QUnit.module('Views integration', { this.reinit = (options) => { this.$element.remove(); - this.$element = $('
').appendTo('body'); + this.$element = $('
').appendTo('#qunit-fixture'); this.calendar = this.$element.dxCalendar(options).dxCalendar('instance'); }; }, @@ -544,7 +544,7 @@ QUnit.module('Views integration', { this.reinit({ rtlEnabled: true }); - assert.ok(getCurrentViewInstance(this.calendar).option('rtl')); + assert.ok(getCurrentViewInstance(this.calendar).option('rtlEnabled')); }); QUnit.test('calendar must pass disabled to the created views', function(assert) { @@ -711,7 +711,7 @@ QUnit.module('Keyboard navigation', { beforeEach: function() { fx.off = true; - this.$element = $('
').appendTo('body'); + this.$element = $('
').appendTo('#qunit-fixture'); this.value = new Date(2013, 9, 13); this.calendar = this.$element.dxCalendar({ @@ -723,7 +723,7 @@ QUnit.module('Keyboard navigation', { this.reinit = (options) => { this.$element.remove(); - this.$element = $('
').appendTo('body'); + this.$element = $('
').appendTo('#qunit-fixture'); this.calendar = this.$element.dxCalendar(options).dxCalendar('instance'); }; }, @@ -1073,7 +1073,7 @@ QUnit.module('Keyboard navigation', { assert.expect(4); this.$element.remove(); - this.$element = $('
').appendTo('body'); + this.$element = $('
').appendTo('#qunit-fixture'); this.$element.dxCalendar({ value: new Date(2013, 11, 15), focusStateEnabled: true @@ -1125,7 +1125,7 @@ QUnit.module('Preserve time component on value change', { beforeEach: function() { fx.off = true; - this.$element = $('
').appendTo('body'); + this.$element = $('
').appendTo('#qunit-fixture'); this.calendar = this.$element.dxCalendar({ focusStateEnabled: true }).dxCalendar('instance'); @@ -1165,7 +1165,7 @@ QUnit.module('Calendar footer', { beforeEach: function() { fx.off = true; - this.$element = $('
').appendTo('body'); + this.$element = $('
').appendTo('#qunit-fixture'); this.calendar = this.$element.dxCalendar({ value: new Date(2010, 10, 10), focusStateEnabled: true, @@ -1174,7 +1174,7 @@ QUnit.module('Calendar footer', { this.reinit = (options = {}) => { this.$element.remove(); - this.$element = $('
').appendTo('body'); + this.$element = $('
').appendTo('#qunit-fixture'); this.calendar = this.$element.dxCalendar(options).dxCalendar('instance'); }; }, @@ -1368,12 +1368,12 @@ QUnit.module('Options', { beforeEach: function() { fx.off = true; - this.$element = $('
').appendTo('body'); + this.$element = $('
').appendTo('#qunit-fixture'); this.calendar = this.$element.dxCalendar().dxCalendar('instance'); this.reinit = (options) => { this.$element.remove(); - this.$element = $('
').appendTo('body'); + this.$element = $('
').appendTo('#qunit-fixture'); this.calendar = this.$element.dxCalendar(options).dxCalendar('instance'); }; }, @@ -1490,7 +1490,7 @@ QUnit.module('Options', { QUnit.module('ZoomLevel option', { beforeEach: function() { fx.off = true; - this.$element = $('
').appendTo('body'); + this.$element = $('
').appendTo('#qunit-fixture'); }, afterEach: function() { this.$element.remove(); @@ -1720,7 +1720,7 @@ QUnit.module('Min & Max options', { this.minDate = new Date(2010, 9, 10); this.maxDate = new Date(2010, 11, 10); - this.$element = $('
').appendTo('body'); + this.$element = $('
').appendTo('#qunit-fixture'); this.calendar = this.$element.dxCalendar({ min: this.minDate, value: this.value, @@ -1732,7 +1732,7 @@ QUnit.module('Min & Max options', { this.reinit = (options) => { this.$element.remove(); - this.$element = $('
').appendTo('body'); + this.$element = $('
').appendTo('#qunit-fixture'); this.calendar = this.$element.dxCalendar(options).dxCalendar('instance'); }; }, @@ -2005,7 +2005,7 @@ QUnit.module('disabledDates option', { } }; - this.$element = $('
').appendTo('body'); + this.$element = $('
').appendTo('#qunit-fixture'); this.calendar = this.$element.dxCalendar({ disabledDates: this.disabledDates, value: this.value, @@ -2016,7 +2016,7 @@ QUnit.module('disabledDates option', { this.reinit = (options) => { this.$element.remove(); - this.$element = $('
').appendTo('body'); + this.$element = $('
').appendTo('#qunit-fixture'); this.calendar = this.$element.dxCalendar(options).dxCalendar('instance'); }; }, @@ -2641,11 +2641,11 @@ QUnit.module('disabledDates option', { QUnit.module('Current date', { beforeEach: function() { fx.off = true; - this.$element = $('
').appendTo('body'); + this.$element = $('
').appendTo('#qunit-fixture'); this.reinit = () => { this.$element.remove(); - this.$element = $('
').appendTo('body'); + this.$element = $('
').appendTo('#qunit-fixture'); }; }, afterEach: function() { @@ -2824,7 +2824,7 @@ QUnit.module('Current date', { QUnit.module('Navigation - click on other view cell', { beforeEach: function() { fx.off = true; - this.$element = $('
').appendTo('body'); + this.$element = $('
').appendTo('#qunit-fixture'); }, afterEach: function() { this.$element.remove(); @@ -2913,7 +2913,7 @@ QUnit.module('Navigation - swiping', { beforeEach: function() { fx.off = true; - this.$element = $('
').appendTo('body'); + this.$element = $('
').appendTo('#qunit-fixture'); this.calendar = this.$element.dxCalendar({ currentDate: new Date(2013, 9, 15), firstDayOfWeek: 1 @@ -2923,7 +2923,7 @@ QUnit.module('Navigation - swiping', { this.reinit = (options) => { this.$element.remove(); - this.$element = $('
').appendTo('body'); + this.$element = $('
').appendTo('#qunit-fixture'); this.calendar = this.$element.dxCalendar(options).dxCalendar('instance'); this.pointer = pointerMock(this.$element).start(); }; @@ -3209,22 +3209,13 @@ QUnit.module('Navigation - swiping', { QUnit.module('Aria accessibility', { beforeEach: function() { fx.off = true; - this.$element = $('
').appendTo('body'); + this.$element = $('
').appendTo('#qunit-fixture'); }, afterEach: function() { this.$element.remove(); fx.off = false; } }, () => { - QUnit.test('role for calendar widget', function(assert) { - const $element = this.$element; - - $element.dxCalendar(); - - assert.equal($element.attr('role'), 'listbox', 'role is correct'); - assert.equal($element.attr('aria-label'), 'Calendar', 'label is correct'); - }); - QUnit.test('aria-activedescendant on widget should point to the focused cell', function(assert) { const $element = this.$element; @@ -3294,11 +3285,14 @@ QUnit.module('Aria accessibility', { assert.equal($element.attr('aria-activedescendant'), $cell.attr('id'), 'selected cell id and activedescendant are equal'); }); - QUnit.test('role for calendar cells', function(assert) { - const calendar = this.$element.dxCalendar().dxCalendar('instance'); - const $cell = $(getCurrentViewInstance(calendar).$element().find(toSelector(CALENDAR_CELL_CLASS)).first()); + QUnit.test('role for calendar cells and rows', function(assert) { + this.$element.dxCalendar(); + + const $row = this.$element.find('tr').last(); + const $cell = this.$element.find(toSelector(CALENDAR_CELL_CLASS)).first(); - assert.equal($cell.attr('role'), 'option', 'aria role is correct'); + assert.equal($row.attr('role'), 'row', 'Row: aria role is correct'); + assert.equal($cell.attr('role'), 'gridcell', 'Cell: aria role is correct'); }); QUnit.test('aria id on contoured date cell', function(assert) { @@ -3415,17 +3409,37 @@ QUnit.module('Aria accessibility', { clock.restore(); } }); + + QUnit.test('table should have correct role after navigation to another view or zoom level', function(assert) { + const calendar = this.$element.dxCalendar().dxCalendar('instance'); + const $navigatorNext = this.$element.find(toSelector(CALENDAR_NAVIGATOR_NEXT_VIEW_CLASS)); + + ['month', 'year', 'decade', 'century'].forEach((zoomLevel) => { + calendar.option({ zoomLevel }); + $navigatorNext.trigger('dxclick'); + + const $tables = this.$element.find('table'); + + $tables.each((index, tableElement) => { + const role = tableElement.getAttribute('role'); + const label = tableElement.getAttribute('aria-label'); + + assert.strictEqual(role, 'grid', `zoomLevel: ${zoomLevel}, role is correct`); + assert.equal(label, 'Calendar', `zoomLevel: ${zoomLevel}, label is correct`); + }); + }); + }); }); QUnit.module('Regression', { beforeEach: function() { fx.off = true; - this.$element = $('
').appendTo('body'); + this.$element = $('
').appendTo('#qunit-fixture'); this.reinit = (options) => { this.$element.remove(); - this.$element = $('
').appendTo('body'); + this.$element = $('
').appendTo('#qunit-fixture'); }; }, afterEach: function() { @@ -3480,7 +3494,7 @@ QUnit.module('Regression', { QUnit.module('dxCalendar number and string value support', { beforeEach: function() { - this.$element = $('
').appendTo('body'); + this.$element = $('
').appendTo('#qunit-fixture'); fx.off = true; }, afterEach: function() { diff --git a/testing/tests/DevExpress.ui.widgets.editors/calendarView.markup.tests.js b/testing/tests/DevExpress.ui.widgets.editors/calendarView.markup.tests.js index b6d5840f6466..d4c293195133 100644 --- a/testing/tests/DevExpress.ui.widgets.editors/calendarView.markup.tests.js +++ b/testing/tests/DevExpress.ui.widgets.editors/calendarView.markup.tests.js @@ -37,7 +37,7 @@ QUnit.module('Basics', () => { QUnit.module('MonthView markup', { beforeEach: function() { - this.$element = $('
').appendTo('body'); + this.$element = $('
').appendTo('#qunit-fixture'); this.view = new Views['month'](this.$element, { date: new Date(2013, 9, 16), firstDayOfWeek: 1, @@ -46,7 +46,7 @@ QUnit.module('MonthView markup', { }, reinit: function(options) { this.$element.remove(); - this.$element = $('
').appendTo('body'); + this.$element = $('
').appendTo('#qunit-fixture'); this.view = new Views['month'](this.$element, options); }, afterEach: function() { @@ -75,13 +75,20 @@ QUnit.module('MonthView markup', { this.reinit({ date: new Date(2013, 9, 16), firstDayOfWeek: 1, - rtl: true + rtlEnabled: true }); const captions = this.$element.find('table').find('th'); assert.deepEqual(getTextsArray(captions), ['Sun', 'Sat', 'Fri', 'Thu', 'Wed', 'Tue', 'Mon'], 'day captions order is correct'); }); + QUnit.test('day captions must be rendered in proper order in RTL mode after changing runtime', function(assert) { + this.view.option('rtlEnabled', true); + + const captions = this.$element.find('table').find('th'); + assert.deepEqual(getTextsArray(captions), ['Sun', 'Sat', 'Fri', 'Thu', 'Wed', 'Tue', 'Mon'], 'day captions order is correct'); + }); + QUnit.test('dates must be rendered in proper positions', function(assert) { const dateCells = this.$element.find('table').find('td'); assert.deepEqual(getTextsArray(dateCells), @@ -94,7 +101,7 @@ QUnit.module('MonthView markup', { this.reinit({ date: new Date(2013, 9, 16), firstDayOfWeek: 1, - rtl: true + rtlEnabled: true }); const dateCells = this.$element.find('table').find('td'); @@ -104,6 +111,16 @@ QUnit.module('MonthView markup', { '3', '2', '1', '31', '30', '29', '28', '10', '9', '8', '7', '6', '5', '4']); }); + QUnit.test('dates must be rendered in proper positions in RTL mode after changing runtime', function(assert) { + this.view.option('rtlEnabled', true); + + const dateCells = this.$element.find('table').find('td'); + assert.deepEqual(getTextsArray(dateCells), + ['6', '5', '4', '3', '2', '1', '30', '13', '12', '11', '10', '9', '8', '7', + '20', '19', '18', '17', '16', '15', '14', '27', '26', '25', '24', '23', '22', '21', + '3', '2', '1', '31', '30', '29', '28', '10', '9', '8', '7', '6', '5', '4']); + }); + QUnit.test('dates must be rendered in proper positions when the first day of the month comes right before the first day of the week', function(assert) { this.reinit({ date: new Date(2013, 8, 11), @@ -146,7 +163,7 @@ QUnit.module('MonthView markup', { QUnit.module('YearView markup', { beforeEach: function() { - this.$element = $('
').appendTo('body'); + this.$element = $('
').appendTo('#qunit-fixture'); this.view = new Views['year'](this.$element, { date: new Date(2013, 9, 16), firstDayOfWeek: 1, @@ -155,7 +172,7 @@ QUnit.module('YearView markup', { }, reinit: function(options) { this.$element.remove(); - this.$element = $('
').appendTo('body'); + this.$element = $('
').appendTo('#qunit-fixture'); this.view = new Views['year'](this.$element, options); }, afterEach: function() { @@ -187,7 +204,7 @@ QUnit.module('YearView markup', { QUnit.test('month must be rendered in proper positions in RTL mode', function(assert) { this.reinit({ date: new Date(2015, 2, 1), - rtl: true + rtlEnabled: true }); const dateCells = this.$element.find('table').find('td'); @@ -221,7 +238,7 @@ QUnit.module('DecadeView', { beforeEach: function() { fx.off = true; - this.$element = $('
').appendTo('body'); + this.$element = $('
').appendTo('#qunit-fixture'); this.view = new Views['decade'](this.$element, { date: new Date(2013, 9, 16), value: new Date(2013, 9, 16), @@ -231,7 +248,7 @@ QUnit.module('DecadeView', { }, reinit: function(options) { this.$element.remove(); - this.$element = $('
').appendTo('body'); + this.$element = $('
').appendTo('#qunit-fixture'); this.view = new Views['decade'](this.$element, options); }, afterEach: function() { @@ -264,7 +281,7 @@ QUnit.module('DecadeView', { QUnit.test('years must be rendered in proper positions in RTL mode', function(assert) { this.reinit({ date: new Date(2015, 2, 1), - rtl: true + rtlEnabled: true }); const dateCells = this.$element.find('table').find('td'); @@ -291,7 +308,7 @@ QUnit.module('CenturyView', { beforeEach: function() { fx.off = true; - this.$element = $('
').appendTo('body'); + this.$element = $('
').appendTo('#qunit-fixture'); this.view = new Views['century'](this.$element, { date: new Date(2013, 9, 16), value: new Date(2013, 9, 16), @@ -301,7 +318,7 @@ QUnit.module('CenturyView', { }, reinit: function(options) { this.$element.remove(); - this.$element = $('
').appendTo('body'); + this.$element = $('
').appendTo('#qunit-fixture'); this.view = new Views['century'](this.$element, options); }, afterEach: function() { @@ -334,7 +351,7 @@ QUnit.module('CenturyView', { QUnit.test('decades must be rendered in proper positions in RTL mode', function(assert) { this.reinit({ date: new Date(2015, 2, 1), - rtl: true + rtlEnabled: true }); const dateCells = this.$element.find('table').find('td'); @@ -371,7 +388,7 @@ QUnit.module('MonthView min/max', { this.min = new Date(2010, 10, 5); this.max = new Date(2010, 10, 25); - this.$element = $('
').appendTo('body'); + this.$element = $('
').appendTo('#qunit-fixture'); this.view = new Views['month'](this.$element, { min: this.min, date: new Date(2010, 10, 10), @@ -401,7 +418,7 @@ QUnit.module('MonthView disabledDates', { } }; - this.$element = $('
').appendTo('body'); + this.$element = $('
').appendTo('#qunit-fixture'); this.view = new Views['month'](this.$element, { disabledDates: this.disabledDates, date: new Date(2010, 10, 10), @@ -431,7 +448,7 @@ QUnit.module('MonthView disabledDates as array', { new Date(2010, 10, 4) ]; - this.$element = $('
').appendTo('body'); + this.$element = $('
').appendTo('#qunit-fixture'); this.view = new Views['month'](this.$element, { disabledDates: this.disabledDates, date: new Date(2010, 10, 10), @@ -457,7 +474,7 @@ QUnit.module('YearView min/max', { this.min = new Date(2015, 0, 18); this.max = new Date(2015, 6, 18); - this.$element = $('
').appendTo('body'); + this.$element = $('
').appendTo('#qunit-fixture'); this.view = new Views['year'](this.$element, { min: this.min, date: new Date(2015, 3, 15), @@ -490,7 +507,7 @@ QUnit.module('YearView disabledDates', { } }; - this.$element = $('
').appendTo('body'); + this.$element = $('
').appendTo('#qunit-fixture'); this.view = new Views['year'](this.$element, { disabledDates: this.disabledDates, date: new Date(2015, 3, 15) @@ -520,7 +537,7 @@ QUnit.module('DecadeView min/max', { const max = new Date(2018, 6, 18); const currentDate = new Date(2015, 3, 15); - this.$element = $('
').appendTo('body'); + this.$element = $('
').appendTo('#qunit-fixture'); this.view = new Views['decade'](this.$element, { min, max, @@ -555,7 +572,7 @@ QUnit.module('DecadeView disabledDates', { } }; - this.$element = $('
').appendTo('body'); + this.$element = $('
').appendTo('#qunit-fixture'); this.view = new Views['decade'](this.$element, { disabledDates: this.disabledDates, value: currentDate, @@ -585,7 +602,7 @@ QUnit.module('CenturyView min/max', { this.min = new Date(2005, 0, 18); this.max = new Date(2075, 6, 18); - this.$element = $('
').appendTo('body'); + this.$element = $('
').appendTo('#qunit-fixture'); this.view = new Views['century'](this.$element, { min: this.min, value: new Date(2015, 3, 15), @@ -618,7 +635,7 @@ QUnit.module('CenturyView disabledDates', { } }; - this.$element = $('
').appendTo('body'); + this.$element = $('
').appendTo('#qunit-fixture'); this.view = new Views['century'](this.$element, { disabledDates: this.disabledDates, value: new Date(2015, 3, 15) diff --git a/testing/tests/DevExpress.ui.widgets.editors/calendarViews.tests.js b/testing/tests/DevExpress.ui.widgets.editors/calendarViews.tests.js index e0311320fe48..4d50f67133be 100644 --- a/testing/tests/DevExpress.ui.widgets.editors/calendarViews.tests.js +++ b/testing/tests/DevExpress.ui.widgets.editors/calendarViews.tests.js @@ -46,7 +46,7 @@ const FakeView = BaseView.inherit({ QUnit.module('Basics', () => { QUnit.test('onCellClick action should be fired on cell click', function(assert) { - const $element = $('
').appendTo('body'); + const $element = $('
').appendTo('#qunit-fixture'); try { const spy = sinon.spy(); @@ -62,7 +62,7 @@ QUnit.module('Basics', () => { }); QUnit.test('no contouredDate is set by default', function(assert) { - const $element = $('
').appendTo('body'); + const $element = $('
').appendTo('#qunit-fixture'); try { const view = new FakeView($element, {}); @@ -73,7 +73,7 @@ QUnit.module('Basics', () => { }); QUnit.test('onCellClick should not be fired on out of range cells', function(assert) { - const $element = $('
').appendTo('body'); + const $element = $('
').appendTo('#qunit-fixture'); try { const spy = sinon.spy(); @@ -90,7 +90,7 @@ QUnit.module('Basics', () => { }); QUnit.test('Calendar should set first day by firstDayOfWeek option if it is setted and this is different in localization', function(assert) { - const $element = $('
').appendTo('body'); const spy = sinon.spy(dateLocalization, 'firstDayOfWeekIndex'); + const $element = $('
').appendTo('#qunit-fixture'); const spy = sinon.spy(dateLocalization, 'firstDayOfWeekIndex'); this.view = new Views['month']($element, { date: new Date(2017, 11, 11), @@ -106,7 +106,7 @@ QUnit.module('MonthView', { beforeEach: function() { fx.off = true; - this.$element = $('
').appendTo('body'); + this.$element = $('
').appendTo('#qunit-fixture'); this.view = new Views['month'](this.$element, { date: new Date(2013, 9, 16), firstDayOfWeek: 1, @@ -115,7 +115,7 @@ QUnit.module('MonthView', { }, reinit: function(options) { this.$element.remove(); - this.$element = $('
').appendTo('body'); + this.$element = $('
').appendTo('#qunit-fixture'); this.view = new Views['month'](this.$element, options); }, afterEach: function() { @@ -128,7 +128,7 @@ QUnit.module('MonthView', { }); QUnit.test('getNavigatorCaption must return a proper caption in RTL mode', function(assert) { - this.view.option('rtl', true); + this.view.option('rtlEnabled', true); assert.equal(this.view.getNavigatorCaption(), 'October 2013', 'caption is correct'); }); @@ -183,7 +183,7 @@ QUnit.module('YearView', { beforeEach: function() { fx.off = true; - this.$element = $('
').appendTo('body'); + this.$element = $('
').appendTo('#qunit-fixture'); this.view = new Views['year'](this.$element, { date: new Date(2013, 9, 16), firstDayOfWeek: 1, @@ -192,7 +192,7 @@ QUnit.module('YearView', { }, reinit: function(options) { this.$element.remove(); - this.$element = $('
').appendTo('body'); + this.$element = $('
').appendTo('#qunit-fixture'); this.view = new Views['year'](this.$element, options); }, afterEach: function() { @@ -233,7 +233,7 @@ QUnit.module('DecadeView', { beforeEach: function() { fx.off = true; - this.$element = $('
').appendTo('body'); + this.$element = $('
').appendTo('#qunit-fixture'); this.view = new Views['decade'](this.$element, { date: new Date(2013, 9, 16), value: new Date(2013, 9, 16), @@ -243,7 +243,7 @@ QUnit.module('DecadeView', { }, reinit: function(options) { this.$element.remove(); - this.$element = $('
').appendTo('body'); + this.$element = $('
').appendTo('#qunit-fixture'); this.view = new Views['decade'](this.$element, options); }, afterEach: function() { @@ -295,7 +295,7 @@ QUnit.module('CenturyView', { beforeEach: function() { fx.off = true; - this.$element = $('
').appendTo('body'); + this.$element = $('
').appendTo('#qunit-fixture'); this.view = new Views['century'](this.$element, { date: new Date(2013, 9, 16), value: new Date(2013, 9, 16), @@ -305,7 +305,7 @@ QUnit.module('CenturyView', { }, reinit: function(options) { this.$element.remove(); - this.$element = $('
').appendTo('body'); + this.$element = $('
').appendTo('#qunit-fixture'); this.view = new Views['century'](this.$element, options); }, afterEach: function() { @@ -353,7 +353,7 @@ QUnit.module('MonthView min/max', { this.min = new Date(2010, 10, 5); this.max = new Date(2010, 10, 25); - this.$element = $('
').appendTo('body'); + this.$element = $('
').appendTo('#qunit-fixture'); this.view = new Views['month'](this.$element, { min: this.min, date: new Date(2010, 10, 10), @@ -399,7 +399,7 @@ QUnit.module('MonthView disabledDates', { } }; - this.$element = $('
').appendTo('body'); + this.$element = $('
').appendTo('#qunit-fixture'); this.view = new Views['month'](this.$element, { disabledDates: this.disabledDates, date: new Date(2010, 10, 10), @@ -439,7 +439,7 @@ QUnit.module('MonthView disabledDates as array', { new Date(2010, 10, 4) ]; - this.$element = $('
').appendTo('body'); + this.$element = $('
').appendTo('#qunit-fixture'); this.view = new Views['month'](this.$element, { disabledDates: this.disabledDates, date: new Date(2010, 10, 10), @@ -474,7 +474,7 @@ QUnit.module('YearView min/max', { this.min = new Date(2015, 0, 18); this.max = new Date(2015, 6, 18); - this.$element = $('
').appendTo('body'); + this.$element = $('
').appendTo('#qunit-fixture'); this.view = new Views['year'](this.$element, { min: this.min, date: new Date(2015, 3, 15), @@ -510,7 +510,7 @@ QUnit.module('YearView disabledDates', { } }; - this.$element = $('
').appendTo('body'); + this.$element = $('
').appendTo('#qunit-fixture'); this.view = new Views['year'](this.$element, { disabledDates: this.disabledDates, date: new Date(2015, 3, 15) @@ -538,7 +538,7 @@ QUnit.module('DecadeView min/max', { this.min = new Date(2013, 0, 18); this.max = new Date(2018, 6, 18); - this.$element = $('
').appendTo('body'); + this.$element = $('
').appendTo('#qunit-fixture'); this.view = new Views['decade'](this.$element, { min: this.min, value: new Date(2015, 3, 15), @@ -574,7 +574,7 @@ QUnit.module('DecadeView disabledDates', { } }; - this.$element = $('
').appendTo('body'); + this.$element = $('
').appendTo('#qunit-fixture'); this.view = new Views['decade'](this.$element, { disabledDates: this.disabledDates, value: new Date(2015, 3, 15), @@ -601,7 +601,7 @@ QUnit.module('CenturyView min/max', { this.min = new Date(2005, 0, 18); this.max = new Date(2075, 6, 18); - this.$element = $('
').appendTo('body'); + this.$element = $('
').appendTo('#qunit-fixture'); this.view = new Views['century'](this.$element, { min: this.min, value: new Date(2015, 3, 15), @@ -635,7 +635,7 @@ QUnit.module('CenturyView disabledDates', { } }; - this.$element = $('
').appendTo('body'); + this.$element = $('
').appendTo('#qunit-fixture'); this.view = new Views['century'](this.$element, { disabledDates: this.disabledDates, value: new Date(2015, 3, 15) @@ -672,7 +672,7 @@ QUnit.module('Aria accessibility', { }; $.each(['month', 'year', 'decade', 'century'], function(_, type) { - const $element = $('
').appendTo('body'); + const $element = $('
').appendTo('#qunit-fixture'); new Views[type]($element, { date: new Date(2015, 5, 1), @@ -690,5 +690,56 @@ QUnit.module('Aria accessibility', { } }); }); + + QUnit.test('check roles across the views', function(assert) { + ['month', 'year', 'decade', 'century'].forEach((viewName) => { + const $element = $('
').appendTo('#qunit-fixture'); + + new Views[viewName]($element, { + date: new Date(2015, 5, 1), + value: new Date(2015, 5, 1), + contouredDate: new Date(2015, 5, 1), + firstDayOfWeek: 1, + focusStateEnabled: true + }); + + try { + const $cell = $element.find(`.${CALENDAR_CONTOURED_DATE_CLASS}`); + const $row = $cell.closest('tr'); + const $table = $row.closest('table'); + + assert.equal($cell.attr('role'), 'gridcell', `${viewName} - cell role is correct`); + assert.equal($row.attr('role'), 'row', `${viewName} - row role is correct`); + assert.equal($table.attr('role'), 'grid', `${viewName} - table role is correct`); + } finally { + $element.remove(); + } + }); + }); + + QUnit.test('header row of the Month view should have correct attributes', function(assert) { + const $element = $('
').appendTo('#qunit-fixture'); + const view = new Views.month($element, { + date: new Date(2015, 5, 1), + value: new Date(2015, 5, 1), + contouredDate: new Date(2015, 5, 1), + firstDayOfWeek: 1, + focusStateEnabled: true + }); + const $headerCells = $element.find('thead > tr').first().find('th'); + + $headerCells.each((index, cell) => { + const scope = cell.getAttribute('scope'); + const abbr = cell.getAttribute('abbr'); + const cellText = cell.textContent; + const { full: fullDayCaption, abbreviated: shortDayCaption } = view._getDayCaption(view._getFirstDayOfWeek() + index); + + assert.strictEqual(scope, 'col', `"${cellText}" cell: correct header cell role`); + assert.strictEqual(abbr, fullDayCaption, `"${cellText}" cell: correct cell "abbr" attribute`); + assert.strictEqual(cellText, shortDayCaption, `"${cellText}" cell: correct cell text`); + }); + + $element.remove(); + }); }); diff --git a/testing/tests/DevExpress.ui.widgets.editors/datebox.mask.tests.js b/testing/tests/DevExpress.ui.widgets.editors/datebox.mask.tests.js index 7bcb1b715067..7fad55195a51 100644 --- a/testing/tests/DevExpress.ui.widgets.editors/datebox.mask.tests.js +++ b/testing/tests/DevExpress.ui.widgets.editors/datebox.mask.tests.js @@ -1119,10 +1119,9 @@ module('Regression', () => { }); }); -module('Advanced caret', setupModule, () => { +module('Caret moving', setupModule, () => { test('Move caret to the next group', function(assert) { this.instance.option({ - advanceCaret: true, displayFormat: 'dd.MM' }); @@ -1133,7 +1132,6 @@ module('Advanced caret', setupModule, () => { test('Move caret to the next group when next digit will overflow', function(assert) { this.instance.option({ - advanceCaret: true, displayFormat: 'MM.dd' }); @@ -1144,7 +1142,6 @@ module('Advanced caret', setupModule, () => { test('Move caret to the next group after limit overflow', function(assert) { this.instance.option({ - advanceCaret: true, displayFormat: 'dd.MM' }); @@ -1154,7 +1151,6 @@ module('Advanced caret', setupModule, () => { test('Move caret to the next group after format length overflow', function(assert) { this.instance.option({ - advanceCaret: true, displayFormat: 'yy MM' }); @@ -1165,7 +1161,6 @@ module('Advanced caret', setupModule, () => { test('Don\'t move caret to next group when format length is less than limit length', function(assert) { this.instance.option({ - advanceCaret: true, displayFormat: 'y MM' }); @@ -1176,7 +1171,6 @@ module('Advanced caret', setupModule, () => { test('Typed year and value should be in the same century when short year format is used', function(assert) { this.instance.option({ - advanceCaret: true, displayFormat: 'yy MM', value: new Date(1995, 10, 11) }); @@ -1198,7 +1192,6 @@ module('Advanced caret', setupModule, () => { test('Move caret to the next group after string length overflow', function(assert) { this.instance.option({ - advanceCaret: true, displayFormat: 'dd.MM' }); diff --git a/testing/tests/DevExpress.ui.widgets.editors/datebox.tests.js b/testing/tests/DevExpress.ui.widgets.editors/datebox.tests.js index 21884f8ac493..b513e4dbe007 100644 --- a/testing/tests/DevExpress.ui.widgets.editors/datebox.tests.js +++ b/testing/tests/DevExpress.ui.widgets.editors/datebox.tests.js @@ -60,6 +60,7 @@ const BUTTONS_CONTAINER_CLASS = 'dx-texteditor-buttons-container'; const TODAY_CELL_CLASS = 'dx-calendar-today'; const GESTURE_COVER_CLASS = 'dx-gesture-cover'; const DROP_DOWN_BUTTON_CLASS = 'dx-dropdowneditor-button'; +const DROP_DOWN_BUTTON_VISIBLE_CLASS = 'dx-dropdowneditor-button-visible'; const CALENDAR_APPLY_BUTTON_SELECTOR = '.dx-popup-done.dx-button'; @@ -905,31 +906,28 @@ QUnit.module('options changed callbacks', moduleConfig, () => { assert.deepEqual(secondValue, calendar.option('value'), 'value in calendar is changed'); }); - QUnit.test('buttons are removed after applyValueMode option is changed', function(assert) { - const dateBox = $('#dateBox').dxDateBox({ + QUnit.test('dxDateBox should hide or show its DDButton on showDropDownButton option change', function(assert) { + const $dateBox = $('#dateBox').dxDateBox({ + showDropDownButton: true, + value: new Date(), type: 'date', - applyValueMode: 'useButtons', - pickerType: 'calendar', - value: new Date() - }).dxDateBox('instance'); - - dateBox.open(); - let $buttons = $('.dx-datebox-wrapper .dx-toolbar .dx-button'); + pickerType: 'calendar' + }); + const dateBox = $dateBox.dxDateBox('instance'); - assert.equal($buttons.length, 3, 'two buttons are rendered'); + assert.ok($dateBox.hasClass(DROP_DOWN_BUTTON_VISIBLE_CLASS)); - dateBox.close(); - dateBox.option('applyValueMode', 'instantly'); - dateBox.open(); - $buttons = $('.dx-datebox-wrapper .dx-toolbar .dx-button'); + dateBox.option('showDropDownButton', false); + assert.notOk($dateBox.hasClass(DROP_DOWN_BUTTON_VISIBLE_CLASS)); - assert.equal($buttons.length, 0, 'no buttons are rendered'); + dateBox.option('showDropDownButton', true); + assert.ok($dateBox.hasClass(DROP_DOWN_BUTTON_VISIBLE_CLASS)); }); - QUnit.test('closeOnValueChange option still affects on buttons rendering', function(assert) { + QUnit.test('buttons are removed after applyValueMode option is changed', function(assert) { const dateBox = $('#dateBox').dxDateBox({ type: 'date', - closeOnValueChange: false, + applyValueMode: 'useButtons', pickerType: 'calendar', value: new Date() }).dxDateBox('instance'); @@ -940,7 +938,7 @@ QUnit.module('options changed callbacks', moduleConfig, () => { assert.equal($buttons.length, 3, 'two buttons are rendered'); dateBox.close(); - dateBox.option('closeOnValueChange', true); + dateBox.option('applyValueMode', 'instantly'); dateBox.open(); $buttons = $('.dx-datebox-wrapper .dx-toolbar .dx-button'); @@ -1501,7 +1499,7 @@ QUnit.module('widget sizing render', {}, () => { QUnit.test('component width calculation should consider buttons containers element', function(assert) { const $parent = $('#parent-div'); - $parent.css('width', 200); + $parent.css('display', 'inline-block'); const $element = $('#dateBox').appendTo($parent); const component = $('#dateBox').dxDateBox({ @@ -2470,7 +2468,6 @@ QUnit.module('datebox w/ calendar', { this.reinitFixture({ type: 'date', value, - closeOnValueChange: true, pickerType: 'calendar' }); @@ -2797,25 +2794,80 @@ QUnit.module('datebox with time component', { } }); - QUnit.test('date box should have compact view when showAnalogClock option is false', function(assert) { - const $element = $('#dateBox').dxDateBox({ - type: 'datetime', - pickerType: 'calendar' + [true, false].forEach((adaptivityEnabledValue) => { + QUnit.test(`date box should change behavior if adaptivityEnabled option is changed to ${adaptivityEnabledValue} at runtime`, function(assert) { + const widthStub = sinon.stub(renderer.fn, 'width').returns(300); + + try { + const $element = $('#dateBox').dxDateBox({ + type: 'datetime', + pickerType: 'calendar', + adaptivityEnabled: !adaptivityEnabledValue, + opened: true + }); + const instance = $element.dxDateBox('instance'); + + instance.option('adaptivityEnabled', adaptivityEnabledValue); + instance.close(); + instance.open(); + + const $content = $(instance._popup.$content()); + const box = Box.getInstance($content.find(`.${BOX_CLASS}`)); + const $clock = $content.find(`.${TIMEVIEW_CLOCK_CLASS}`); + const timeViewExpectedMessage = `timeview is ${adaptivityEnabledValue ? '' : 'not'} rendered`; + const clockExpectedMessage = `clock is ${adaptivityEnabledValue ? 'not' : ''} rendered`; + + assert.strictEqual(box.itemElements().eq(0).find(`.${TIMEVIEW_CLASS}`).length, (adaptivityEnabledValue ? 1 : 0), timeViewExpectedMessage); + assert.strictEqual($clock.length, (adaptivityEnabledValue ? 0 : 1), clockExpectedMessage); + } finally { + widthStub.restore(); + } }); + }); - const instance = $element.dxDateBox('instance'); + [true, false].forEach((showAnalogClockValue) => { + const timeViewExpectedMessage = `timeview is ${showAnalogClockValue ? 'not' : ''} rendered`; + const clockExpectedMessage = `clock is ${showAnalogClockValue ? '' : 'not'} rendered`; - instance.option('showAnalogClock', false); - instance.open(); + QUnit.test(`date box should ${showAnalogClockValue ? 'not' : ''} have compact view when showAnalogClock option is ${showAnalogClockValue}`, function(assert) { + const $element = $('#dateBox').dxDateBox({ + type: 'datetime', + pickerType: 'calendar', + showAnalogClock: showAnalogClockValue + }); - const $content = $(instance._popup.$content()); - const box = Box.getInstance($content.find('.' + BOX_CLASS)); - const $clock = $content.find('.dx-timeview-clock'); + const instance = $element.dxDateBox('instance'); + instance.open(); + + const $content = $(instance._popup.$content()); + const box = Box.getInstance($content.find(`.${BOX_CLASS}`)); + const $clock = $content.find('.dx-timeview-clock'); + + assert.strictEqual(box.option('direction'), 'row', 'correct box direction specified'); + assert.strictEqual(box.itemElements().eq(0).find(`.${CALENDAR_CLASS}`).length, 1, 'calendar rendered'); + assert.strictEqual(box.itemElements().eq(0).find(`.${TIMEVIEW_CLASS}`).length, (showAnalogClockValue ? 0 : 1), timeViewExpectedMessage); + assert.strictEqual($clock.length, (showAnalogClockValue ? 1 : 0), clockExpectedMessage); + }); + + QUnit.test(`date box should change behavior if showAnalogClock option is changed to ${showAnalogClockValue} at runtime`, function(assert) { + const $element = $('#dateBox').dxDateBox({ + type: 'datetime', + pickerType: 'calendar', + showAnalogClock: !showAnalogClockValue, + opened: true + }); + const instance = $element.dxDateBox('instance'); + + instance.option('showAnalogClock', showAnalogClockValue); + instance.close(); + instance.open(); - assert.equal(box.option('direction'), 'row', 'correct box direction specified'); - assert.ok(box.itemElements().eq(0).find('.' + CALENDAR_CLASS).length, 'calendar rendered'); - assert.ok(box.itemElements().eq(0).find('.' + TIMEVIEW_CLASS).length, 'timeview rendered'); - assert.equal($clock.length, 0, 'clock was not rendered'); + const $content = $(instance._popup.$content()); + const box = Box.getInstance($content.find(`.${BOX_CLASS}`)); + const $clock = $content.find(`.${TIMEVIEW_CLOCK_CLASS}`); + assert.strictEqual(box.itemElements().eq(0).find(`.${TIMEVIEW_CLASS}`).length, (showAnalogClockValue ? 0 : 1), timeViewExpectedMessage); + assert.strictEqual($clock.length, (showAnalogClockValue ? 1 : 0), clockExpectedMessage); + }); }); QUnit.test('date box wrapper adaptivity class depends on the screen size', function(assert) { @@ -3610,6 +3662,39 @@ QUnit.module('datebox w/ time list', { const $timeListItems = $('.dx-list .dx-list-item'); assert.ok($timeListItems.length > 0); }); + + QUnit.test('should works correctly with serialized dates (T854579)', function(assert) { + this.dateBox.option({ + opened: true, + dateSerializationFormat: 'yyyy-MM-ddTHH:mm:ssx', + }); + const $input = $(this.dateBox.element()).find(`.${TEXTEDITOR_INPUT_CLASS}`); + const $items = $(this.dateBox.content()).find(LIST_ITEM_SELECTOR); + + $items.eq(1).trigger('dxclick'); + assert.strictEqual($input.val(), $items.eq(1).text(), 'time is applied'); + + this.dateBox.open(); + $items.eq(3).trigger('dxclick'); + assert.strictEqual($input.val(), $items.eq(3).text(), 'new time is applied'); + }); + + QUnit.test('event field should be defined after value has been changed via List', function(assert) { + assert.expect(2); + + this.dateBox.option({ + opened: true, + onValueChanged: ({ event }) => { + assert.ok(!!event, 'event field is defined'); + assert.strictEqual(event.type, 'dxclick'); + } + }); + + $(this.dateBox.content()) + .find('.dx-list-item') + .first() + .trigger('dxclick'); + }); }); QUnit.module('keyboard navigation', { @@ -4173,6 +4258,24 @@ QUnit.module('datebox validation', {}, () => { assert.equal(validationError, 'A lorem ipsum...', 'validation message is correct'); }); + QUnit.test('change invalidDateMessage at runtime', function(assert) { + const $dateBox = $('#dateBox').dxDateBox({ + pickerType: 'calendar', + invalidDateMessage: 'test message' + }); + const dateBox = $dateBox.dxDateBox('instance'); + const $input = $dateBox.find(`.${TEXTEDITOR_INPUT_CLASS}`); + + $input.val('ips'); + $($input).trigger('change'); + + dateBox.option('invalidDateMessage', 'another test message'); + $($input).trigger('change'); + + const validationError = $dateBox.dxDateBox('instance').option('validationError').message; + assert.equal(validationError, 'another test message', 'validation message is correct'); + }); + QUnit.test('dateOutOfRangeMessage', function(assert) { const $dateBox = $('#dateBox').dxDateBox({ dateOutOfRangeMessage: 'A lorem ipsum...', @@ -4189,6 +4292,24 @@ QUnit.module('datebox validation', {}, () => { assert.equal(validationError, 'A lorem ipsum...', 'validation message is correct'); }); + QUnit.test('change dateOutOfRangeMessage at runtime', function(assert) { + const $dateBox = $('#dateBox').dxDateBox({ + dateOutOfRangeMessage: 'test message', + min: new Date(2015, 5, 5), + max: new Date(2016, 5, 5), + value: new Date(2017, 5, 5) + }); + const dateBox = $dateBox.dxDateBox('instance'); + const $input = $dateBox.find(`.${TEXTEDITOR_INPUT_CLASS}`); + + $($input).trigger('change'); + dateBox.option('dateOutOfRangeMessage', 'another test message'); + $($input).trigger('change'); + + const validationError = dateBox.option('validationError.message'); + assert.equal(validationError, 'another test message', 'validation message is correct'); + }); + QUnit.test('year is too big', function(assert) { const $dateBox = $('#dateBox').dxDateBox({ displayFormat: 'd/M/y', diff --git a/testing/tests/DevExpress.ui.widgets.editors/dropDownEditor.markup.tests.js b/testing/tests/DevExpress.ui.widgets.editors/dropDownEditor.markup.tests.js index 6f3aacc00e42..eebef1473b9c 100644 --- a/testing/tests/DevExpress.ui.widgets.editors/dropDownEditor.markup.tests.js +++ b/testing/tests/DevExpress.ui.widgets.editors/dropDownEditor.markup.tests.js @@ -127,3 +127,33 @@ module('aria accessibility', () => { }); }); + +module('option change', function() { + const getStartDirection = (isRtlEnabled) => isRtlEnabled ? 'right' : 'left'; + + [false, true].forEach((rtlEnabled) => { + test(`after updating of the "rtlEnabled" option to "${rtlEnabled}" Popup should update its position`, function(assert) { + const dropDownEditor = $('#dropDownEditorLazy').dxDropDownEditor({ rtlEnabled }).dxDropDownEditor('instance'); + const { my: initialMyPosition, at: initialAtPosition } = dropDownEditor.option('popupPosition'); + const initialStartDirection = getStartDirection(rtlEnabled); + + assert.strictEqual(initialAtPosition, `${initialStartDirection} bottom`, 'correct initial "at" position'); + assert.strictEqual(initialMyPosition, `${initialStartDirection} top`, 'correct initial "my" position'); + + dropDownEditor.option('rtlEnabled', !rtlEnabled); + + const { my: newMyPosition, at: newAtPosition } = dropDownEditor.option('popupPosition'); + const newStartDirection = getStartDirection(!rtlEnabled); + + assert.strictEqual(newAtPosition, `${newStartDirection} bottom`, 'correct new "at" position'); + assert.strictEqual(newMyPosition, `${newStartDirection} top`, 'correct new "my" position'); + + dropDownEditor.option('rtlEnabled', rtlEnabled); + + const { my: revertedMyPosition, at: revertedAtPosition } = dropDownEditor.option('popupPosition'); + + assert.strictEqual(revertedAtPosition, `${initialStartDirection} bottom`, 'correct initial "at" position'); + assert.strictEqual(revertedMyPosition, `${initialStartDirection} top`, 'correct initial "my" position'); + }); + }); +}); diff --git a/testing/tests/DevExpress.ui.widgets.editors/dropDownList.tests.js b/testing/tests/DevExpress.ui.widgets.editors/dropDownList.tests.js index 55c03750f8ea..6f325d10bccf 100644 --- a/testing/tests/DevExpress.ui.widgets.editors/dropDownList.tests.js +++ b/testing/tests/DevExpress.ui.widgets.editors/dropDownList.tests.js @@ -1063,16 +1063,43 @@ QUnit.module('popup', moduleConfig, () => { opened: true }).dxDropDownList('instance'); - assert.ok($(instance.content('.dx-overlay-content')).parent().height() > 80, 'popup sizes are not limited if container has no overflow: hidden styles'); + assert.ok($(instance.content()).parent().height() > 80, 'popup sizes are not limited if container has no overflow: hidden styles'); parentContainer.css('overflow', 'hidden'); instance.close(); instance.open(); - assert.roughEqual($(instance.content('.dx-overlay-content')).parent().height(), 80 / 2, 2, 'popup sizes are limited by container parent bounds'); + assert.roughEqual($(instance.content()).parent().height(), 80 / 2, 2, 'popup sizes are limited by container parent bounds'); childContainer.css('overflow', 'hidden'); instance.repaint(); - assert.roughEqual($(instance.content('.dx-overlay-content')).parent().height(), 60 / 2, 2, 'popup sizes are limited by container bounds'); + assert.roughEqual($(instance.content()).parent().height(), 60 / 2, 2, 'popup sizes are limited by container bounds'); + + parentContainer.remove(); + }); + + QUnit.test('popup max height are limited by container bounds and window', function(assert) { + const items = []; + for(let i = 0; i < 100; i++) { + items.push(`item ${i}`); + } + + const windowHeight = $(window).outerHeight(); + const parentContainer = $('
') + .attr('id', 'specific-container') + .css('overflow', 'hidden') + .height(windowHeight * 2) + .appendTo('#qunit-fixture'); + + const instance = $('#dropDownList').dxDropDownList({ + items, + dropDownOptions: { + container: parentContainer + }, + opened: true + }).dxDropDownList('instance'); + const $overlay = $(instance.content()).parent(); + + assert.roughEqual($overlay.height(), windowHeight / 2, 2, 'popup sizes are limited by window if overflow:hidden container is larger than window'); parentContainer.remove(); }); diff --git a/testing/tests/DevExpress.ui.widgets.editors/htmlEditor.converterController.tests.js b/testing/tests/DevExpress.ui.widgets.editors/htmlEditor.converterController.tests.js index b4a6c50e3526..a90eae4ce78b 100644 --- a/testing/tests/DevExpress.ui.widgets.editors/htmlEditor.converterController.tests.js +++ b/testing/tests/DevExpress.ui.widgets.editors/htmlEditor.converterController.tests.js @@ -1,6 +1,7 @@ import $ from 'jquery'; import 'common.css!'; +import '../../helpers/ignoreQuillTimers.js'; QUnit.testStart(() => { const markup = '
'; diff --git a/testing/tests/DevExpress.ui.widgets.editors/htmlEditor.missingModules.tests.part1.js b/testing/tests/DevExpress.ui.widgets.editors/htmlEditor.missingModules.tests.part1.js index 43e24e0fd6ec..a520f7146ddc 100644 --- a/testing/tests/DevExpress.ui.widgets.editors/htmlEditor.missingModules.tests.part1.js +++ b/testing/tests/DevExpress.ui.widgets.editors/htmlEditor.missingModules.tests.part1.js @@ -1,2 +1,3 @@ +require('../../helpers/ignoreQuillTimers.js'); require('./htmlEditorParts/importQuill.tests.js'); require('./htmlEditorParts/importShowdown.tests.js'); diff --git a/testing/tests/DevExpress.ui.widgets.editors/htmlEditor.missingModules.tests.part2.js b/testing/tests/DevExpress.ui.widgets.editors/htmlEditor.missingModules.tests.part2.js index 39769b779985..7d8c327494d0 100644 --- a/testing/tests/DevExpress.ui.widgets.editors/htmlEditor.missingModules.tests.part2.js +++ b/testing/tests/DevExpress.ui.widgets.editors/htmlEditor.missingModules.tests.part2.js @@ -1 +1,2 @@ +require('../../helpers/ignoreQuillTimers.js'); require('./htmlEditorParts/importTurnDown.tests.js'); diff --git a/testing/tests/DevExpress.ui.widgets.editors/htmlEditor.tests.js b/testing/tests/DevExpress.ui.widgets.editors/htmlEditor.tests.js index 71950a737d38..def2e8491dfb 100644 --- a/testing/tests/DevExpress.ui.widgets.editors/htmlEditor.tests.js +++ b/testing/tests/DevExpress.ui.widgets.editors/htmlEditor.tests.js @@ -1,4 +1,5 @@ import 'common.css!'; +import '../../helpers/ignoreQuillTimers.js'; import './htmlEditorParts/initFixture.js'; import './htmlEditorParts/converters.tests.js'; diff --git a/testing/tests/DevExpress.ui.widgets.editors/htmlEditorParts/toolbarIntegration.tests.js b/testing/tests/DevExpress.ui.widgets.editors/htmlEditorParts/toolbarIntegration.tests.js index 74e2f958543d..7ad6bd9f86c3 100644 --- a/testing/tests/DevExpress.ui.widgets.editors/htmlEditorParts/toolbarIntegration.tests.js +++ b/testing/tests/DevExpress.ui.widgets.editors/htmlEditorParts/toolbarIntegration.tests.js @@ -358,9 +358,9 @@ QUnit.module('Toolbar integration', { const blackIndex = value.indexOf(BLACK_PIXEL); const orangeIndex = value.indexOf(ORANGE_PIXEL); - assert.ok(value.indexOf(WHITE_PIXEL) === -1, 'There is no white pixel'); - assert.ok(blackIndex !== -1, 'There is a black pixel'); - assert.ok(orangeIndex !== -1, 'There is an orange pixel'); + assert.strictEqual(value.indexOf(WHITE_PIXEL), -1, 'There is no white pixel'); + assert.notStrictEqual(blackIndex, -1, 'There is a black pixel'); + assert.notStrictEqual(orangeIndex, -1, 'There is an orange pixel'); assert.ok(orangeIndex < blackIndex, 'orange pixel placed before black pixel'); done(); } diff --git a/testing/tests/DevExpress.ui.widgets.editors/numberBoxParts/common.tests.js b/testing/tests/DevExpress.ui.widgets.editors/numberBoxParts/common.tests.js index 65c358020e81..38783a636de4 100644 --- a/testing/tests/DevExpress.ui.widgets.editors/numberBoxParts/common.tests.js +++ b/testing/tests/DevExpress.ui.widgets.editors/numberBoxParts/common.tests.js @@ -24,6 +24,8 @@ const PLACEHOLDER_CLASS = 'dx-placeholder'; const ACTIVE_STATE_CLASS = 'dx-state-active'; const CLEAR_BUTTON_CLASS = 'dx-clear-button-area'; +const INVALID_MESSAGE_POPUP_CONTENT_SELECTOR = '.dx-invalid-message .dx-overlay-content'; + QUnit.module('basics', {}, () => { QUnit.test('markup init', function(assert) { const element = $('#numberbox').dxNumberBox(); @@ -2019,7 +2021,19 @@ QUnit.module('number validation', {}, () => { const instance = $numberBox.dxNumberBox('instance'); - assert.equal($numberBox.find('.dx-invalid-message .dx-overlay-content').text(), instance.option('invalidValueMessage'), 'validation message is rendered'); + assert.equal($numberBox.find(INVALID_MESSAGE_POPUP_CONTENT_SELECTOR).text(), instance.option('invalidValueMessage'), 'validation message is rendered'); + }); + + QUnit.test('custom validation message can be changed at runtime', function(assert) { + const $numberBox = $('#numberbox').dxNumberBox({ + value: 'abc' + }); + const instance = $numberBox.dxNumberBox('instance'); + + instance.option('invalidValueMessage', 'test message'); + instance.option('value', 'ab'); + + assert.strictEqual($numberBox.find(INVALID_MESSAGE_POPUP_CONTENT_SELECTOR).text(), 'test message', 'new validation message is applyed after the value change'); }); QUnit.test('the validation message should be shown if value is invalid after \'enter\' key was pressed', function(assert) { @@ -2042,11 +2056,11 @@ QUnit.module('number validation', {}, () => { keyboard.type('2'); keyboard.change(); - assert.equal($numberBox.find('.dx-invalid-message .dx-overlay-content').text(), instance.option('validationError').message, 'validation message is rendered'); + assert.equal($numberBox.find(INVALID_MESSAGE_POPUP_CONTENT_SELECTOR).text(), instance.option('validationError').message, 'validation message is rendered'); keyboard.press('enter'); - assert.equal($numberBox.find('.dx-invalid-message .dx-overlay-content').text(), 'Value is not in range', 'validation message is not empty'); + assert.equal($numberBox.find(INVALID_MESSAGE_POPUP_CONTENT_SELECTOR).text(), 'Value is not in range', 'validation message is not empty'); }); QUnit.test('onValueChanged should be fired after \'enter\' key was pressed', function(assert) { diff --git a/testing/tests/DevExpress.ui.widgets.editors/radioGroup.tests.js b/testing/tests/DevExpress.ui.widgets.editors/radioGroup.tests.js index 955d0ae6bfc7..031705d9b7d0 100644 --- a/testing/tests/DevExpress.ui.widgets.editors/radioGroup.tests.js +++ b/testing/tests/DevExpress.ui.widgets.editors/radioGroup.tests.js @@ -135,6 +135,25 @@ module('buttons group rendering', () => { instance.option('dataSource', [1, 2, 3]); assert.strictEqual(onContentReadyHandler.callCount, 2); }); + + test('onContentReady - subscription using "on" method', function(assert) { + const done = assert.async(); + + const onContentReadyHandler = () => { + assert.strictEqual(instance.itemElements().eq(0).text(), '1', 'contentReady is fired'); + done(); + }; + + const instance = getInstance( + createRadioGroup({ + dataSource: ['str1', 'str2', 'str3'] + }) + ); + + instance.on('contentReady', onContentReadyHandler); + + instance.option('dataSource', [1, 2, 3]); + }); }); module('layout', moduleConfig, () => { @@ -341,6 +360,25 @@ module('value', moduleConfig, () => { assert.equal(value, 1, 'value changed'); }); + test('value is changed on item click - subscription using "on" method', function(assert) { + const handler = sinon.spy(); + const $radioGroup = createRadioGroup({ + items: [1, 2, 3] + }); + const radioGroup = getInstance($radioGroup); + + radioGroup.on('valueChanged', handler); + $(radioGroup.itemElements()).first().trigger('dxclick'); + + const e = handler.lastCall.args[0]; + + assert.ok(handler.calledOnce, 'handler was called'); + assert.strictEqual(e.component, radioGroup, 'component is correct'); + assert.strictEqual(e.element, radioGroup.element(), 'element is correct'); + assert.strictEqual(e.event.type, 'dxclick', 'event is correct'); + assert.strictEqual(e.value, 1, 'itemData is correct'); + }); + test('onValueChanged option should get jQuery event as a parameter', function(assert) { let jQueryEvent; const $radioGroup = createRadioGroup({ @@ -509,7 +547,7 @@ module('keyboard navigation', moduleConfig, () => { disabled: true }); - assert.ok($element.attr('tabindex') === undefined, 'collection of radio group has not tabindex'); + assert.strictEqual($element.attr('tabindex'), undefined, 'collection of radio group has not tabindex'); }); test('radio group items should not have tabIndex(T674238)', function(assert) { @@ -520,8 +558,8 @@ module('keyboard navigation', moduleConfig, () => { }); const $items = $element.find('.' + RADIO_BUTTON_CLASS); - assert.ok($items.eq(0).attr('tabindex') === undefined, 'items of radio group hasn\'t tabindex'); - assert.ok($items.eq(1).attr('tabindex') === undefined, 'items of radio group hasn\'t tabindex'); + assert.strictEqual($items.eq(0).attr('tabindex'), undefined, 'items of radio group hasn\'t tabindex'); + assert.strictEqual($items.eq(1).attr('tabindex'), undefined, 'items of radio group hasn\'t tabindex'); }); }); @@ -640,6 +678,46 @@ module('focus policy', moduleConfig, () => { }); module('option changed', () => { + test('focusStateEnabled option change', function(assert) { + const $radioGroup = createRadioGroup({ + focusStateEnabled: true + }); + const instance = getInstance($radioGroup); + + instance.option('focusStateEnabled', false); + assert.strictEqual(instance.$element().attr('tabindex'), undefined, 'element is not focusable'); + + instance.option('focusStateEnabled', true); + assert.strictEqual(instance.$element().attr('tabindex'), '0', 'element is focusable'); + }); + + test('items option change', function(assert) { + const $radioGroup = createRadioGroup({ + items: [1, 2, 3] + }); + const instance = getInstance($radioGroup); + + assert.equal($(instance.itemElements()).eq(0).text(), '1', 'item is correct'); + instance.option('items', [4, 5, 6]); + assert.equal($(instance.itemElements()).eq(0).text(), '4', 'item is correct'); + }); + + test('displayExpr option change', function(assert) { + const radioGroup = getInstance( + createRadioGroup({ + dataSource: [{ id: 1, name: 'Item 1' }], + valueExpr: 'id', + displayExpr: 'id', + value: 1 + }) + ); + + radioGroup.option('displayExpr', 'name'); + + const $item = $(radioGroup.itemElements()).eq(0); + assert.strictEqual($item.text(), 'Item 1', 'displayExpr works'); + }); + test('items from the getDataSource method are wrong when the dataSource option is changed', function(assert) { const instance = getInstance( createRadioGroup({ diff --git a/testing/tests/DevExpress.ui.widgets.editors/selectBox.tests.js b/testing/tests/DevExpress.ui.widgets.editors/selectBox.tests.js index ac468fd70bff..a82c8db74779 100644 --- a/testing/tests/DevExpress.ui.widgets.editors/selectBox.tests.js +++ b/testing/tests/DevExpress.ui.widgets.editors/selectBox.tests.js @@ -945,6 +945,45 @@ QUnit.module('widget options', moduleSetup, () => { assert.equal(count, 4); }); + QUnit.test('selectionChanged - subscription by "on" method', function(assert) { + const selectionChangedHandler = sinon.spy(); + const items = [1, 2, 3]; + + const selectBox = $('#selectBox').dxSelectBox({ + dataSource: items, + value: items[0] + }).dxSelectBox('instance'); + + selectBox.on('selectionChanged', selectionChangedHandler); + + assert.strictEqual(selectBox.option('selectedItem'), items[0], 'selectedItem is correct on init'); + + selectBox.option('value', items[0]); + assert.equal(selectionChangedHandler.callCount, 0, 'selectionChanged should not fire twice'); + + selectBox.option('value', items[1]); + assert.equal(selectionChangedHandler.callCount, 1, 'selectionChanged has been fired'); + }); + + QUnit.test('selectionChanged - runtime change', function(assert) { + const selectionChangedFirstHandler = sinon.spy(); + const selectionChangedSecondHandler = sinon.spy(); + + const items = [1, 2, 3]; + + const selectBox = $('#selectBox').dxSelectBox({ + dataSource: items, + value: items[0], + onSelectionChanged: selectionChangedFirstHandler + }).dxSelectBox('instance'); + + assert.equal(selectionChangedFirstHandler.callCount, 1, 'selectionChanged handler is correct'); + + selectBox.option('onSelectionChanged', selectionChangedSecondHandler); + selectBox.option('value', items[1]); + assert.equal(selectionChangedSecondHandler.callCount, 1, 'selectionChanged handler is correct'); + }); + QUnit.test('options displayExpr, valueExpr', function(assert) { assert.expect(5); @@ -3140,6 +3179,27 @@ QUnit.module('search substitution', { assert.equal(this.$input.val(), this.testItem[0], 'search value is not substituted'); }); + QUnit.test('autocompletionEnabled - runtime change', function(assert) { + this.reinit({ + items: [this.testItem], + searchTimeout: 0, + searchEnabled: true, + focusStateEnabled: true, + searchMode: 'startswith' + }); + + this.keyboard + .focus() + .type(this.testItem[0]); + + this.selectBox.option('autocompletionEnabled', false); + this.keyboard + .focus() + .type(this.testItem[1]); + + assert.equal(this.$input.val(), this.testItem[0] + this.testItem[1], 'search value is not substituted after option runtime change'); + }); + QUnit.test('search value is substituted while typing', function(assert) { const itemLength = this.testItem.length; const inputElement = this.$input.get(0); diff --git a/testing/tests/DevExpress.ui.widgets.editors/slider.tests.js b/testing/tests/DevExpress.ui.widgets.editors/slider.tests.js index 5994d1bd1356..3604ce78843c 100644 --- a/testing/tests/DevExpress.ui.widgets.editors/slider.tests.js +++ b/testing/tests/DevExpress.ui.widgets.editors/slider.tests.js @@ -1145,7 +1145,7 @@ module('keyboard navigation', moduleOptions, () => { const $handle = $slider.find('.' + SLIDER_HANDLE_CLASS); keyboardMock($handle).press('left'); - assert.ok(spy.called === false, 'the onValueChanged is not called'); + assert.strictEqual(spy.called, false, 'the onValueChanged is not called'); }); test('T380070 - the value should not be changed on the \'right\' key press if the value is max', function(assert) { @@ -1159,7 +1159,7 @@ module('keyboard navigation', moduleOptions, () => { const $handle = $slider.find('.' + SLIDER_HANDLE_CLASS); keyboardMock($handle).press('right'); - assert.ok(spy.called === false, 'the onValueChanged is not called'); + assert.strictEqual(spy.called, false, 'the onValueChanged is not called'); }); }); diff --git a/testing/tests/DevExpress.ui.widgets.editors/switch.tests.js b/testing/tests/DevExpress.ui.widgets.editors/switch.tests.js index ba41e4a1600e..6e1711579ee4 100644 --- a/testing/tests/DevExpress.ui.widgets.editors/switch.tests.js +++ b/testing/tests/DevExpress.ui.widgets.editors/switch.tests.js @@ -269,20 +269,23 @@ QUnit.module('interaction', { }); QUnit.test('swipe gesture is to fire onValueChanged', function(assert) { - let counter = 0; - + const valueChangeStub = sinon.stub(); const $element = $('#switch').dxSwitch({ value: true, - 'onValueChanged': function() { counter++; } + onValueChanged: valueChangeStub }); const mouse = pointerMock($element); mouse.start().swipeStart().swipeEnd(-1); - assert.equal(counter, 1); + assert.ok(valueChangeStub.calledOnce); mouse.start().swipeStart().swipeEnd(1); - assert.equal(counter, 2); + assert.ok(valueChangeStub.calledTwice); + + const { event } = valueChangeStub.lastCall.args[0]; + assert.ok(event); + assert.strictEqual(event.type, 'dxswipeend'); }); QUnit.test('swipe doesn\'t turn off feedback during gesture', function(assert) { diff --git a/testing/tests/DevExpress.ui.widgets.editors/tagBox.tests.js b/testing/tests/DevExpress.ui.widgets.editors/tagBox.tests.js index b933d8f33820..02973dc5c3c3 100644 --- a/testing/tests/DevExpress.ui.widgets.editors/tagBox.tests.js +++ b/testing/tests/DevExpress.ui.widgets.editors/tagBox.tests.js @@ -331,7 +331,7 @@ QUnit.module('tags', moduleSetup, () => { }); this.clock.tick(TIME_TO_WAIT); - assert.ok($element.find('.' + LIST_ITEM_CLASS).length === 3, 'found 3 items'); + assert.strictEqual($element.find('.' + LIST_ITEM_CLASS).length, 3, 'found 3 items'); $($element.find('.' + LIST_ITEM_CLASS).first()).trigger('dxclick'); assert.equal($element.find('.' + TAGBOX_TAG_CLASS).length, 1, 'tag is added'); @@ -708,7 +708,7 @@ QUnit.module('multi tag support', { assert.equal($tagBox.find('.' + TAGBOX_TAG_CLASS).length, 4, '4 tags when option was disabled'); }); - QUnit.test('onMultitagPreparing option change', function(assert) { + QUnit.test('onMultiTagPreparing option change', function(assert) { assert.expect(4); const onMultiTagPreparing = e => { @@ -732,6 +732,28 @@ QUnit.module('multi tag support', { assert.deepEqual($tag.text(), 'custom text', 'custom text is displayed'); }); + QUnit.test('multitagPreparing event test', function(assert) { + assert.expect(4); + + const onMultiTagPreparing = e => { + assert.equal(e.component.NAME, 'dxTagBox', 'component is correct'); + assert.ok($(e.multiTagElement).hasClass(TAGBOX_MULTI_TAG_CLASS), 'element is correct'); + assert.deepEqual(e.selectedItems, [1, 2, 4], 'selectedItems are correct'); + e.text = 'custom text'; + }; + const $tagBox = $('#tagBox').dxTagBox({ + items: [1, 2, 3, 4], + maxDisplayedTags: 2 + }); + const tagBox = $tagBox.dxTagBox('instance'); + + tagBox.on('multiTagPreparing', onMultiTagPreparing); + tagBox.option('value', [1, 2, 4]); + + const $tag = $tagBox.find('.' + TAGBOX_TAG_CLASS); + assert.deepEqual($tag.text(), 'custom text', 'custom text is displayed'); + }); + QUnit.test('tags should be rerendered after showMultiTagOnly option changed', function(assert) { const $tagBox = $('#tagBox').dxTagBox({ items: [1, 2, 3, 4], @@ -3582,6 +3604,21 @@ QUnit.module('the \'selectedItems\' option', moduleSetup, () => { assert.deepEqual(tagBox.option('selectedItems'), [items[1]], 'the \'selectedItems\' option value is correct'); }); + QUnit.test('onSelectionChanged handler should be called if selected items was changed at runtime', function(assert) { + const items = [1, 2, 3]; + const selectionChangedHandler = sinon.spy(); + + const tagBox = $('#tagBox').dxTagBox({ + items, + opened: true, + onSelectionChanged: selectionChangedHandler + }).dxTagBox('instance'); + + const callCountOnInit = selectionChangedHandler.callCount; + tagBox.option('selectedItems', [items[0], items[1]]); + assert.strictEqual(selectionChangedHandler.callCount, callCountOnInit + 1, 'onSelectionChanged handler was called'); + }); + QUnit.test('The \'selectedItems\' option changes after the \'value\' option', function(assert) { const items = [1, 2, 3]; @@ -3796,6 +3833,20 @@ QUnit.module('the \'onSelectionChanged\' option', moduleSetup, () => { assert.deepEqual(spy.args[1][0].removedItems, [data[2]], 'the \'removedItems\' argument'); assert.equal(spy.args[1][0].addedItems.length, 0, 'the \'addedItems\' argument'); }); + + QUnit.test('selectionChanged event should be raised if selected items were changed', function(assert) { + const items = [1, 2, 3]; + const selectionChangedHandler = sinon.spy(); + const tagBox = $('#tagBox').dxTagBox({ + items, + opened: true + }).dxTagBox('instance'); + + tagBox.on('selectionChanged', selectionChangedHandler); + tagBox.option('value', [1]); + + assert.strictEqual(selectionChangedHandler.callCount, 1, 'selectionChanged event was raised'); + }); }); QUnit.module('the \'fieldTemplate\' option', moduleSetup, () => { @@ -4363,7 +4414,7 @@ QUnit.module('the \'onSelectAllValueChanged\' option', { assert.ok(this.spy.args[this.spy.args.length - 1][0].value, 'all items are selected'); $($selectAllCheckbox).trigger('dxclick'); - assert.ok(this.spy.args[this.spy.args.length - 1][0].value === false, 'all items are unselected'); + assert.strictEqual(this.spy.args[this.spy.args.length - 1][0].value, false, 'all items are unselected'); }); QUnit.test('the \'onSelectAllValueChanged\' action is fired only one time if all items are selected', function(assert) { @@ -4399,6 +4450,26 @@ QUnit.module('the \'onSelectAllValueChanged\' option', { $($list.find('.dx-list-item').eq(0)).trigger('dxclick'); assert.equal(this.spy.callCount, 1, 'count is correct'); }); + + QUnit.test('the "selectAllValueChanged" event is fired one time after all items selection changing', function(assert) { + const spy = sinon.spy(); + + this.reinit({ + items: this.items, + value: this.items.splice(), + onSelectAllValueChanged: null + }); + + const $list = this.instance._list.$element(); + const $selectAllElement = $($list.find('.dx-list-select-all-checkbox')); + $selectAllElement.trigger('dxclick'); + assert.equal(this.spy.callCount, 0, 'count is correct'); + + this.instance.on('selectAllValueChanged', spy); + $selectAllElement.trigger('dxclick'); + + assert.equal(spy.callCount, 1, 'count is correct'); + }); }); QUnit.module('single line mode', { @@ -5205,6 +5276,25 @@ QUnit.module('performance', () => { assert.strictEqual(load.getCall(0).args[0].filter, undefined); }); + QUnit.test('load filter should be undefined when tagBox has some initial values and "maxFilterLength" was changed at runtime', function(assert) { + const load = sinon.stub(); + + const instance = $('#tagBox').dxTagBox({ + dataSource: { + load + }, + value: Array.apply(null, { length: 1 }).map(Number.call, Number), + valueExpr: 'id', + displayExpr: 'text' + }).dxTagBox('instance'); + + instance.option('maxFilterLength', 0); + instance.option('value', Array.apply(null, { length: 2 }).map(Number.call, Number)); + + assert.ok(load.getCall(0).args[0].filter); + assert.strictEqual(load.getCall(load.callCount - 1).args[0].filter, undefined); + }); + QUnit.test('load filter should be array when tagBox has not a lot of initial values', function(assert) { const load = sinon.stub(); diff --git a/testing/tests/DevExpress.ui.widgets.editors/textEditorParts/common.tests.js b/testing/tests/DevExpress.ui.widgets.editors/textEditorParts/common.tests.js index 3b558b3591b8..42eca25a47e4 100644 --- a/testing/tests/DevExpress.ui.widgets.editors/textEditorParts/common.tests.js +++ b/testing/tests/DevExpress.ui.widgets.editors/textEditorParts/common.tests.js @@ -749,7 +749,7 @@ QUnit.module('options changing', moduleConfig, () => { instance.option('onValueChanged', handleValueUpdateEvent); pointerMock($element.find('.dx-clear-button-area')).click(); clock.tick(10); - assert.ok($input.val() === '', 'Click on \'clear\' button causes input value reset'); + assert.strictEqual($input.val(), '', 'Click on \'clear\' button causes input value reset'); assert.ok($element.hasClass(EMPTY_INPUT_CLASS), 'Click on \'clear\' button causes marking with \'empty input\' CSS class'); assert.equal(eventWasHandled, 1, 'Click on \'clear\' button rises value update event'); clock.restore(); diff --git a/testing/tests/DevExpress.ui.widgets.editors/validatorIntegration.tests.js b/testing/tests/DevExpress.ui.widgets.editors/validatorIntegration.tests.js index f2b3f76f1ca1..1f5de50cad6c 100644 --- a/testing/tests/DevExpress.ui.widgets.editors/validatorIntegration.tests.js +++ b/testing/tests/DevExpress.ui.widgets.editors/validatorIntegration.tests.js @@ -3,6 +3,7 @@ import Class from 'core/class'; import ValidationEngine from 'ui/validation_engine'; import Validator from 'ui/validator'; import keyboardMock from '../../helpers/keyboardMock.js'; +import '../../helpers/ignoreQuillTimers.js'; import 'common.css!'; import 'generic_light.css!'; diff --git a/testing/tests/DevExpress.ui.widgets.pivotGrid/fieldChooser.tests.js b/testing/tests/DevExpress.ui.widgets.pivotGrid/fieldChooser.tests.js index a91da822f496..6177a43f1066 100644 --- a/testing/tests/DevExpress.ui.widgets.pivotGrid/fieldChooser.tests.js +++ b/testing/tests/DevExpress.ui.widgets.pivotGrid/fieldChooser.tests.js @@ -2096,6 +2096,80 @@ QUnit.test('headerFilter items if showRelevantValues is true', function(assert) ], 'getFieldValues calling args'); }); +// T852897 +QUnit.test('Custom texts.emptyValue in header filter', function(assert) { + const that = this; + let listItems; + let fieldElements; + const fields = [ + { caption: 'Field 1', area: 'column', index: 0, areaIndex: 0, allowSorting: true, allowFiltering: true } + ]; + const dataSourceOptions = { + columnFields: fields, + fieldValues: [ + [{ value: 1, text: '1' }, { value: 2, text: '' }] + ] + }; + + this.setup(dataSourceOptions, { + headerFilter: { + texts: { + emptyValue: 'Test' + } + } + }); + + $.each(fields, function(_, field) { + that.$container.append(that.fieldChooser.renderField(field)); + }); + + fieldElements = that.$container.find('.dx-area-field'); + + // act + fieldElements.first().find('.dx-header-filter').trigger('dxclick'); + this.clock.tick(500); + + // assert + listItems = $('.dx-list').dxList('instance').option('items'); + + assert.equal(listItems.length, 2, 'header filter items'); + assert.equal(listItems[1].text, 'Test'); +}); + +// T852897 +QUnit.test('Default texts.emptyValue in header filter', function(assert) { + const that = this; + let listItems; + let fieldElements; + const fields = [ + { caption: 'Field 1', area: 'column', index: 0, areaIndex: 0, allowSorting: true, allowFiltering: true } + ]; + const dataSourceOptions = { + columnFields: fields, + fieldValues: [ + [{ value: 1, text: '' }, { value: 2, text: '2' }] + ] + }; + + this.setup(dataSourceOptions); + + $.each(fields, function(_, field) { + that.$container.append(that.fieldChooser.renderField(field)); + }); + + fieldElements = that.$container.find('.dx-area-field'); + + // act + fieldElements.first().find('.dx-header-filter').trigger('dxclick'); + this.clock.tick(500); + + // assert + listItems = $('.dx-list').dxList('instance').option('items'); + + assert.equal(listItems.length, 2, 'header filter items'); + assert.equal(listItems[0].text, '(Blanks)'); +}); + QUnit.module('applyChangesMode: onDemand', { beforeEach: function() { this.$container = $('#container'); diff --git a/testing/tests/DevExpress.ui.widgets.scheduler/appointmentPopup.tests.js b/testing/tests/DevExpress.ui.widgets.scheduler/appointmentPopup.tests.js index 235ad946ddfa..fd1a98e97232 100644 --- a/testing/tests/DevExpress.ui.widgets.scheduler/appointmentPopup.tests.js +++ b/testing/tests/DevExpress.ui.widgets.scheduler/appointmentPopup.tests.js @@ -124,6 +124,26 @@ QUnit.module('Appointment popup form', moduleConfig, () => { }); }); + QUnit.test('Appointment popup should be with correct dates after change allDay switch and w/o saving (T832711)', function(assert) { + const scheduler = createScheduler({ dataSource: [] }); + const data = { + text: 'all day apo', + startDate: new Date(2017, 4, 1, 9, 30), + endDate: new Date(2017, 4, 1, 11), + allDay: true + }; + + scheduler.instance.showAppointmentPopup(data); + const allDayEditor = scheduler.appointmentForm.getEditor('allDay'); + allDayEditor.option('value', false); + scheduler.appointmentPopup.clickCancelButton(); + + scheduler.instance.showAppointmentPopup(data); + + assert.deepEqual(scheduler.appointmentForm.getEditor('startDate').option('value'), data.startDate); + assert.deepEqual(scheduler.appointmentForm.getEditor('endDate').option('value'), data.endDate); + }); + QUnit.test('onAppointmentFormOpening event should handle e.cancel value', function(assert) { const data = [{ text: 'Website Re-Design Plan', @@ -186,13 +206,14 @@ QUnit.module('Appointment popup form', moduleConfig, () => { assert.ok(scheduler.appointmentPopup.form.isRecurrenceEditorVisible(), 'Recurrence editor should be visible after click on recurrence appointment'); assert.equal(scheduler.appointmentPopup.form.getSubject(), defaultData[0].text, 'Subject in form should equal selected appointment'); - scheduler.appointmentPopup.clickDoneButton(); + // TODO: Fix unstable test asserts + // scheduler.appointmentPopup.clickDoneButton(); - scheduler.appointments.click(); // click on common appointment, due to redrawing its index has changed - scheduler.tooltip.clickOnItem(); + // scheduler.appointments.click(); // click on common appointment, due to redrawing its index has changed + // scheduler.tooltip.clickOnItem(); - assert.notOk(scheduler.appointmentPopup.form.isRecurrenceEditorVisible(), 'Recurrence editor shouldn\'t visible on click on common appointment'); - assert.equal(scheduler.appointmentPopup.form.getSubject(), NEW_EXPECTED_SUBJECT, 'Subject in form should equal selected common appointment'); + // assert.notOk(scheduler.appointmentPopup.form.isRecurrenceEditorVisible(), 'Recurrence editor shouldn\'t visible on click on common appointment'); + // assert.equal(scheduler.appointmentPopup.form.getSubject(), NEW_EXPECTED_SUBJECT, 'Subject in form should equal selected common appointment'); }); }); @@ -740,7 +761,6 @@ QUnit.test('Popup should contains allDay editor', function(assert) { }); QUnit.test('allDay changing should switch date & type in editors', function(assert) { - this.instance.option('startDayHour', 5); this.instance.showAppointmentPopup({ startDate: new Date(2015, 1, 1, 6), @@ -753,7 +773,6 @@ QUnit.test('allDay changing should switch date & type in editors', function(asse allDayEditor.option('value', true); - const startDate = $popupContent.find('.dx-datebox').eq(0).dxDateBox('instance'); const endDate = $popupContent.find('.dx-datebox').eq(1).dxDateBox('instance'); diff --git a/testing/tests/DevExpress.ui.widgets.scheduler/appointments.tests.js b/testing/tests/DevExpress.ui.widgets.scheduler/appointments.tests.js index 0096df14b724..1ddf54830370 100644 --- a/testing/tests/DevExpress.ui.widgets.scheduler/appointments.tests.js +++ b/testing/tests/DevExpress.ui.widgets.scheduler/appointments.tests.js @@ -1041,13 +1041,11 @@ QUnit.test('Focus method should call focus on appointment', function(assert) { const focusSpy = sinon.spy(eventsEngine, 'trigger').withArgs(sinon.match(function($element) { return config().useJQuery ? $element.get(0) === focusedElement : $element === focusedElement; }), 'focus'); - const appointmentFocusedStub = sinon.stub(this.instance, 'notifyObserver').withArgs('appointmentFocused'); this.instance.focus(); this.clock.tick(); assert.ok(focusSpy.called, 'focus is called'); - assert.ok(appointmentFocusedStub.called, 'appointmentFocused is fired'); sinon.restore(); eventsEngine.trigger = initialTrigger; diff --git a/testing/tests/DevExpress.ui.widgets.scheduler/common.markup.tests.js b/testing/tests/DevExpress.ui.widgets.scheduler/common.markup.tests.js index 48ca67a39631..ae99dcabdb4a 100644 --- a/testing/tests/DevExpress.ui.widgets.scheduler/common.markup.tests.js +++ b/testing/tests/DevExpress.ui.widgets.scheduler/common.markup.tests.js @@ -1,7 +1,7 @@ import $ from 'jquery'; import fx from 'animation/fx'; import dxScheduler from 'ui/scheduler/ui.scheduler'; -import DataSource from 'data/data_source/data_source'; +import { DataSource } from 'data/data_source/data_source'; import dateUtils from 'core/utils/date'; import dxSchedulerAppointmentModel from 'ui/scheduler/ui.scheduler.appointment_model'; @@ -54,7 +54,7 @@ QUnit.module('Scheduler markup', moduleConfig, () => { }); QUnit.test('Scheduler should not fail when dataSource is set', function(assert) { - const data = new DataSource.DataSource({ + const data = new DataSource({ store: this.tasks }); @@ -66,11 +66,11 @@ QUnit.module('Scheduler markup', moduleConfig, () => { }).dxScheduler('instance'); assert.ok(instance._appointmentModel instanceof dxSchedulerAppointmentModel, 'Task model is initialized on scheduler init'); - assert.ok(instance._appointmentModel._dataSource instanceof DataSource.DataSource, 'Task model has data source instance'); + assert.ok(instance._appointmentModel._dataSource instanceof DataSource, 'Task model has data source instance'); }); QUnit.test('Scheduler should not fail when dataSource is set, timelineView', function(assert) { - const data = new DataSource.DataSource({ + const data = new DataSource({ store: this.tasks }); @@ -82,11 +82,11 @@ QUnit.module('Scheduler markup', moduleConfig, () => { }).dxScheduler('instance'); assert.ok(instance._appointmentModel instanceof dxSchedulerAppointmentModel, 'Task model is initialized on scheduler init'); - assert.ok(instance._appointmentModel._dataSource instanceof DataSource.DataSource, 'Task model has data source instance'); + assert.ok(instance._appointmentModel._dataSource instanceof DataSource, 'Task model has data source instance'); }); QUnit.test('Scheduler should not fail when dataSource is set, timelineWeek', function(assert) { - const data = new DataSource.DataSource({ + const data = new DataSource({ store: this.tasks }); @@ -98,11 +98,11 @@ QUnit.module('Scheduler markup', moduleConfig, () => { }).dxScheduler('instance'); assert.ok(instance._appointmentModel instanceof dxSchedulerAppointmentModel, 'Task model is initialized on scheduler init'); - assert.ok(instance._appointmentModel._dataSource instanceof DataSource.DataSource, 'Task model has data source instance'); + assert.ok(instance._appointmentModel._dataSource instanceof DataSource, 'Task model has data source instance'); }); QUnit.test('Scheduler should not fail when dataSource is set, agenda', function(assert) { - const data = new DataSource.DataSource({ + const data = new DataSource({ store: this.tasks }); @@ -114,7 +114,7 @@ QUnit.module('Scheduler markup', moduleConfig, () => { }).dxScheduler('instance'); assert.ok(instance._appointmentModel instanceof dxSchedulerAppointmentModel, 'Task model is initialized on scheduler init'); - assert.ok(instance._appointmentModel._dataSource instanceof DataSource.DataSource, 'Task model has data source instance'); + assert.ok(instance._appointmentModel._dataSource instanceof DataSource, 'Task model has data source instance'); }); QUnit.test('Header & work space currentDate should not contain information about hours, minutes, seconds', function(assert) { diff --git a/testing/tests/DevExpress.ui.widgets.scheduler/common.tests.js b/testing/tests/DevExpress.ui.widgets.scheduler/common.tests.js index aeebfe6a7e7d..2e31d51ee1e7 100644 --- a/testing/tests/DevExpress.ui.widgets.scheduler/common.tests.js +++ b/testing/tests/DevExpress.ui.widgets.scheduler/common.tests.js @@ -361,7 +361,7 @@ QUnit.testStart(function() { this.instance.addAppointment({ startDate: new Date(2015, 1, 9, 16), endDate: new Date(2015, 1, 9, 17), text: 'caption' }); this.clock.tick(); - assert.ok(this.instance.option('dataSource').items().length === 3, 'new item is added'); + assert.strictEqual(this.instance.option('dataSource').items().length, 3, 'new item is added'); }); QUnit.test('Add new item with empty text', function(assert) { @@ -378,7 +378,7 @@ QUnit.testStart(function() { this.instance.addAppointment({ startDate: new Date(2015, 1, 9, 16), endDate: new Date(2015, 1, 9, 17) }); this.clock.tick(); - assert.ok(this.instance.option('dataSource').items()[2].text === '', 'new item was added with correct text'); + assert.strictEqual(this.instance.option('dataSource').items()[2].text, '', 'new item was added with correct text'); }); QUnit.test('Add new item when timezone doesn\'t equal to the default value', function(assert) { @@ -2131,7 +2131,7 @@ QUnit.testStart(function() { this.instance.addAppointment({ startDate: new Date(), text: 'Appointment 1' }); this.clock.tick(); - assert.ok(dataSource.items().length === 0, 'Insert operation is canceled'); + assert.strictEqual(dataSource.items().length, 0, 'Insert operation is canceled'); }); QUnit.test('Appointment should not be added to the data source if \'cancel\' flag is defined as true during async operation', function(assert) { @@ -2151,7 +2151,7 @@ QUnit.testStart(function() { this.instance.addAppointment({ startDate: new Date(), text: 'Appointment 1' }); this.clock.tick(200); - assert.ok(dataSource.items().length === 0, 'Insert operation is canceled'); + assert.strictEqual(dataSource.items().length, 0, 'Insert operation is canceled'); }); QUnit.test('Appointment should not be added to the data source if \'cancel\' flag is defined as Promise', function(assert) { @@ -2174,7 +2174,7 @@ QUnit.testStart(function() { this.clock.tick(200); promise.then(function() { - assert.ok(dataSource.items().length === 0, 'Insert operation is canceled'); + assert.strictEqual(dataSource.items().length, 0, 'Insert operation is canceled'); }); return promise; diff --git a/testing/tests/DevExpress.ui.widgets.scheduler/editing.tests.js b/testing/tests/DevExpress.ui.widgets.scheduler/editing.tests.js index 996f312f283b..4a519b8630f7 100644 --- a/testing/tests/DevExpress.ui.widgets.scheduler/editing.tests.js +++ b/testing/tests/DevExpress.ui.widgets.scheduler/editing.tests.js @@ -409,14 +409,14 @@ QUnit.test('Appointment should not be deleted, if allowUpdating || allowDeleting }); let appointments = this.instance.$element().find('.dx-scheduler-scrollable-appointments').dxSchedulerAppointments('instance'); - assert.ok(appointments.option('allowDelete') === false, 'Delete is not allowed'); + assert.strictEqual(appointments.option('allowDelete'), false, 'Delete is not allowed'); this.instance.option('editing', { allowUpdating: false, allowDeleting: true }); - assert.ok(appointments.option('allowDelete') === false, 'Delete is not allowed'); + assert.strictEqual(appointments.option('allowDelete'), false, 'Delete is not allowed'); this.instance.option('editing', { allowUpdating: true, @@ -424,5 +424,5 @@ QUnit.test('Appointment should not be deleted, if allowUpdating || allowDeleting }); appointments = this.instance.$element().find('.dx-scheduler-scrollable-appointments').dxSchedulerAppointments('instance'); - assert.ok(appointments.option('allowDelete') === true, 'Delete is allowed'); + assert.strictEqual(appointments.option('allowDelete'), true, 'Delete is allowed'); }); diff --git a/testing/tests/DevExpress.ui.widgets.scheduler/integration.adaptivity.tests.js b/testing/tests/DevExpress.ui.widgets.scheduler/integration.adaptivity.tests.js index 044ba8859f4e..e43b1586dd12 100644 --- a/testing/tests/DevExpress.ui.widgets.scheduler/integration.adaptivity.tests.js +++ b/testing/tests/DevExpress.ui.widgets.scheduler/integration.adaptivity.tests.js @@ -113,7 +113,7 @@ module('Mobile tooltip', moduleConfig, () => { appointmentTooltipTemplate: (model, index, contentElement) => { assert.equal(model.targetedAppointmentData.text, model.appointmentData.text, 'targetedAppointmentData should be not empty'); assert.equal(index, templateCallCount, 'Index should be correct pass in template callback'); - assert.ok($(contentElement).length === 1, 'contentElement should be DOM element'); + assert.strictEqual($(contentElement).length, 1, 'contentElement should be DOM element'); templateCallCount++; return $('
').addClass(TOOLTIP_TEMPLATE_MARKER_CLASS_NAME).text(`template item index - ${index}`); diff --git a/testing/tests/DevExpress.ui.widgets.scheduler/integration.allDayAppointments.tests.js b/testing/tests/DevExpress.ui.widgets.scheduler/integration.allDayAppointments.tests.js index a1f0710c8e0c..f2fe6ad96294 100644 --- a/testing/tests/DevExpress.ui.widgets.scheduler/integration.allDayAppointments.tests.js +++ b/testing/tests/DevExpress.ui.widgets.scheduler/integration.allDayAppointments.tests.js @@ -1527,8 +1527,8 @@ QUnit.test('Appointment in allDayPanel must not change position if `editing` opt $appointment = scheduler.appointments.getAppointment(); assert.ok($appointment.hasClass('dx-scheduler-all-day-appointment'), 'Appointment has `addDayAppointment` class'); - assert.ok($(scheduler.instance.$element()).find('.dx-scheduler-all-day-appointments .dx-scheduler-appointment').length === 1, 'Appointment is in `allDayAppointments` container'); - assert.ok(translator.locate($appointment).top === 0, 'Appointment is on top of it`s container'); + assert.strictEqual($(scheduler.instance.$element()).find('.dx-scheduler-all-day-appointments .dx-scheduler-appointment').length, 1, 'Appointment is in `allDayAppointments` container'); + assert.strictEqual(translator.locate($appointment).top, 0, 'Appointment is on top of it`s container'); }); QUnit.test('New allDay appointment should be rendered correctly when groupByDate = true (T845632)', function(assert) { @@ -1578,8 +1578,8 @@ QUnit.test('New allDay appointment should be rendered correctly when groupByDate const $appointment = scheduler.appointments.getAppointment(); assert.ok($appointment.hasClass('dx-scheduler-all-day-appointment'), 'Appointment has `addDayAppointment` class'); - assert.ok($(scheduler.instance.$element()).find('.dx-scheduler-all-day-appointments .dx-scheduler-appointment').length === 1, 'Appointment is in `allDayAppointments` container'); - assert.ok(translator.locate($appointment).top === 0, 'Appointment is on top of it`s container'); + assert.strictEqual($(scheduler.instance.$element()).find('.dx-scheduler-all-day-appointments .dx-scheduler-appointment').length, 1, 'Appointment is in `allDayAppointments` container'); + assert.strictEqual(translator.locate($appointment).top, 0, 'Appointment is on top of it`s container'); }); QUnit.test('Recurrence allDay appointment should be rendered correctly (T831801)', function(assert) { diff --git a/testing/tests/DevExpress.ui.widgets.scheduler/integration.appointments.tests.js b/testing/tests/DevExpress.ui.widgets.scheduler/integration.appointments.tests.js index ffce3bb4d4c4..ab60307fdfc5 100644 --- a/testing/tests/DevExpress.ui.widgets.scheduler/integration.appointments.tests.js +++ b/testing/tests/DevExpress.ui.widgets.scheduler/integration.appointments.tests.js @@ -3712,9 +3712,9 @@ QUnit.test('Long term appoinment inflict index shift in other appointments (T737 }); const appointments = this.instance._getAppointmentsToRepaint(); - assert.ok(appointments[0].settings[1].index === 0, 'Long term appointment tail has right index'); - assert.ok(appointments[1].settings[0].index === 1, 'Appointment next to long term appointment head has right index'); - assert.ok(appointments[2].settings[0].index === 1, 'Appointment next to long term appointment tail has right index'); + assert.strictEqual(appointments[0].settings[1].index, 0, 'Long term appointment tail has right index'); + assert.strictEqual(appointments[1].settings[0].index, 1, 'Appointment next to long term appointment head has right index'); + assert.strictEqual(appointments[2].settings[0].index, 1, 'Appointment next to long term appointment tail has right index'); }); QUnit.test('Multi-day appointment should be rendered when started after endDayHour (T819852)', function(assert) { @@ -3776,6 +3776,29 @@ QUnit.test('Appointment with equal startDate and endDate should render with 1 mi assert.equal(this.scheduler.appointments.getAppointmentHeight(0), this.scheduler.appointments.getAppointmentHeight(1), 'Appointment heights are equal'); }); +$.each(['month', 'timelineMonth'], (index, value) => { + QUnit.test(`Appointment with equal startDate and endDate should render in whole cell on ${value} view (T858496)`, function(assert) { + this.createInstance({ + dataSource: [{ + text: 'Zero-minute appointment', + startDate: new Date(2017, 4, 22, 0), + endDate: new Date(2017, 4, 22, 0) + }, { + text: 'Default appointment', + startDate: new Date(2017, 4, 22, 0), + endDate: new Date(2017, 4, 22, 1) + }], + views: [value], + currentView: value, + currentDate: new Date(2017, 4, 25), + height: 600, + }); + + assert.strictEqual(this.scheduler.appointments.getAppointmentCount(), 2, 'Appointments are rendered'); + assert.equal(this.scheduler.appointments.getAppointmentWidth(0), this.scheduler.appointments.getAppointmentWidth(1), 'Appointment widths are equal'); + }); +}); + QUnit.test('Multi-day appointment is hidden in compact collectors according to head and tail coordinates (T835541)', function(assert) { this.createInstance({ dataSource: [{ @@ -3821,7 +3844,7 @@ QUnit.module('Appointments', () => { return createWrapper($.extend(config, options)); }; - const createTestForCommonData = (assert, skipCallCount = false) => { + const createTestForCommonData = (assert, scheduler, skipCallCount = false) => { eventCallCount = 0; return (model, index, container) => { @@ -3841,7 +3864,6 @@ QUnit.module('Appointments', () => { return (model, index, container) => { const { appointmentData, targetedAppointmentData } = model; - const startDateExpr = scheduler.option('startDateExpr'); const endDateExpr = scheduler.option('endDateExpr'); const textExpr = scheduler.option('textExpr'); @@ -3960,14 +3982,14 @@ QUnit.module('Appointments', () => { const scheduler = createScheduler(commonData); scheduler.option({ appointmentTemplate: createTestForCommonData(assert) }); - assert.ok(eventCallCount === 5, 'appointmentTemplate should be raised'); + assert.strictEqual(eventCallCount, 5, 'appointmentTemplate should be raised'); }); QUnit.test('model.targetedAppointmentData argument should have current appointment data in case recurrence', function(assert) { const scheduler = createScheduler(recurrenceData); scheduler.option({ appointmentTemplate: createTestForRecurrenceData(assert, scheduler) }); - assert.ok(eventCallCount === 5, 'appointmentTemplate should be raised'); + assert.strictEqual(eventCallCount, 5, 'appointmentTemplate should be raised'); }); QUnit.test('model.targetedAppointmentData argument should have current appointment data in case recurrence and custom data properties', function(assert) { @@ -3978,59 +4000,65 @@ QUnit.module('Appointments', () => { }); scheduler.option({ appointmentTemplate: createTestForRecurrenceData(assert, scheduler) }); - assert.ok(eventCallCount === 5, 'appointmentTemplate should be raised'); + assert.strictEqual(eventCallCount, 5, 'appointmentTemplate should be raised'); }); }); QUnit.module('appointmentTooltipTemplate', () => { - QUnit.test('model.targetedAppointmentData argument should have current appointment data', function(assert) { - const scheduler = createScheduler(commonData); - scheduler.option({ appointmentTooltipTemplate: createTestForCommonData(assert, true) }); - - for(let i = 0; i < 5; i++) { - scheduler.appointments.click(i); - } - - assert.ok(eventCallCount === 5, 'appointmentTemplate should be raised'); - }); - - QUnit.test('model.targetedAppointmentData argument should have current appointment data in case recurrence', function(assert) { - const scheduler = createScheduler(recurrenceData); - scheduler.option({ appointmentTooltipTemplate: createTestForRecurrenceData(assert, scheduler) }); - - for(let i = 0; i < 5; i++) { - scheduler.appointments.click(i); + const cases = [ + { + data: commonData, + appointmentTooltip: createTestForCommonData, + name: 'common' + }, + { + data: recurrenceData, + appointmentTooltip: createTestForRecurrenceData, + name: 'recurrence' + }, + { + data: recurrenceAndCompactData, + appointmentTooltip: createTestForRecurrenceData, + name: 'recurrence in collector' + }, + { + data: hourlyRecurrenceData, + options: { + textExpr: 'textCustom', + startDateExpr: 'startDateCustom', + endDateExpr: 'endDateCustom', + currentView: 'week' + }, + appointmentTooltip: createTestForHourlyRecurrenceData, + name: 'hourly recurrence in collector' + }, + { + data: hourlyRecurrenceData, + options: { + textExpr: 'textCustom', + startDateExpr: 'startDateCustom', + endDateExpr: 'endDateCustom', + currentView: 'week', + timeZone: 'Asia/Yekaterinburg', + startDayHour: 0, + endDayHour: 24 + }, + appointmentTooltip: createTestForHourlyRecurrenceData, + name: 'hourly recurrence in collector, custom timezone is set' } + ]; - assert.ok(eventCallCount === 5, 'appointmentTooltipTemplate should be raised'); - }); - - QUnit.test('model.targetedAppointmentData argument should have current appointment data in case recurrence in collector', function(assert) { - const scheduler = createScheduler(recurrenceAndCompactData); - scheduler.option({ appointmentTooltipTemplate: createTestForRecurrenceData(assert, scheduler) }); - - for(let i = 0; i < 5; i++) { - scheduler.appointments.compact.click(i); - } + cases.forEach(testCase => { + QUnit.test(`model.targetedAppointmentData argument should have current appointment data, ${testCase.name} case`, function(assert) { + const scheduler = createScheduler(testCase.data, testCase.options); + scheduler.option('appointmentTooltipTemplate', testCase.appointmentTooltip(assert, scheduler, true)); - assert.ok(eventCallCount === 5, 'appointmentTooltipTemplate should be raised'); - }); + for(let i = 0; i < 5; i++) { + scheduler.appointments.click(i); + } - QUnit.test('model.targetedAppointmentData argument should have current appointment data in case hourly recurrence in collector', function(assert) { - const scheduler = createScheduler(hourlyRecurrenceData, { - textExpr: 'textCustom', - startDateExpr: 'startDateCustom', - endDateExpr: 'endDateCustom', - currentView: 'week' + assert.strictEqual(eventCallCount, 5, 'appointmentTemplate should be raised'); }); - - scheduler.option({ appointmentTooltipTemplate: createTestForHourlyRecurrenceData(assert, scheduler) }); - - for(let i = 0; i < 5; i++) { - scheduler.appointments.compact.click(i); - } - - assert.ok(eventCallCount === 5, 'appointmentTooltipTemplate should be raised'); }); }); diff --git a/testing/tests/DevExpress.ui.widgets.scheduler/integration.dstAppointments.tests.js b/testing/tests/DevExpress.ui.widgets.scheduler/integration.dstAppointments.tests.js index 8f7bea52c9d8..b0f92a825376 100644 --- a/testing/tests/DevExpress.ui.widgets.scheduler/integration.dstAppointments.tests.js +++ b/testing/tests/DevExpress.ui.widgets.scheduler/integration.dstAppointments.tests.js @@ -1,233 +1,308 @@ -const $ = require('jquery'); - -QUnit.testStart(function() { - $('#qunit-fixture').html('
'); -}); - -require('common.css!'); -require('generic_light.css!'); - - -const dateLocalization = require('localization/date'); -const fx = require('animation/fx'); -const subscribes = require('ui/scheduler/ui.scheduler.subscribes'); - -require('ui/scheduler/ui.scheduler'); - -const DATE_TABLE_CELL_CLASS = 'dx-scheduler-date-table-cell'; -const APPOINTMENT_CLASS = 'dx-scheduler-appointment'; - -function getDeltaTz(schedulerTz, date) { - const defaultTz = date.getTimezoneOffset() * 60000; - return schedulerTz * 3600000 + defaultTz; -} - -QUnit.module('Integration: Appointments', { - beforeEach: function() { +import { initTestMarkup, createWrapper } from './helpers.js'; +import dateLocalization from 'localization/date'; +import fx from 'animation/fx'; +import subscribes from 'ui/scheduler/ui.scheduler.subscribes'; +import { dateToMilliseconds as toMs } from 'core/utils/date'; + +import 'ui/scheduler/ui.scheduler'; +import 'common.css!'; +import 'generic_light.css!'; + +QUnit.testStart(() => initTestMarkup()); +const moduleConfig = { + beforeEach() { fx.off = true; - this.createInstance = function(options) { - this.instance = $('#scheduler').dxScheduler(options).dxScheduler('instance'); - }; this.clock = sinon.useFakeTimers(); }, - afterEach: function() { - fx.off = false; + + afterEach() { this.clock.restore(); + fx.off = false; } -}); +}; -QUnit.test('Appointment wich started in DST and ended in STD time should have correct start & end dates', function(assert) { - let startDate = 1541311200000; - let endDate = 1541319000000; - - this.createInstance({ - currentDate: new Date(2018, 10, 4), - views: ['week'], - currentView: 'week', - dataSource: [{ - text: 'DST', - startDate: startDate, - endDate: endDate - }], - timeZone: 'America/Chicago' - }); +QUnit.module('Appointments with DST/STD cases', moduleConfig, () => { + const getDeltaTz = (schedulerTz, date) => schedulerTz * toMs('hour') + date.getTimezoneOffset() * toMs('minute'); - startDate = new Date(startDate); - endDate = new Date(endDate); + QUnit.test('Appointment wich started in DST and ended in STD time should have correct start & end dates', function(assert) { + const startDate = new Date(1541311200000); + const endDate = new Date(1541319000000); - const $appointment = $(this.instance.$element()).find('.' + APPOINTMENT_CLASS).eq(0); - const deltaTzStart = getDeltaTz(-5, startDate); - const deltaTzEnd = getDeltaTz(-6, endDate); - const startDateByTz = new Date(startDate.setHours(startDate.getHours() + deltaTzStart / 3600000)); - const endDateByTz = new Date(endDate.setHours(endDate.getHours() + deltaTzEnd / 3600000)); - const resultDate = `${dateLocalization.format(startDateByTz, 'shorttime')} - ${dateLocalization.format(endDateByTz, 'shorttime')}`; + const scheduler = createWrapper({ + currentDate: new Date(2018, 10, 4), + views: ['week'], + currentView: 'week', + dataSource: [{ + text: 'DST', + startDate: startDate, + endDate: endDate + }], + timeZone: 'America/Chicago' + }); - assert.equal($appointment.find('.dx-scheduler-appointment-content div').eq(0).text(), 'DST', 'Text is correct on init'); - assert.equal($appointment.find('.dx-scheduler-appointment-content-date').eq(0).text(), resultDate, 'Date is correct on init'); -}); + const deltaTzStart = getDeltaTz(-5, startDate); + const deltaTzEnd = getDeltaTz(-6, endDate); + const startDateByTz = new Date(startDate.setHours(startDate.getHours() + deltaTzStart / toMs('hour'))); + const endDateByTz = new Date(endDate.setHours(endDate.getHours() + deltaTzEnd / toMs('hour'))); + const resultDateText = `${dateLocalization.format(startDateByTz, 'shorttime')} - ${dateLocalization.format(endDateByTz, 'shorttime')}`; -QUnit.test('Appointment wich started in STD and ended in DST time should have correct start & end dates', function(assert) { - let startDate = new Date(1520748000000); - let endDate = new Date(1520751600000); - - this.createInstance({ - currentDate: new Date(2018, 2, 11), - views: ['timelineDay'], - maxAppointmentsPerCell: null, - currentView: 'timelineDay', - dataSource: [{ - text: 'DST', - startDate: startDate, - endDate: endDate - }], - timeZone: 'America/New_York' + assert.equal(scheduler.appointments.getTitleText(), 'DST', 'Text is correct on init'); + assert.equal(scheduler.appointments.getDateText(), resultDateText, 'Date is correct on init'); }); - startDate = new Date(startDate); - endDate = new Date(endDate); + QUnit.test('Appointment wich started in STD and ended in DST time should have correct start & end dates', function(assert) { + const startDate = new Date(1520748000000); + const endDate = new Date(1520751600000); - const $appointment = $(this.instance.$element()).find('.' + APPOINTMENT_CLASS).eq(0); - const deltaTzStart = getDeltaTz(-5, startDate); - const deltaTzEnd = getDeltaTz(-4, endDate); - const startDateByTz = new Date(startDate.setHours(startDate.getHours() + deltaTzStart / 3600000)); - const endDateByTz = new Date(endDate.setHours(endDate.getHours() + deltaTzEnd / 3600000)); - const resultDate = `${dateLocalization.format(startDateByTz, 'shorttime')} - ${dateLocalization.format(endDateByTz, 'shorttime')}`; + const scheduler = createWrapper({ + currentDate: new Date(2018, 2, 11), + views: ['timelineDay'], + maxAppointmentsPerCell: null, + currentView: 'timelineDay', + dataSource: [{ + text: 'DST', + startDate: startDate, + endDate: endDate + }], + timeZone: 'America/New_York' + }); - assert.equal($appointment.find('.dx-scheduler-appointment-content div').eq(0).text(), 'DST', 'Text is correct on init'); - assert.equal($appointment.find('.dx-scheduler-appointment-content-date').eq(0).text(), resultDate, 'Date is correct on init'); -}); + const deltaTzStart = getDeltaTz(-5, startDate); + const deltaTzEnd = getDeltaTz(-4, endDate); + const startDateByTz = new Date(startDate.setHours(startDate.getHours() + deltaTzStart / toMs('hour'))); + const endDateByTz = new Date(endDate.setHours(endDate.getHours() + deltaTzEnd / toMs('hour'))); + const resultDateText = `${dateLocalization.format(startDateByTz, 'shorttime')} - ${dateLocalization.format(endDateByTz, 'shorttime')}`; -QUnit.test('Second recurring appointment wich started in STD and ended in DST time should have correct start & end dates & position', function(assert) { - let startDate = new Date(1520748000000); - let endDate = new Date(1520751600000); - - this.createInstance({ - currentDate: new Date(2018, 2, 12), - views: ['timelineDay'], - currentView: 'timelineDay', - maxAppointmentsPerCell: null, - dataSource: [{ - text: 'DST', - startDate: startDate, - endDate: endDate, - recurrenceRule: 'FREQ=DAILY' - }], - timeZone: 'America/New_York' + assert.equal(scheduler.appointments.getTitleText(), 'DST', 'Text is correct on init'); + assert.equal(scheduler.appointments.getDateText(), resultDateText, 'Date is correct on init'); }); - startDate = new Date(startDate); - endDate = new Date(endDate); + QUnit.test('Second recurring appointment wich started in STD and ended in DST time should have correct start & end dates & position', function(assert) { + const startDate = new Date(1520748000000); + const endDate = new Date(1520751600000); - const $appointment = $(this.instance.$element()).find('.' + APPOINTMENT_CLASS).eq(0); + const scheduler = createWrapper({ + currentDate: new Date(2018, 2, 12), + views: ['timelineDay'], + currentView: 'timelineDay', + maxAppointmentsPerCell: null, + dataSource: [{ + text: 'DST', + startDate: startDate, + endDate: endDate, + recurrenceRule: 'FREQ=DAILY' + }], + timeZone: 'America/New_York' + }); - assert.equal($appointment.find('.dx-scheduler-appointment-content div').eq(0).text(), 'DST', 'Text is correct on init'); - assert.equal($appointment.find('.dx-scheduler-appointment-content-date').eq(0).text(), '1:00 AM - 2:00 AM', 'Start Date is correct on init'); + assert.equal(scheduler.appointments.getTitleText(), 'DST', 'Text is correct on init'); + assert.equal(scheduler.appointments.getDateText(), '1:00 AM - 2:00 AM', 'Start Date is correct on init'); + assert.roughEqual(scheduler.appointments.getAppointment(0).outerWidth(), scheduler.workSpace.getCellWidth() * 2, 2, 'Appointment width is correct'); + }); - assert.roughEqual($appointment.get(0).getBoundingClientRect().width, $(this.instance.$element()).find('.' + DATE_TABLE_CELL_CLASS).get(0).getBoundingClientRect().width * 2, 2, 'Appointment width is correct'); -}); + // NOTE: Timezone-sensitive test, use US/Pacific for proper testing + QUnit.test('Appointment which started in DST and ended in STD time should have right width, timeline view', function(assert) { + const startDate = new Date(2018, 10, 4, 1); + const endDate = new Date(2018, 10, 4, 3); + const currentDate = new Date(2018, 10, 4); + + const scheduler = createWrapper({ + views: ['timelineWeek'], + currentView: 'timelineWeek', + cellDuration: 60, + currentDate: currentDate, + maxAppointmentsPerCell: null, + dataSource: [{ + text: 'DST', + startDate: startDate, + endDate: endDate + }] + }); + + const duration = (endDate - startDate) / toMs('hour'); + const tzDiff = (startDate.getTimezoneOffset() - endDate.getTimezoneOffset()) / 60; -QUnit.test('Appointment which started in DST and ended in STD time should have right width, timeline view', function(assert) { - const startDate = new Date(2018, 10, 4, 1); - const endDate = new Date(2018, 10, 4, 3); - const currentDate = new Date(2018, 10, 4); - - this.createInstance({ - views: ['timelineWeek'], - currentView: 'timelineWeek', - cellDuration: 60, - currentDate: currentDate, - maxAppointmentsPerCell: null, - dataSource: [{ - text: 'DST', - startDate: startDate, - endDate: endDate - }] + assert.roughEqual(scheduler.appointments.getAppointment(0).outerWidth(), scheduler.workSpace.getCellWidth() * (duration + tzDiff), 2.001, 'Appt width is correct on the day of the time ajusting'); }); - const $appointment = $(this.instance.$element()).find('.' + APPOINTMENT_CLASS).first(); - const cellWidth = this.instance.$element().find('.' + DATE_TABLE_CELL_CLASS).first().outerWidth(); - const duration = (endDate - startDate) / 3600000; - const tzDiff = (startDate.getTimezoneOffset() - endDate.getTimezoneOffset()) / 60; + QUnit.test('Second recurring appointment should have right width if previous appt started in STD and ended in DST, timeline view', function(assert) { + const startDate = new Date(1520758800000); + const endDate = new Date(1520762400000); + const currentDate = new Date(2018, 2, 12); - assert.roughEqual($appointment.outerWidth(), cellWidth * (duration + tzDiff), 2.001, 'Appt width is correct on the day of the time ajusting'); -}); + const scheduler = createWrapper({ + currentDate: currentDate, + views: ['timelineDay'], + currentView: 'timelineDay', + maxAppointmentsPerCell: null, + dataSource: [{ + text: 'DST', + startDate: startDate, + endDate: endDate, + recurrenceRule: 'FREQ=DAILY' + }], + cellDuration: 60, + timeZone: 'America/New_York' + }); -QUnit.test('Second recurring appointment should have right width if previous appt started in STD and ended in DST, timeline view', function(assert) { - const startDate = new Date(1520758800000); - const endDate = new Date(1520762400000); - const currentDate = new Date(2018, 2, 12); - - this.createInstance({ - currentDate: currentDate, - views: ['timelineDay'], - currentView: 'timelineDay', - maxAppointmentsPerCell: null, - dataSource: [{ - text: 'DST', - startDate: startDate, - endDate: endDate, - recurrenceRule: 'FREQ=DAILY' - }], - cellDuration: 60, - timeZone: 'America/New_York' - }); - this.instance.option('currentDate', this.instance.fire('convertDateByTimezone', currentDate, -5)); + scheduler.instance.option('currentDate', scheduler.instance.fire('convertDateByTimezone', currentDate, -5)); + const duration = (endDate - startDate) / toMs('hour'); - const $secondRecAppointment = $(this.instance.$element()).find('.' + APPOINTMENT_CLASS).first(); - const cellWidth = this.instance.$element().find('.' + DATE_TABLE_CELL_CLASS).first().outerWidth(); - const duration = (endDate - startDate) / 3600000; + assert.roughEqual(scheduler.appointments.getAppointment(0).outerWidth(), scheduler.workSpace.getCellWidth() * duration, 2.001, 'Appt width is correct after the day of the time ajusting'); + }); - assert.roughEqual($secondRecAppointment.outerWidth(), cellWidth * duration, 2.001, 'Appt width is correct after the day of the time ajusting'); -}); + QUnit.test('Recurrence exception should not be rendered if exception goes after adjusting AEST-> AEDT (T619455)', function(assert) { + const tzOffsetStub = sinon.stub(subscribes, 'getClientTimezoneOffset').returns(-39600000); + try { + const scheduler = createWrapper({ + dataSource: [{ + text: 'Recruiting students', + startDate: new Date(2018, 2, 30, 10, 0), + endDate: new Date(2018, 2, 30, 11, 0), + recurrenceRule: 'FREQ=DAILY', + recurrenceException: '20180401T100000' + }], + views: ['month'], + currentView: 'month', + currentDate: new Date(2018, 2, 30), + timeZone: 'Australia/Sydney', + height: 600 + }); + assert.equal(scheduler.appointments.getAppointmentCount(), 8, 'correct number of the events'); + + scheduler.instance.option('currentView', 'day'); + scheduler.instance.option('currentDate', new Date(2018, 3, 1)); + + assert.notOk(scheduler.appointments.getAppointmentCount(), 'event is an exception'); + } finally { + tzOffsetStub.restore(); + } + }); -QUnit.test('Recurrence exception should not be rendered if exception goes after adjusting AEST-> AEDT (T619455)', function(assert) { - const tzOffsetStub = sinon.stub(subscribes, 'getClientTimezoneOffset').returns(-39600000); - try { - this.createInstance({ + QUnit.test('Appointment should rendered correctly if end date appointment coincided translation oт STD', function(assert) { + const scheduler = createWrapper({ dataSource: [{ - text: 'Recruiting students', - startDate: new Date(2018, 2, 30, 10, 0), - endDate: new Date(2018, 2, 30, 11, 0), - recurrenceRule: 'FREQ=DAILY', - recurrenceException: '20180401T100000' + text: 'November 4', + startDate: new Date(2018, 10, 4, 18, 0), + endDate: new Date(2018, 10, 5, 0, 0), }], views: ['month'], currentView: 'month', - currentDate: new Date(2018, 2, 30), - timeZone: 'Australia/Sydney', - height: 600 + currentDate: new Date(2018, 10, 1), + firstDayOfWeek: 0, + cellDuration: 60, + height: 800 }); - const $appointments = $(this.instance.$element()).find('.' + APPOINTMENT_CLASS); + assert.roughEqual(scheduler.appointments.getAppointment(0).outerWidth(), scheduler.workSpace.getCellWidth(), 2.001, 'Appointment width is correct after translation oт STD'); + }); - assert.equal($appointments.length, 8, 'correct number of the events'); + QUnit.test('Recurrence appt part should be rendered correctly if recurrence starts in STD and ends in DST in custom timezone, appointment timezone is set (T804886)', function(assert) { + // NOTE: The daylight saving changed in Montreal on 10.03.2019 and in Paris on 31.03.2019 + const scheduler = createWrapper({ + dataSource: [ + { + text: 'Daily meeting', + startDate: '2019-03-01T09:00:00+01:00', + endDate: '2019-03-01T12:00:00+01:00', + recurrenceRule: 'FREQ=DAILY', + startDateTimeZone: 'Europe/Paris', + endDateTimeZone: 'Europe/Paris' + } + ], + views: ['day'], + currentView: 'day', + currentDate: new Date(2019, 2, 1), // NOTE: STD Montreal + startDayHour: 0, + height: 600, + timeZone: 'America/Montreal', + dateSerializationFormat: 'yyyy-MM-ddTHH:mm:ssx' + }); - this.instance.option('currentView', 'day'); - this.instance.option('currentDate', new Date(2018, 3, 1)); + let targetCell = scheduler.workSpace.getCell(6); + let appointment = scheduler.appointments.getAppointment(0); - assert.notOk($(this.instance.$element()).find('.' + APPOINTMENT_CLASS).length, 'event is an exception'); - } finally { - tzOffsetStub.restore(); - } -}); + assert.equal(appointment.position().top, targetCell.position().top, 'Recurrence appointment part is rendered in right cell'); + assert.equal(appointment.outerHeight(), targetCell.outerHeight() * 6, 'Recurrence appointment part has right size'); + + scheduler.instance.option('currentDate', new Date(2019, 2, 11)); // NOTE: DST Montreal, STD Paris + + targetCell = scheduler.workSpace.getCell(8); + appointment = scheduler.appointments.getAppointment(0); + + assert.equal(appointment.position().top, targetCell.position().top, 'Recurrence appointment part is rendered in right cell'); + assert.equal(appointment.outerHeight(), targetCell.outerHeight() * 6, 'Recurrence appointment part has right size'); -QUnit.test('Appointment should rendered correctly if end date appointment coincided translation oт STD', function(assert) { - this.createInstance({ - dataSource: [{ - text: 'November 4', - startDate: new Date(2018, 10, 4, 18, 0), - endDate: new Date(2018, 10, 5, 0, 0), - }], - views: ['month'], - currentView: 'month', - currentDate: new Date(2018, 10, 1), - firstDayOfWeek: 0, - cellDuration: 60, - height: 800 + scheduler.instance.option('currentDate', new Date(2019, 3, 1)); // NOTE: DST Paris + + targetCell = scheduler.workSpace.getCell(6); + appointment = scheduler.appointments.getAppointment(0); + + assert.equal(appointment.position().top, targetCell.position().top, 'Recurrence appointment part is rendered in right cell'); + assert.equal(appointment.outerHeight(), targetCell.outerHeight() * 6, 'Recurrence appointment part has right size'); + }); + + QUnit.test('Recurrence appt part should be rendered correctly if recurrence starts in STD and ends in DST in custom timezone', function(assert) { + // NOTE: The daylight saving changed in Montreal on 10.03.2019 + const scheduler = createWrapper({ + dataSource: [ + { + text: 'Daily meeting', + startDate: '2019-03-01T09:00:00+01:00', + endDate: '2019-03-01T12:00:00+01:00', + recurrenceRule: 'FREQ=DAILY' + } + ], + views: ['day'], + currentView: 'day', + currentDate: new Date(2019, 2, 5), // NOTE: STD Montreal + startDayHour: 0, + height: 600, + timeZone: 'America/Montreal', + dateSerializationFormat: 'yyyy-MM-ddTHH:mm:ssx' + }); + + let targetCell = scheduler.workSpace.getCell(6); + let appointment = scheduler.appointments.getAppointment(0); + + assert.equal(appointment.position().top, targetCell.position().top, 'Recurrence appointment part is rendered in right cell'); + assert.equal(appointment.outerHeight(), targetCell.outerHeight() * 6, 'Recurrence appointment part has right size'); + + scheduler.instance.option('currentDate', new Date(2019, 3, 1)); // NOTE: DST Montreal + + targetCell = scheduler.workSpace.getCell(6); + appointment = scheduler.appointments.getAppointment(0); + + assert.equal(appointment.position().top, targetCell.position().top, 'Recurrence appointment part is rendered in right cell'); + assert.equal(appointment.outerHeight(), targetCell.outerHeight() * 6, 'Recurrence appointment part has right size'); }); - const $appointment = $(this.instance.$element()).find('.' + APPOINTMENT_CLASS).first(); - const cellWidth = this.instance.$element().find('.' + DATE_TABLE_CELL_CLASS).first().outerWidth(); + QUnit.test('Recurrence appt part should be rendered correctly if recurrence starts in STD and ends in DST, appointment timezone is set', function(assert) { + // NOTE: The daylight saving changed in Paris on 31.03.2019 + const scheduler = createWrapper({ + dataSource: [ + { + text: 'Daily meeting', + startDate: '2019-03-01T09:00:00+01:00', + endDate: '2019-03-01T12:00:00+01:00', + recurrenceRule: 'FREQ=DAILY', + startDateTimeZone: 'Europe/Paris', + endDateTimeZone: 'Europe/Paris' + } + ], + views: ['day'], + currentView: 'day', + currentDate: new Date(2019, 2, 30), // NOTE: STD Paris + startDayHour: 0, + height: 600, + dateSerializationFormat: 'yyyy-MM-ddTHH:mm:ssx' + }); - assert.roughEqual($appointment.outerWidth(), cellWidth, 1.1, 'Appointment width is correct after translation oт STD'); + const appointmentPosition = scheduler.appointments.getAppointment(0).position().top; + + scheduler.instance.option('currentDate', new Date(2019, 3, 1)); // NOTE: DST Paris + + const appointment = scheduler.appointments.getAppointment(0); + assert.equal(appointment.position().top, appointmentPosition, 'Recurrence appointment part positions are the same and independent of time changing'); + }); }); diff --git a/testing/tests/DevExpress.ui.widgets.scheduler/integration.workSpace.tests.js b/testing/tests/DevExpress.ui.widgets.scheduler/integration.workSpace.tests.js index 77f569a0fc69..d87b2744ba20 100644 --- a/testing/tests/DevExpress.ui.widgets.scheduler/integration.workSpace.tests.js +++ b/testing/tests/DevExpress.ui.widgets.scheduler/integration.workSpace.tests.js @@ -1929,7 +1929,7 @@ QUnit.test('Recurrent appointment with tail on next week has most top coordinate const coords = translator.locate(appointment); - assert.ok(coords.top === 0, 'Appointment tail has most top coordinate'); + assert.strictEqual(coords.top, 0, 'Appointment tail has most top coordinate'); }); QUnit.test('Workspace view has correct viewEndDate with empty groups and groupByDate = true (T815379)', function(assert) { diff --git a/testing/tests/DevExpress.ui.widgets.scheduler/subscribes.tests.js b/testing/tests/DevExpress.ui.widgets.scheduler/subscribes.tests.js index 37d5371b0aeb..291e437b329a 100644 --- a/testing/tests/DevExpress.ui.widgets.scheduler/subscribes.tests.js +++ b/testing/tests/DevExpress.ui.widgets.scheduler/subscribes.tests.js @@ -387,17 +387,6 @@ QUnit.test('\'showAddAppointmentPopup\' should update appointment data if there }, 'Appointment data is OK'); }); -QUnit.test('\'appointmentFocused\' should fire restoreScrollTop', function(assert) { - this.createInstance(); - - const workspace = this.instance.$element().find('.dx-scheduler-work-space').dxSchedulerWorkSpaceDay('instance'); - const restoreScrollTopStub = sinon.stub(workspace, 'restoreScrollTop'); - - this.instance.fire('appointmentFocused'); - - assert.ok(restoreScrollTopStub.calledOnce, 'There is some result'); -}); - QUnit.test('check the \'getField\' method with date field', function(assert) { const defaultForceIsoDateParsing = config().forceIsoDateParsing; config().forceIsoDateParsing = true; diff --git a/testing/tests/DevExpress.ui.widgets.scheduler/timeline.tests.js b/testing/tests/DevExpress.ui.widgets.scheduler/timeline.tests.js index 6236efe0dafd..5cc285c89bed 100644 --- a/testing/tests/DevExpress.ui.widgets.scheduler/timeline.tests.js +++ b/testing/tests/DevExpress.ui.widgets.scheduler/timeline.tests.js @@ -788,6 +788,18 @@ QUnit.test('\'getCoordinatesByDate\' should return right coordinates with view o assert.equal(coords.left, targetCellPosition.left, 'Cell coordinates are right'); }); +QUnit.test('\'getCoordinatesByDateInGroup\' method should return only work week days (t853629)', function(assert) { + this.instance.option({ + intervalCount: 2, + currentDate: new Date(2018, 4, 21), + }); + + assert.ok(!this.instance.getCoordinatesByDateInGroup(new Date(2018, 4, 26))[0]); + assert.ok(!this.instance.getCoordinatesByDateInGroup(new Date(2018, 4, 27))[0]); + assert.ok(this.instance.getCoordinatesByDateInGroup(new Date(2018, 4, 23))[0]); + assert.ok(this.instance.getCoordinatesByDateInGroup(new Date(2018, 4, 28))[0]); +}); + QUnit.module('TimelineWeek with grouping by date', { beforeEach: function() { this.instance = $('#scheduler-timeline').dxSchedulerTimelineWeek({ diff --git a/testing/tests/DevExpress.ui.widgets.scheduler/workSpace.tests.js b/testing/tests/DevExpress.ui.widgets.scheduler/workSpace.tests.js index 3d03a79db3b1..be5383d24eff 100644 --- a/testing/tests/DevExpress.ui.widgets.scheduler/workSpace.tests.js +++ b/testing/tests/DevExpress.ui.widgets.scheduler/workSpace.tests.js @@ -12,7 +12,6 @@ import dateUtils from 'core/utils/date'; import dateLocalization from 'localization/date'; import dragEvents from 'events/drag'; import memoryLeaksHelper from '../../helpers/memoryLeaksHelper.js'; -import devices from 'core/devices'; import 'common.css!'; import 'generic_light.css!'; @@ -162,16 +161,6 @@ QUnit.testStart(function() { assert.equal(stub.callCount, 0, 'Tables were not updated'); }); - if(devices.real().deviceType === 'desktop') { - QUnit.test('Workspace should restore scrollTop after restoreScrollTop call', function(assert) { - this.instance.$element().scrollTop(30); - assert.equal(this.instance.$element().scrollTop(), 30, 'scrollTop is right'); - - this.instance.restoreScrollTop(); - assert.equal(this.instance.$element().scrollTop(), 0, 'scrollTop is restored'); - }); - } - QUnit.test('dateUtils.getTimezonesDifference should be called when calculating interval between dates', function(assert) { const stub = sinon.stub(dateUtils, 'getTimezonesDifference'); const minDate = new Date('Thu Mar 10 2016 00:00:00 GMT-0500'); @@ -1618,7 +1607,7 @@ QUnit.testStart(function() { $($element).trigger('focusin'); keyboard.keyDown('enter'); const cellData = updateSpy.getCall(0).args[0].cellData; - assert.notOk(cellData === {}, 'cellData is not empty'); + assert.notOk($.isEmptyObject(cellData), 'cellData is not empty'); assert.deepEqual(cellData.startDate, new Date(2015, 2, 30), 'cellData startDate is passing right'); assert.deepEqual(cellData.endDate, new Date(2015, 2, 31), 'cellData endDate is passing right'); }); @@ -3180,6 +3169,17 @@ QUnit.testStart(function() { assert.deepEqual(lastCellData.endDate, new Date(2017, 6, 10, 1), 'cell has right endtDate'); }); + QUnit.test('\'getCoordinatesByDateInGroup\' method should return only work week days (t853629)', function(assert) { + this.createInstance({ + intervalCount: 2, + currentDate: new Date(2018, 4, 21), + }); + + assert.ok(!this.instance.getCoordinatesByDateInGroup(new Date(2018, 4, 26))[0]); + assert.ok(!this.instance.getCoordinatesByDateInGroup(new Date(2018, 4, 27))[0]); + assert.ok(this.instance.getCoordinatesByDateInGroup(new Date(2018, 4, 23))[0]); + assert.ok(this.instance.getCoordinatesByDateInGroup(new Date(2018, 4, 28))[0]); + }); })('Work Space Work Week with intervalCount'); (function() { diff --git a/testing/tests/DevExpress.ui.widgets.treeList/adaptiveColumns.tests.js b/testing/tests/DevExpress.ui.widgets.treeList/adaptiveColumns.tests.js new file mode 100644 index 000000000000..647dd9458354 --- /dev/null +++ b/testing/tests/DevExpress.ui.widgets.treeList/adaptiveColumns.tests.js @@ -0,0 +1,81 @@ +QUnit.testStart(function() { + const markup = + '
\ +
\ +
'; + $('#qunit-fixture').html(markup); +}); + +import 'common.css!'; +import 'generic_light.css!'; +import 'ui/tree_list/ui.tree_list'; + +import $ from 'jquery'; +import treeListMocks from '../../helpers/treeListMocks.js'; +import renderer from 'core/renderer'; + +function setupTreeList(that, $treeListContainer) { + that.$element = function() { + return $treeListContainer ? $treeListContainer : renderer('.dx-treelist'); + }; + + if(that.columns !== null) { + that.columns = that.columns || [ + { dataField: 'firstName', index: 0, allowEditing: true, allowExporting: true }, + { dataField: 'lastName', index: 1, allowEditing: true, allowExporting: true } + ]; + } + + that.items = that.items || [ + { id: 1, parentId: 0, firstName: 'TestTestTestTestTestTestTestTest1', lastName: 'Psy' }, + { id: 2, parentId: 1, firstName: 'Super', lastName: 'Star' } + ]; + + that.options = $.extend({}, { + keyExpr: 'id', + parentIdExpr: 'parentId', + rootValue: 0, + columns: that.columns, + dataSource: { + asyncLoadEnabled: false, + store: that.items + }, + expandedRowKeys: [], + columnHidingEnabled: true + }, that.options); + + that.setupOptions = { + initViews: true + }; + + treeListMocks.setupTreeListModules(that, ['data', 'columns', 'rows', 'columnHeaders', 'masterDetail', 'editing', 'adaptivity', 'columnsResizingReordering', 'keyboardNavigation', 'gridView'], that.setupOptions); +} + +QUnit.module('API', { + beforeEach: function() { + this.clock = sinon.useFakeTimers(); + }, + afterEach: function() { + this.clock.restore(); + } +}); + +QUnit.test('The detail adaptive row should have the node property', function(assert) { + // arrange + $('.dx-treelist').width(200); + + setupTreeList(this); + this.rowsView.render($('#container')); + this.resizingController.updateDimensions(); + this.clock.tick(); + + // act + this.adaptiveColumnsController.expandAdaptiveDetailRow(1); + this.clock.tick(); + + // assert + const rows = this.getVisibleRows(); + assert.ok($('.dx-adaptive-detail-row').length, 'render field items'); + assert.strictEqual(rows[1].rowType, 'detailAdaptive', 'detail adaptive row'); + assert.deepEqual(rows[1].node, rows[0].node, 'detail adaptive row has the node property'); +}); diff --git a/testing/tests/DevExpress.ui.widgets.treeList/selection.tests.js b/testing/tests/DevExpress.ui.widgets.treeList/selection.tests.js index 6fa5492638f3..f57fac027fb2 100644 --- a/testing/tests/DevExpress.ui.widgets.treeList/selection.tests.js +++ b/testing/tests/DevExpress.ui.widgets.treeList/selection.tests.js @@ -40,7 +40,7 @@ const setupModule = function() { }; that.setupTreeList = function() { - setupTreeListModules(that, ['data', 'columns', 'rows', 'selection', 'editorFactory', 'columnHeaders', 'filterRow', 'sorting', 'search'], { + setupTreeListModules(that, ['data', 'columns', 'rows', 'selection', 'editorFactory', 'columnHeaders', 'filterRow', 'sorting', 'search', 'focus'], { initViews: true }); }; @@ -497,6 +497,38 @@ QUnit.test('selection for nested node should works', function(assert) { assert.strictEqual(this.getVisibleRows()[1].isSelected, true, 'row 1 is selected'); }); +// T858312 +QUnit.test('The getSelectedRowsData method should work correctly when calling navigateToRow in the onNodesInitialized event', function(assert) { + // arrange + const $testElement = $('#treeList'); + const clock = sinon.useFakeTimers(); + + this.options.loadingTimeout = 30; + this.options.autoNavigateToFocusedRow = true; + this.options.onNodesInitialized = (e) => { + this.navigateToRow(2); + }; + + this.setupTreeList(); + clock.tick(60); + this.rowsView.render($testElement); + + // assert + assert.ok(this.getNodeByKey(1), 'node with key "1" exists'); + assert.ok(this.getNodeByKey(2), 'node with key "2" exists'); + + // act + this.selectRows(2); + + // assert + assert.deepEqual(this.getSelectedRowKeys(), [2], 'getSelectedRowKeys'); + assert.deepEqual(this.option('selectedRowKeys'), [2], 'selectedRowKeys'); + assert.deepEqual(this.getSelectedRowsData(), [{ id: 2, parentId: 1, field1: 'test2', field2: 2, field3: new Date(2002, 1, 2) }], 'getSelectedRowsData'); + + clock.restore(); +}); + + QUnit.module('Recursive selection', { beforeEach: function() { setupModule.call(this); diff --git a/testing/tests/DevExpress.ui.widgets.treeList/treeList.tests.js b/testing/tests/DevExpress.ui.widgets.treeList/treeList.tests.js index d636d014f085..b11f18b2e939 100644 --- a/testing/tests/DevExpress.ui.widgets.treeList/treeList.tests.js +++ b/testing/tests/DevExpress.ui.widgets.treeList/treeList.tests.js @@ -17,12 +17,12 @@ import $ from 'jquery'; import { noop } from 'core/utils/common'; import devices from 'core/devices'; import fx from 'animation/fx'; -import pointerEvents from 'events/pointer'; import { DataSource } from 'data/data_source/data_source'; import { TreeListWrapper } from '../../helpers/wrappers/dataGridWrappers.js'; import ArrayStore from 'data/array_store'; import TreeList from 'ui/tree_list/ui.tree_list'; import pointerMock from '../../helpers/pointerMock.js'; +import { CLICK_EVENT } from '../../helpers/grid/keyboardNavigationHelper.js'; fx.off = true; @@ -490,6 +490,50 @@ QUnit.test('Click on selectCheckBox shouldn\'t render editor, editing & selectio assert.notOk($('#treeList').find('.dx-texteditor').length, 'Editing textEditor wasn\'t rendered'); }); +// T857405 +QUnit.test('Assign new values using the promise parameter in the onInitNewRow', function(assert) { + // arrange + let visibleRows; + + const rowData = { room: 42 }; + + const treeList = createTreeList({ + editing: { + allowAdding: true, + mode: 'row' + }, + dataSource: [], + columns: ['room'], + onInitNewRow: function(e) { + e.promise = $.Deferred(); + setTimeout(() => { + e.data = rowData; + e.promise.resolve(); + }, 500); + } + }); + + // act + treeList.addRow(); + + visibleRows = treeList.getVisibleRows(); + + // assert + assert.equal(visibleRows.length, 0); + + // act + this.clock.tick(500); + + treeList.saveEditData(); + this.clock.tick(); + + visibleRows = treeList.getVisibleRows(); + + // assert + assert.equal(visibleRows.length, 1, 'row was added'); + assert.deepEqual(visibleRows[0].data, rowData, 'row data'); +}); + // T742147 QUnit.test('Selection checkbox should be rendered if first column is lookup', function(assert) { const treeList = createTreeList({ @@ -1336,7 +1380,7 @@ QUnit.test('TreeList should focus only one focused row (T827201)', function(asse this.clock.tick(); // act - $(treeList.getCellElement(4, 1)).trigger(pointerEvents.up); + $(treeList.getCellElement(4, 1)).trigger(CLICK_EVENT); this.clock.tick(); // assert @@ -1359,10 +1403,31 @@ QUnit.test('TreeList navigateTo', function(assert) { this.clock.tick(); // assert + assert.deepEqual(treeList.option('expandedRowKeys'), [11], 'parent node is expanded'); assert.equal(treeList.pageIndex(), 1, 'page is changed'); assert.ok(treeList.getRowIndexByKey(12) >= 0, 'key is visible'); }); +QUnit.test('TreeList navigateTo to the same page with expand', function(assert) { + // arrange, act + const treeList = createTreeList({ + dataSource: generateData(10), + paging: { + pageSize: 4 + } + }); + + this.clock.tick(); + + treeList.navigateToRow(2); + this.clock.tick(); + + // assert + assert.deepEqual(treeList.option('expandedRowKeys'), [1], 'parent node is expanded'); + assert.equal(treeList.pageIndex(), 0, 'page is not changed'); + assert.ok(treeList.getRowIndexByKey(2) >= 0, 'key is visible'); +}); + // T697860 QUnit.test('dataSource change with columns should force one loading only', function(assert) { const loadingSpy = sinon.spy(); diff --git a/testing/tests/DevExpress.ui.widgets/diagram.tests.js b/testing/tests/DevExpress.ui.widgets/diagram.tests.js index 7376931593cd..0ce72a10813e 100644 --- a/testing/tests/DevExpress.ui.widgets/diagram.tests.js +++ b/testing/tests/DevExpress.ui.widgets/diagram.tests.js @@ -1,632 +1,22 @@ import $ from 'jquery'; -const { test } = QUnit; import 'common.css!'; import 'ui/diagram'; -import { DiagramCommand, DataLayoutType } from 'devexpress-diagram'; + +import './diagramParts/dom.tests.js'; +import './diagramParts/mainToolbar.tests.js'; +import './diagramParts/historyToolbar.tests.js'; +import './diagramParts/viewToolbar.tests.js'; +import './diagramParts/contextMenu.tests.js'; +import './diagramParts/propertiesPanel.tests.js'; +import './diagramParts/toolbox.tests.js'; +import './diagramParts/options.tests.js'; +import './diagramParts/commandManager.tests.js'; +import './diagramParts/clientSideEvents.tests.js'; + +export const SIMPLE_DIAGRAM = '{ "shapes": [{ "key":"107", "type":"Ellipsis", "text":"A new ticket", "x":1440, "y":1080, "width":1440, "height":720, "zIndex":0 }] }'; QUnit.testStart(() => { const markup = '
'; $('#qunit-fixture').html(markup); }); -const TOOLBAR_SELECTOR = '.dx-diagram-toolbar'; -const TOOBOX_ACCORDION_SELECTOR = '.dx-diagram-left-panel .dx-accordion'; -const CONTEXT_MENU_SELECTOR = 'div:not(.dx-diagram-toolbar-wrapper) > .dx-has-context-menu'; -const PROPERTIES_PANEL_ACCORDION_SELECTOR = '.dx-diagram-right-panel .dx-accordion'; -const PROPERTIES_PANEL_FORM_SELECTOR = '.dx-diagram-right-panel .dx-accordion .dx-form'; -const TOOLBAR_ITEM_ACTIVE_CLASS = 'dx-format-active'; -const SIMPLE_DIAGRAM = '{ "shapes": [{ "key":"107", "type":"Ellipsis", "text":"A new ticket", "x":1440, "y":1080, "width":1440, "height":720, "zIndex":0 }] }'; -const DX_MENU_ITEM_SELECTOR = '.dx-menu-item'; -const DIAGRAM_FULLSCREEN_CLASS = 'dx-diagram-fullscreen'; - -const moduleConfig = { - beforeEach: function() { - this.$element = $('#diagram').dxDiagram(); - this.instance = this.$element.dxDiagram('instance'); - } -}; - -function getToolbarIcon(button) { - return button.find('.dx-dropdowneditor-field-template-wrapper').find('.dx-diagram-i, .dx-icon'); -} - - -QUnit.module('Diagram DOM Layout', { - beforeEach: function() { - this.clock = sinon.useFakeTimers(); - moduleConfig.beforeEach.apply(this, arguments); - }, - afterEach: function() { - this.clock.restore(); - this.clock.reset(); - } -}, () => { - test('should return correct size of document container in default options', function(assert) { - assertSizes(assert, - this.$element.find('.dxdi-control'), - this.$element.find('.dx-diagram-drawer-wrapper'), - this.instance); - }); - test('should return correct size of document container if options panel is hidden', function(assert) { - this.instance.option('propertiesPanel.enabled', false); - this.clock.tick(10000); - assertSizes(assert, - this.$element.find('.dxdi-control'), - this.$element.find('.dx-diagram-drawer-wrapper'), - this.instance); - }); - - test('should return correct size of document container if toolbox is hidden', function(assert) { - this.instance.option('toolbox.visible', false); - this.clock.tick(10000); - assertSizes(assert, - this.$element.find('.dxdi-control'), - this.$element.find('.dx-diagram-drawer-wrapper'), - this.instance); - }); - - test('should return correct size of document container if toolbar is hidden', function(assert) { - this.instance.option('toolbar.visible', false); - this.clock.tick(10000); - assertSizes(assert, - this.$element.find('.dxdi-control'), - this.$element.find('.dx-diagram-drawer-wrapper'), - this.instance); - }); - - test('should return correct size of document container if all UI is hidden', function(assert) { - this.instance.option('toolbar.visible', false); - this.instance.option('toolbox.visible', false); - this.instance.option('propertiesPanel.enabled', false); - this.clock.tick(10000); - assertSizes(assert, - this.$element.find('.dxdi-control'), - this.$element.find('.dx-diagram-drawer-wrapper'), - this.instance); - }); - - - function assertSizes(assert, $scrollContainer, $actualContainer, inst) { - assert.equal($scrollContainer.width(), $actualContainer.width()); - assert.equal($scrollContainer.height(), $actualContainer.height()); - const coreScrollSize = inst._diagramInstance.render.view.scrollView.getSize(); - assert.equal(coreScrollSize.width, $actualContainer.width()); - assert.equal(coreScrollSize.height, $actualContainer.height()); - } -}); - -QUnit.module('Diagram Toolbar', { - beforeEach: function() { - this.clock = sinon.useFakeTimers(); - moduleConfig.beforeEach.apply(this, arguments); - }, - afterEach: function() { - this.clock.restore(); - this.clock.reset(); - } -}, () => { - test('should not render if toolbar.visible is false', function(assert) { - this.instance.option('toolbar.visible', false); - const $toolbar = this.$element.find(TOOLBAR_SELECTOR); - assert.equal($toolbar.length, 0); - }); - test('should fill toolbar with default items', function(assert) { - const toolbar = this.$element.find(TOOLBAR_SELECTOR).dxToolbar('instance'); - assert.ok(toolbar.option('dataSource').length > 10); - }); - test('should fill toolbar with custom items', function(assert) { - this.instance.option('toolbar.commands', ['export']); - let toolbar = this.$element.find(TOOLBAR_SELECTOR).dxToolbar('instance'); - assert.equal(toolbar.option('dataSource').length, 2); // + show properties panel - - this.instance.option('propertiesPanel.enabled', false); - toolbar = this.$element.find(TOOLBAR_SELECTOR).dxToolbar('instance'); - assert.equal(toolbar.option('dataSource').length, 1); - this.instance.option('propertiesPanel.enabled', true); - this.instance.option('propertiesPanel.collapsible', false); - toolbar = this.$element.find(TOOLBAR_SELECTOR).dxToolbar('instance'); - assert.equal(toolbar.option('dataSource').length, 1); - }); - test('should enable items on diagram request', function(assert) { - const undoButton = findToolbarItem(this.$element, 'undo').dxButton('instance'); - assert.ok(undoButton.option('disabled')); - this.instance._diagramInstance.commandManager.getCommand(DiagramCommand.PageLandscape).execute(true); - assert.notOk(undoButton.option('disabled')); - }); - test('should activate items on diagram request', function(assert) { - assert.ok(findToolbarItem(this.$element, 'center').hasClass(TOOLBAR_ITEM_ACTIVE_CLASS)); - assert.notOk(findToolbarItem(this.$element, 'left').hasClass(TOOLBAR_ITEM_ACTIVE_CLASS)); - this.instance._diagramInstance.commandManager.getCommand(DiagramCommand.TextLeftAlign).execute(true); - assert.notOk(findToolbarItem(this.$element, 'center').hasClass(TOOLBAR_ITEM_ACTIVE_CLASS)); - assert.ok(findToolbarItem(this.$element, 'left').hasClass(TOOLBAR_ITEM_ACTIVE_CLASS)); - }); - test('button should raise diagram commands', function(assert) { - assert.notOk(this.instance._diagramInstance.commandManager.getCommand(DiagramCommand.TextLeftAlign).getState().value); - findToolbarItem(this.$element, 'left').trigger('dxclick'); - assert.ok(this.instance._diagramInstance.commandManager.getCommand(DiagramCommand.TextLeftAlign).getState().value); - }); - test('selectBox should raise diagram commands', function(assert) { - assert.equal(this.instance._diagramInstance.commandManager.getCommand(DiagramCommand.FontName).getState().value, 'Arial'); - const fontSelectBox = this.$element.find(TOOLBAR_SELECTOR).find('.dx-selectbox').eq(0).dxSelectBox('instance'); - fontSelectBox.option('value', 'Arial Black'); - assert.equal(this.instance._diagramInstance.commandManager.getCommand(DiagramCommand.FontName).getState().value, 'Arial Black'); - }); - test('selectboxes with icon items should be replaced with select buttons', function(assert) { - const $selectButtonTemplates = this.$element.find(TOOLBAR_SELECTOR).find('.dx-diagram-select-b').find('.dx-dropdowneditor-field-template-wrapper'); - assert.ok($selectButtonTemplates.length > 0, 'select buttons are rendered'); - const selectButtonsCount = $selectButtonTemplates.length; - assert.equal($selectButtonTemplates.find('.dx-diagram-i').length, selectButtonsCount, 'icons are rendered'); - assert.equal($selectButtonTemplates.find('.dx-textbox')[0].offsetWidth, 0, 'textbox is hidden'); - }); - test('colorboxes should be replaced with color buttons', function(assert) { - const $selectButtonTemplates = this.$element.find(TOOLBAR_SELECTOR).find('.dx-diagram-color-b').find('.dx-dropdowneditor-field-template-wrapper'); - assert.ok($selectButtonTemplates.length > 0, 'color buttons are rendered'); - const selectButtonsCount = $selectButtonTemplates.length; - assert.equal($selectButtonTemplates.find('.dx-diagram-i, .dx-icon').length, selectButtonsCount, 'icons are rendered'); - assert.equal($selectButtonTemplates.find('.dx-textbox')[0].offsetWidth, 0, 'textbox is hidden'); - }); - test('colorbuttons should show an active color', function(assert) { - const colorButton = this.$element.find(TOOLBAR_SELECTOR).find('.dx-diagram-color-b').first(); - assert.equal(getToolbarIcon(colorButton).css('borderBottomColor'), 'rgb(0, 0, 0)'); - this.instance._diagramInstance.commandManager.getCommand(DiagramCommand.FontColor).execute('rgb(255, 0, 0)'); - assert.equal(getToolbarIcon(colorButton).css('borderBottomColor'), 'rgb(255, 0, 0)', 'button changed via command'); - colorButton.find('.dx-dropdowneditor-button').trigger('dxclick'); - const $overlayContent = $('.dx-colorbox-overlay'); - $overlayContent.find('.dx-colorview-label-hex').find('.dx-textbox').dxTextBox('instance').option('value', '00ff00'); - $overlayContent.find('.dx-colorview-buttons-container .dx-colorview-apply-button').trigger('dxclick'); - assert.equal(this.instance._diagramInstance.commandManager.getCommand(DiagramCommand.FontColor).getState().value, '#00ff00', 'color changed by color button'); - assert.equal(getToolbarIcon(colorButton).css('borderBottomColor'), 'rgb(0, 255, 0)', 'button changed via coloredit'); - }); - test('colorbutton should show dropdown on icon click', function(assert) { - const colorButton = this.$element.find(TOOLBAR_SELECTOR).find('.dx-diagram-color-b').first(); - const colorBox = colorButton.find('.dx-colorbox').dxColorBox('instance'); - getToolbarIcon(colorButton).trigger('dxclick'); - assert.ok(colorBox.option('opened'), true); - }); - test('call .update() after accordion item collapsing/expanding', function(assert) { - const clock = sinon.useFakeTimers(); - const $leftPanel = this.$element.find('.dx-diagram-left-panel'); - const scrollView = $leftPanel.find('.dx-scrollview').dxScrollView('instance'); - const updateSpy = sinon.spy(scrollView, 'update'); - $leftPanel.find('.dx-accordion-item-title').first().trigger('dxclick'); - clock.tick(2000); - assert.equal(updateSpy.callCount, 1, 'scrollView.update() called once'); - clock.restore(); - }); - test('should toggle fullscreen class name on button click', function(assert) { - assert.notOk(this.$element.hasClass(DIAGRAM_FULLSCREEN_CLASS)); - const fullScreenButton = findToolbarItem(this.$element, 'full screen'); - fullScreenButton.trigger('dxclick'); - assert.ok(this.$element.hasClass(DIAGRAM_FULLSCREEN_CLASS)); - fullScreenButton.trigger('dxclick'); - assert.notOk(this.$element.hasClass(DIAGRAM_FULLSCREEN_CLASS)); - }); - test('diagram should be focused after change font family', function(assert) { - const fontSelectBox = this.$element.find(TOOLBAR_SELECTOR).find('.dx-selectbox').eq(0).dxSelectBox('instance'); - fontSelectBox.focus(); - fontSelectBox.open(); - const item = $(document).find('.dx-list-item-content').filter(function() { - return $(this).text().toLowerCase().indexOf('arial black') >= 0; - }); - assert.notEqual(document.activeElement, this.instance._diagramInstance.render.input.inputElement); - item.trigger('dxclick'); - assert.equal(document.activeElement, this.instance._diagramInstance.render.input.inputElement); - }); - test('diagram should be focused after set font bold', function(assert) { - const boldButton = findToolbarItem(this.$element, 'bold'); - assert.notEqual(document.activeElement, this.instance._diagramInstance.render.input.inputElement); - boldButton.trigger('dxclick'); - assert.equal(document.activeElement, this.instance._diagramInstance.render.input.inputElement); - }); - test('Auto Layout button should be disabled when there is no selection', function(assert) { - const button = findToolbarItem(this.$element, 'auto layout').dxButton('instance'); - assert.ok(button.option('disabled')); - }); - test('Auto Layout button should be disabled in Read Only mode', function(assert) { - this.instance.option('contextMenu.commands', ['selectAll']); - this.instance._diagramInstance.commandManager.getCommand(DiagramCommand.Import).execute(SIMPLE_DIAGRAM); - const contextMenu = this.$element.find(CONTEXT_MENU_SELECTOR).dxContextMenu('instance'); - contextMenu.show(); - $(contextMenu.itemsContainer().find(DX_MENU_ITEM_SELECTOR).eq(0)).trigger('dxclick'); // Select All - const button = findToolbarItem(this.$element, 'auto layout').dxButton('instance'); - assert.notOk(button.option('disabled')); - this.instance.option('readOnly', true); - assert.ok(button.option('disabled')); - }); -}); - -QUnit.module('Diagram Toolbox', moduleConfig, () => { - test('should not render if toolbox.visible is false', function(assert) { - this.instance.option('toolbox.visible', false); - const $accordion = this.$element.find(TOOBOX_ACCORDION_SELECTOR); - assert.equal($accordion.length, 0); - }); - test('should fill toolbox with default items', function(assert) { - const accordion = this.$element.find(TOOBOX_ACCORDION_SELECTOR).dxAccordion('instance'); - assert.ok(accordion.option('dataSource').length > 1); - }); - test('should fill toolbox with custom items', function(assert) { - this.instance.option('toolbox.groups', ['general']); - const accordion = this.$element.find(TOOBOX_ACCORDION_SELECTOR).dxAccordion('instance'); - assert.equal(accordion.option('dataSource').length, 1); - }); -}); - -QUnit.module('Diagram Properties Panel', moduleConfig, () => { - test('should not render if propertiesPanel.enabled is false', function(assert) { - this.instance.option('propertiesPanel.enabled', false); - const $accordion = this.$element.find(PROPERTIES_PANEL_ACCORDION_SELECTOR); - assert.equal($accordion.length, 0); - }); - test('should fill properties panel with default items', function(assert) { - const form = this.$element.find(PROPERTIES_PANEL_FORM_SELECTOR).dxForm('instance'); - assert.ok(form.option('items').length > 1); - }); - test('should fill toolbox with custom items', function(assert) { - this.instance.option('propertiesPanel.groups', [{ commands: ['units'] }]); - const form = this.$element.find(PROPERTIES_PANEL_FORM_SELECTOR).dxForm('instance'); - assert.equal(form.option('items').length, 1); - }); -}); - -QUnit.module('Context Menu', { - beforeEach: function() { - this.clock = sinon.useFakeTimers(); - moduleConfig.beforeEach.apply(this, arguments); - }, - afterEach: function() { - this.clock.restore(); - this.clock.reset(); - } -}, () => { - test('should not render if contextMenu.enabled is false', function(assert) { - let $contextMenu = this.$element.find(CONTEXT_MENU_SELECTOR); - assert.equal($contextMenu.length, 1); - this.instance.option('contextMenu.enabled', false); - $contextMenu = this.$element.children(CONTEXT_MENU_SELECTOR); - assert.equal($contextMenu.length, 0); - }); - test('should load default items', function(assert) { - const contextMenu = this.$element.find(CONTEXT_MENU_SELECTOR).dxContextMenu('instance'); - assert.ok(contextMenu.option('items').length > 1); - }); - test('should load custom items', function(assert) { - this.instance.option('contextMenu.commands', ['copy']); - const contextMenu = this.$element.find(CONTEXT_MENU_SELECTOR).dxContextMenu('instance'); - assert.equal(contextMenu.option('items').length, 1); - }); - test('should update items on showing', function(assert) { - this.instance.option('contextMenu.commands', ['copy', 'selectAll']); - const contextMenu = this.$element.find(CONTEXT_MENU_SELECTOR).dxContextMenu('instance'); - assert.notOk(contextMenu.option('visible')); - assert.ok(contextMenu.option('items')[0].text.indexOf('Copy') > -1); - contextMenu.show(); - assert.ok(contextMenu.option('visible')); - assert.ok(contextMenu.option('items')[0].text.indexOf('Select All') > -1); - }); - test('should execute commands on click', function(assert) { - this.instance.option('contextMenu.commands', ['selectAll']); - this.instance._diagramInstance.commandManager.getCommand(DiagramCommand.Import).execute(SIMPLE_DIAGRAM); - const contextMenu = this.$element.find(CONTEXT_MENU_SELECTOR).dxContextMenu('instance'); - contextMenu.show(); - assert.ok(this.instance._diagramInstance.selection.isEmpty()); - $(contextMenu.itemsContainer().find(DX_MENU_ITEM_SELECTOR).eq(0)).trigger('dxclick'); - assert.notOk(this.instance._diagramInstance.selection.isEmpty()); - }); -}); - -QUnit.module('Options', moduleConfig, () => { - test('should change readOnly property', function(assert) { - assert.notOk(this.instance._diagramInstance.settings.readOnly); - this.instance.option('readOnly', true); - assert.ok(this.instance._diagramInstance.settings.readOnly); - this.instance.option('readOnly', false); - assert.notOk(this.instance._diagramInstance.settings.readOnly); - }); - test('should change zoomLevel property', function(assert) { - assert.equal(this.instance._diagramInstance.settings.zoomLevel, 1); - this.instance.option('zoomLevel', 1.5); - assert.equal(this.instance._diagramInstance.settings.zoomLevel, 1.5); - this.instance.option('zoomLevel', 1); - assert.equal(this.instance._diagramInstance.settings.zoomLevel, 1); - }); - test('should sync zoomLevel property', function(assert) { - assert.equal(this.instance.option('zoomLevel'), 1); - this.instance._diagramInstance.commandManager.getCommand(DiagramCommand.ZoomLevel).execute(1.5); - assert.equal(this.instance.option('zoomLevel'), 1.5); - }); - test('should change zoomLevel object property', function(assert) { - assert.equal(this.instance._diagramInstance.settings.zoomLevel, 1); - assert.equal(this.instance._diagramInstance.settings.zoomLevelItems.length, 7); - this.instance.option('zoomLevel', { value: 1.5, items: [ 1, 1.5 ] }); - assert.equal(this.instance._diagramInstance.settings.zoomLevel, 1.5); - assert.equal(this.instance._diagramInstance.settings.zoomLevelItems.length, 2); - this.instance.option('zoomLevel', 1); - assert.equal(this.instance._diagramInstance.settings.zoomLevel, 1); - assert.equal(this.instance._diagramInstance.settings.zoomLevelItems.length, 2); - }); - test('should sync zoomLevel object property', function(assert) { - this.instance.option('zoomLevel', { value: 1.5, items: [ 1, 1.5, 2 ] }); - assert.equal(this.instance.option('zoomLevel.value'), 1.5); - this.instance._diagramInstance.commandManager.getCommand(DiagramCommand.ZoomLevel).execute(2); - assert.equal(this.instance.option('zoomLevel.value'), 2); - }); - test('should change autoZoom property', function(assert) { - assert.equal(this.instance._diagramInstance.settings.autoZoom, 0); - this.instance.option('autoZoom', 'fitContent'); - assert.equal(this.instance._diagramInstance.settings.autoZoom, 1); - this.instance.option('autoZoom', 'fitWidth'); - assert.equal(this.instance._diagramInstance.settings.autoZoom, 2); - this.instance.option('autoZoom', 'disabled'); - assert.equal(this.instance._diagramInstance.settings.autoZoom, 0); - }); - test('should sync autoZoom property', function(assert) { - assert.equal(this.instance.option('autoZoom'), 'disabled'); - this.instance._diagramInstance.commandManager.getCommand(DiagramCommand.SwitchAutoZoom).execute(1); - assert.equal(this.instance.option('autoZoom'), 'fitContent'); - }); - test('should change fullScreen property', function(assert) { - assert.notOk(this.instance._diagramInstance.settings.fullscreen); - this.instance.option('fullScreen', true); - assert.ok(this.instance._diagramInstance.settings.fullscreen); - this.instance.option('fullScreen', false); - assert.notOk(this.instance._diagramInstance.settings.fullscreen); - }); - test('should sync fullScreen property', function(assert) { - assert.equal(this.instance.option('fullScreen'), false); - this.instance._diagramInstance.commandManager.getCommand(DiagramCommand.Fullscreen).execute(true); - assert.equal(this.instance.option('fullScreen'), true); - }); - test('should change showGrid property', function(assert) { - assert.ok(this.instance._diagramInstance.settings.showGrid); - this.instance.option('showGrid', false); - assert.notOk(this.instance._diagramInstance.settings.showGrid); - this.instance.option('showGrid', true); - assert.ok(this.instance._diagramInstance.settings.showGrid); - }); - test('should sync showGrid property', function(assert) { - assert.equal(this.instance.option('showGrid'), true); - this.instance._diagramInstance.commandManager.getCommand(DiagramCommand.ShowGrid).execute(false); - assert.equal(this.instance.option('showGrid'), false); - }); - test('should change snapToGrid property', function(assert) { - assert.ok(this.instance._diagramInstance.settings.snapToGrid); - this.instance.option('snapToGrid', false); - assert.notOk(this.instance._diagramInstance.settings.snapToGrid); - this.instance.option('snapToGrid', true); - assert.ok(this.instance._diagramInstance.settings.snapToGrid); - }); - test('should sync snapToGrid property', function(assert) { - assert.equal(this.instance.option('snapToGrid'), true); - this.instance._diagramInstance.commandManager.getCommand(DiagramCommand.SnapToGrid).execute(false); - assert.equal(this.instance.option('snapToGrid'), false); - }); - test('should change gridSize property', function(assert) { - assert.equal(this.instance._diagramInstance.settings.gridSize, 180); - this.instance.option('gridSize', 0.25); - assert.equal(this.instance._diagramInstance.settings.gridSize, 360); - this.instance.option('gridSize', 0.125); - assert.equal(this.instance._diagramInstance.settings.gridSize, 180); - }); - test('should sync gridSize property', function(assert) { - assert.equal(this.instance.option('gridSize'), 0.125); - this.instance._diagramInstance.commandManager.getCommand(DiagramCommand.GridSize).execute(0.25); - assert.equal(this.instance.option('gridSize'), 0.25); - }); - test('should change gridSize object property', function(assert) { - assert.equal(this.instance._diagramInstance.settings.gridSize, 180); - assert.equal(this.instance._diagramInstance.settings.gridSizeItems.length, 4); - this.instance.option('gridSize', { value: 0.25, items: [0.25, 1] }); - assert.equal(this.instance._diagramInstance.settings.gridSize, 360); - assert.equal(this.instance._diagramInstance.settings.gridSizeItems.length, 2); - this.instance.option('gridSize', 0.125); - assert.equal(this.instance._diagramInstance.settings.gridSize, 180); - assert.equal(this.instance._diagramInstance.settings.gridSizeItems.length, 2); - }); - test('should sync gridSize object property', function(assert) { - this.instance.option('gridSize', { value: 0.25, items: [0.125, 0.25, 1] }); - assert.equal(this.instance.option('gridSize.value'), 0.25); - this.instance._diagramInstance.commandManager.getCommand(DiagramCommand.GridSize).execute(1); - assert.equal(this.instance.option('gridSize.value'), 1); - }); - test('should change viewUnits property', function(assert) { - assert.equal(this.instance._diagramInstance.settings.viewUnits, 0); - this.instance.option('viewUnits', 'cm'); - assert.equal(this.instance._diagramInstance.settings.viewUnits, 1); - this.instance.option('viewUnits', 'in'); - assert.equal(this.instance._diagramInstance.settings.viewUnits, 0); - }); - test('should sync viewUnits property', function(assert) { - assert.equal(this.instance.option('viewUnits'), 'in'); - this.instance._diagramInstance.commandManager.getCommand(DiagramCommand.ViewUnits).execute(1); - assert.equal(this.instance.option('viewUnits'), 'cm'); - }); - test('should change units property', function(assert) { - assert.equal(this.instance._diagramInstance.model.units, 0); - this.instance.option('units', 'cm'); - assert.equal(this.instance._diagramInstance.model.units, 1); - this.instance.option('units', 'in'); - assert.equal(this.instance._diagramInstance.model.units, 0); - }); - test('should change pageSize property', function(assert) { - assert.equal(this.instance._diagramInstance.model.pageSize.width, 8391); - assert.equal(this.instance._diagramInstance.model.pageSize.height, 11906); - this.instance.option('pageSize', { width: 3, height: 5 }); - assert.equal(this.instance._diagramInstance.model.pageSize.width, 4320); - assert.equal(this.instance._diagramInstance.model.pageSize.height, 7200); - }); - test('should sync pageSize property', function(assert) { - this.instance.option('pageSize', { width: 3, height: 5 }); - assert.equal(this.instance.option('pageSize.width'), 3); - assert.equal(this.instance.option('pageSize.height'), 5); - this.instance._diagramInstance.commandManager.getCommand(DiagramCommand.PageSize).execute({ width: 4, height: 6 }); - assert.equal(this.instance.option('pageSize.width'), 4); - assert.equal(this.instance.option('pageSize.height'), 6); - }); - test('should change pageSize object property', function(assert) { - assert.equal(this.instance._diagramInstance.model.pageSize.width, 8391); - assert.equal(this.instance._diagramInstance.model.pageSize.height, 11906); - assert.equal(this.instance._diagramInstance.settings.pageSizeItems.length, 11); - this.instance.option('pageSize', { width: 3, height: 5, items: [{ width: 3, height: 5, text: 'A10' }] }); - assert.equal(this.instance._diagramInstance.model.pageSize.width, 4320); - assert.equal(this.instance._diagramInstance.model.pageSize.height, 7200); - assert.equal(this.instance._diagramInstance.settings.pageSizeItems.length, 1); - }); - test('should sync pageSize object property', function(assert) { - this.instance.option('pageSize', { width: 3, height: 5, items: [{ width: 3, height: 5, text: 'A10' }, { width: 4, height: 6, text: 'A11' }] }); - assert.equal(this.instance.option('pageSize.width'), 3); - assert.equal(this.instance.option('pageSize.height'), 5); - this.instance._diagramInstance.commandManager.getCommand(DiagramCommand.PageSize).execute({ width: 4, height: 6 }); - assert.equal(this.instance.option('pageSize.width'), 4); - assert.equal(this.instance.option('pageSize.height'), 6); - }); - test('should change pageOrientation property', function(assert) { - assert.equal(this.instance._diagramInstance.model.pageLandscape, false); - this.instance.option('pageOrientation', 'landscape'); - assert.equal(this.instance._diagramInstance.model.pageLandscape, true); - this.instance.option('pageOrientation', 'portrait'); - assert.equal(this.instance._diagramInstance.model.pageLandscape, false); - }); - test('should sync pageOrientation property', function(assert) { - assert.equal(this.instance.option('pageOrientation'), 'portrait'); - this.instance._diagramInstance.commandManager.getCommand(DiagramCommand.PageLandscape).execute(1); - assert.equal(this.instance.option('pageOrientation'), 'landscape'); - }); - test('should change pageColor property', function(assert) { - assert.equal(this.instance._diagramInstance.model.pageColor, -1); // FFFFFF - this.instance.option('pageColor', 'red'); - assert.equal(this.instance._diagramInstance.model.pageColor, -65536); // FF0000 - this.instance.option('pageColor', 'white'); - assert.equal(this.instance._diagramInstance.model.pageColor, -1); // FFFFFF - }); - test('should sync pageColor property', function(assert) { - assert.equal(this.instance.option('pageColor'), '#ffffff'); - this.instance._diagramInstance.commandManager.getCommand(DiagramCommand.PageColor).execute('red'); - assert.equal(this.instance.option('pageColor'), '#ff0000'); // FF0000 - }); - test('should change simpleView property', function(assert) { - assert.equal(this.instance._diagramInstance.settings.simpleView, false); - this.instance.option('simpleView', true); - assert.equal(this.instance._diagramInstance.settings.simpleView, true); - this.instance.option('simpleView', false); - assert.equal(this.instance._diagramInstance.settings.simpleView, false); - }); - test('should sync simpleView property', function(assert) { - assert.equal(this.instance.option('simpleView'), false); - this.instance._diagramInstance.commandManager.getCommand(DiagramCommand.ToggleSimpleView).execute(true); - assert.equal(this.instance.option('simpleView'), true); - }); - test('should return correct autoLayout parameters based on the nodes.autoLayout option', function(assert) { - assert.equal(this.instance.option('nodes.autoLayout'), 'auto'); - assert.deepEqual(this.instance._getDataBindingLayoutParameters(), { type: DataLayoutType.Sugiyama }); - - this.instance.option('nodes.leftExpr', 'left'); - this.instance.option('nodes.topExpr', 'left'); - assert.equal(this.instance._getDataBindingLayoutParameters(), undefined); - this.instance.option('nodes.autoLayout', { type: 'auto' }); - assert.equal(this.instance._getDataBindingLayoutParameters(), undefined); - - this.instance.option('nodes.leftExpr', ''); - assert.deepEqual(this.instance._getDataBindingLayoutParameters(), { type: DataLayoutType.Sugiyama }); - this.instance.option('nodes.topExpr', ''); - assert.deepEqual(this.instance._getDataBindingLayoutParameters(), { type: DataLayoutType.Sugiyama }); - - this.instance.option('nodes.autoLayout', 'off'); - assert.equal(this.instance._getDataBindingLayoutParameters(), undefined); - this.instance.option('nodes.autoLayout', { type: 'off' }); - assert.equal(this.instance._getDataBindingLayoutParameters(), undefined); - - this.instance.option('nodes.autoLayout', 'tree'); - assert.deepEqual(this.instance._getDataBindingLayoutParameters(), { type: DataLayoutType.Tree }); - this.instance.option('nodes.autoLayout', { type: 'tree' }); - assert.deepEqual(this.instance._getDataBindingLayoutParameters(), { type: DataLayoutType.Tree }); - }); -}); - -QUnit.module('ClientSideEvents', { - beforeEach: function() { - this.clock = sinon.useFakeTimers(); - moduleConfig.beforeEach.apply(this, arguments); - }, - afterEach: function() { - this.clock.restore(); - this.clock.reset(); - } -}, () => { - test('click on unbound diagram', function(assert) { - this.instance._diagramInstance.commandManager.getCommand(DiagramCommand.Import).execute(SIMPLE_DIAGRAM); - let clickedItem; - this.instance.option('onItemClick', function(e) { - clickedItem = e.item; - }); - this.instance._diagramInstance.onNativeAction.raise('notifyItemClick', this.instance._diagramInstance.model.findShape('107').toNative()); - assert.equal(clickedItem.id, '107'); - assert.equal(clickedItem.text, 'A new ticket'); - }); - test('selectionchanged on unbound diagram', function(assert) { - this.instance._diagramInstance.commandManager.getCommand(DiagramCommand.Import).execute(SIMPLE_DIAGRAM); - let selectedItems; - this.instance.option('onSelectionChanged', function(e) { - selectedItems = e.items; - }); - this.instance._diagramInstance.selection.set([this.instance._diagramInstance.model.findShape('107').key]); - assert.equal(selectedItems.length, 1); - assert.equal(selectedItems[0].id, '107'); - assert.equal(selectedItems[0].text, 'A new ticket'); - }); - test('click on bound diagram', function(assert) { - this.instance.option('nodes.keyExpr', 'key'); - this.instance.option('nodes.textExpr', 'text'); - this.instance.option('edges.keyExpr', 'key'); - this.instance.option('edges.fromKey', 'from'); - this.instance.option('edges.toKey', 'to'); - this.instance.option('nodes.dataSource', [ - { key: '123', text: 'mytext', foo: 'bar' }, - { key: '345', text: 'myconnector' } - ]); - this.instance.option('edges.dataSource', [ - { key: '1', from: '123', to: '345' } - ]); - let clickedItem; - let dblClickedItem; - this.instance.option('onItemClick', function(e) { - clickedItem = e.item; - }); - this.instance.option('onItemDblClick', function(e) { - dblClickedItem = e.item; - }); - this.instance._diagramInstance.onNativeAction.raise('notifyItemClick', this.instance._diagramInstance.model.findShapeByDataKey('123').toNative()); - assert.equal(clickedItem.dataItem.key, '123'); - assert.equal(clickedItem.dataItem.foo, 'bar'); - assert.equal(clickedItem.text, 'mytext'); - assert.equal(dblClickedItem, undefined); - - this.instance._diagramInstance.onNativeAction.raise('notifyItemDblClick', this.instance._diagramInstance.model.findShapeByDataKey('123').toNative()); - assert.equal(dblClickedItem.dataItem.key, '123'); - assert.equal(dblClickedItem.dataItem.foo, 'bar'); - assert.equal(dblClickedItem.text, 'mytext'); - - this.instance._diagramInstance.onNativeAction.raise('notifyItemClick', this.instance._diagramInstance.model.findConnectorByDataKey('1').toNative()); - assert.equal(clickedItem.dataItem.key, '1'); - assert.equal(clickedItem.fromKey, '123'); - assert.equal(clickedItem.toKey, '345'); - }); - - test('hasChanges changes on import or editing of an unbound diagram', function(assert) { - assert.equal(this.instance.option('hasChanges'), false, 'on init'); - this.instance._diagramInstance.commandManager.getCommand(DiagramCommand.Import).execute(SIMPLE_DIAGRAM); - assert.equal(this.instance.option('hasChanges'), true, 'on import'); - this.instance.option('hasChanges', false); - this.instance._diagramInstance.selection.set(['107']); - this.instance._diagramInstance.commandManager.getCommand(DiagramCommand.Bold).execute(true); - assert.equal(this.instance.option('hasChanges'), true, 'on edit'); - }); -}); - -function findToolbarItem($diagram, label) { - return $diagram.find(TOOLBAR_SELECTOR) - .find('.dx-widget') - .filter(function() { - return $(this).text().toLowerCase().indexOf(label) >= 0; - }); -} diff --git a/testing/tests/DevExpress.ui.widgets/diagramParts/clientSideEvents.tests.js b/testing/tests/DevExpress.ui.widgets/diagramParts/clientSideEvents.tests.js new file mode 100644 index 000000000000..5f881f8df3c8 --- /dev/null +++ b/testing/tests/DevExpress.ui.widgets/diagramParts/clientSideEvents.tests.js @@ -0,0 +1,93 @@ +import $ from 'jquery'; +const { test } = QUnit; +import 'common.css!'; +import 'ui/diagram'; +import { DiagramCommand } from 'devexpress-diagram'; +import { SIMPLE_DIAGRAM } from '../diagram.tests.js'; + +const moduleConfig = { + beforeEach: function() { + this.$element = $('#diagram').dxDiagram(); + this.instance = this.$element.dxDiagram('instance'); + } +}; + +QUnit.module('ClientSideEvents', { + beforeEach: function() { + this.clock = sinon.useFakeTimers(); + moduleConfig.beforeEach.apply(this, arguments); + }, + afterEach: function() { + this.clock.restore(); + this.clock.reset(); + } +}, () => { + test('click on unbound diagram', function(assert) { + this.instance._diagramInstance.commandManager.getCommand(DiagramCommand.Import).execute(SIMPLE_DIAGRAM); + let clickedItem; + this.instance.option('onItemClick', function(e) { + clickedItem = e.item; + }); + this.instance._diagramInstance.onNativeAction.raise('notifyItemClick', this.instance._diagramInstance.model.findShape('107').toNative()); + assert.equal(clickedItem.id, '107'); + assert.equal(clickedItem.text, 'A new ticket'); + }); + test('selectionchanged on unbound diagram', function(assert) { + this.instance._diagramInstance.commandManager.getCommand(DiagramCommand.Import).execute(SIMPLE_DIAGRAM); + let selectedItems; + this.instance.option('onSelectionChanged', function(e) { + selectedItems = e.items; + }); + this.instance._diagramInstance.selection.set([this.instance._diagramInstance.model.findShape('107').key]); + assert.equal(selectedItems.length, 1); + assert.equal(selectedItems[0].id, '107'); + assert.equal(selectedItems[0].text, 'A new ticket'); + }); + test('click on bound diagram', function(assert) { + this.instance.option('nodes.keyExpr', 'key'); + this.instance.option('nodes.textExpr', 'text'); + this.instance.option('edges.keyExpr', 'key'); + this.instance.option('edges.fromKey', 'from'); + this.instance.option('edges.toKey', 'to'); + this.instance.option('nodes.dataSource', [ + { key: '123', text: 'mytext', foo: 'bar' }, + { key: '345', text: 'myconnector' } + ]); + this.instance.option('edges.dataSource', [ + { key: '1', from: '123', to: '345' } + ]); + let clickedItem; + let dblClickedItem; + this.instance.option('onItemClick', function(e) { + clickedItem = e.item; + }); + this.instance.option('onItemDblClick', function(e) { + dblClickedItem = e.item; + }); + this.instance._diagramInstance.onNativeAction.raise('notifyItemClick', this.instance._diagramInstance.model.findShapeByDataKey('123').toNative()); + assert.equal(clickedItem.dataItem.key, '123'); + assert.equal(clickedItem.dataItem.foo, 'bar'); + assert.equal(clickedItem.text, 'mytext'); + assert.equal(dblClickedItem, undefined); + + this.instance._diagramInstance.onNativeAction.raise('notifyItemDblClick', this.instance._diagramInstance.model.findShapeByDataKey('123').toNative()); + assert.equal(dblClickedItem.dataItem.key, '123'); + assert.equal(dblClickedItem.dataItem.foo, 'bar'); + assert.equal(dblClickedItem.text, 'mytext'); + + this.instance._diagramInstance.onNativeAction.raise('notifyItemClick', this.instance._diagramInstance.model.findConnectorByDataKey('1').toNative()); + assert.equal(clickedItem.dataItem.key, '1'); + assert.equal(clickedItem.fromKey, '123'); + assert.equal(clickedItem.toKey, '345'); + }); + + test('hasChanges changes on import or editing of an unbound diagram', function(assert) { + assert.equal(this.instance.option('hasChanges'), false, 'on init'); + this.instance._diagramInstance.commandManager.getCommand(DiagramCommand.Import).execute(SIMPLE_DIAGRAM); + assert.equal(this.instance.option('hasChanges'), true, 'on import'); + this.instance.option('hasChanges', false); + this.instance._diagramInstance.selection.set(['107']); + this.instance._diagramInstance.commandManager.getCommand(DiagramCommand.Bold).execute(true); + assert.equal(this.instance.option('hasChanges'), true, 'on edit'); + }); +}); diff --git a/testing/tests/DevExpress.ui.widgets/diagramParts/commandManager.tests.js b/testing/tests/DevExpress.ui.widgets/diagramParts/commandManager.tests.js new file mode 100644 index 000000000000..bcebf5bacf59 --- /dev/null +++ b/testing/tests/DevExpress.ui.widgets/diagramParts/commandManager.tests.js @@ -0,0 +1,82 @@ +import $ from 'jquery'; +const { test } = QUnit; +import 'common.css!'; +import 'ui/diagram'; +import DiagramCommandsManager from 'ui/diagram/diagram.commands_manager.js'; + +const moduleConfig = { + beforeEach: function() { + this.$element = $('#diagram').dxDiagram(); + this.instance = this.$element.dxDiagram('instance'); + } +}; + +QUnit.module('CommandManager', { + beforeEach: function() { + this.clock = sinon.useFakeTimers(); + moduleConfig.beforeEach.apply(this, arguments); + }, + afterEach: function() { + this.clock.restore(); + this.clock.reset(); + } +}, () => { + test('default commands', function(assert) { + assert.equal(DiagramCommandsManager.getMainToolbarCommands().length, 23); + assert.equal(DiagramCommandsManager.getHistoryToolbarCommands().length, 3); + assert.equal(DiagramCommandsManager.getViewToolbarCommands().length, 6); + assert.equal(DiagramCommandsManager.getContextMenuCommands().length, 12); + assert.equal(DiagramCommandsManager.getPropertyPanelCommands().length, 3); + }); + test('custom toolbar commands', function(assert) { + const commands = DiagramCommandsManager.getMainToolbarCommands([ + 'copy', + 'paste', + 'separator', + { 'text': 'AAA' }, + { 'icon': 'BBB' }, + { 'xxx': 'CCC' }, + { + 'text': 'DDD', + 'items': [ + 'cut', + 'separator', + 'selectAll' + ] + }, + ]); + assert.equal(commands.length, 6); + assert.equal(commands[5].items.length, 2); + assert.equal(commands[5].items[1].beginGroup, true); + }); + test('custom context menu commands', function(assert) { + const commands = DiagramCommandsManager.getContextMenuCommands([ + 'copy', + 'paste', + 'separator', + { 'text': 'AAA' }, + { 'icon': 'BBB' }, + { 'xxx': 'CCC' }, + { + 'text': 'DDD', + 'items': [ + 'cut', + 'separator', + 'selectAll' + ] + }, + ]); + assert.equal(commands.length, 5); + assert.equal(commands[2].beginGroup, true); + assert.equal(commands[4].items.length, 2); + assert.equal(commands[4].items[1].beginGroup, true); + }); + test('custom properties panel commands', function(assert) { + const commands = DiagramCommandsManager.getPropertyPanelCommands([ + { commands: [ 'gridSize', 'showGrid' ] }, + { commands: [ 'pageSize', 'pageColor' ] } + ]); + assert.equal(commands.length, 4); + assert.equal(commands[2].beginGroup, true); + }); +}); diff --git a/testing/tests/DevExpress.ui.widgets/diagramParts/contextMenu.tests.js b/testing/tests/DevExpress.ui.widgets/diagramParts/contextMenu.tests.js new file mode 100644 index 000000000000..8610abef762c --- /dev/null +++ b/testing/tests/DevExpress.ui.widgets/diagramParts/contextMenu.tests.js @@ -0,0 +1,62 @@ +import $ from 'jquery'; +const { test } = QUnit; +import 'common.css!'; +import 'ui/diagram'; +import { DiagramCommand } from 'devexpress-diagram'; +import { SIMPLE_DIAGRAM } from '../diagram.tests.js'; + +const CONTEXT_MENU_SELECTOR = 'div:not(.dx-diagram-toolbar-wrapper):not(.dx-diagram-floating-toolbar-container) > .dx-has-context-menu'; +const DX_MENU_ITEM_SELECTOR = '.dx-menu-item'; + +const moduleConfig = { + beforeEach: function() { + this.$element = $('#diagram').dxDiagram(); + this.instance = this.$element.dxDiagram('instance'); + } +}; + +QUnit.module('Context Menu', { + beforeEach: function() { + this.clock = sinon.useFakeTimers(); + moduleConfig.beforeEach.apply(this, arguments); + }, + afterEach: function() { + this.clock.restore(); + this.clock.reset(); + } +}, () => { + test('should not render if contextMenu.enabled is false', function(assert) { + let $contextMenu = this.$element.find(CONTEXT_MENU_SELECTOR); + assert.equal($contextMenu.length, 1); + this.instance.option('contextMenu.enabled', false); + $contextMenu = this.$element.children(CONTEXT_MENU_SELECTOR); + assert.equal($contextMenu.length, 0); + }); + test('should load default items', function(assert) { + const contextMenu = this.$element.find(CONTEXT_MENU_SELECTOR).dxContextMenu('instance'); + assert.ok(contextMenu.option('items').length > 1); + }); + test('should load custom items', function(assert) { + this.instance.option('contextMenu.commands', ['copy']); + const contextMenu = this.$element.find(CONTEXT_MENU_SELECTOR).dxContextMenu('instance'); + assert.equal(contextMenu.option('items').length, 1); + }); + test('should update items on showing', function(assert) { + this.instance.option('contextMenu.commands', ['copy', 'selectAll']); + const contextMenu = this.$element.find(CONTEXT_MENU_SELECTOR).dxContextMenu('instance'); + assert.notOk(contextMenu.option('visible')); + assert.ok(contextMenu.option('items')[0].text.indexOf('Copy') > -1); + contextMenu.show(); + assert.ok(contextMenu.option('visible')); + assert.ok(contextMenu.option('items')[0].text.indexOf('Select All') > -1); + }); + test('should execute commands on click', function(assert) { + this.instance.option('contextMenu.commands', ['selectAll']); + this.instance._diagramInstance.commandManager.getCommand(DiagramCommand.Import).execute(SIMPLE_DIAGRAM); + const contextMenu = this.$element.find(CONTEXT_MENU_SELECTOR).dxContextMenu('instance'); + contextMenu.show(); + assert.ok(this.instance._diagramInstance.selection.isEmpty()); + $(contextMenu.itemsContainer().find(DX_MENU_ITEM_SELECTOR).eq(0)).trigger('dxclick'); + assert.notOk(this.instance._diagramInstance.selection.isEmpty()); + }); +}); diff --git a/testing/tests/DevExpress.ui.widgets/diagramParts/dom.tests.js b/testing/tests/DevExpress.ui.widgets/diagramParts/dom.tests.js new file mode 100644 index 000000000000..a57d7d4e4b6b --- /dev/null +++ b/testing/tests/DevExpress.ui.widgets/diagramParts/dom.tests.js @@ -0,0 +1,75 @@ +import $ from 'jquery'; +const { test } = QUnit; +import 'common.css!'; +import 'ui/diagram'; + +const moduleConfig = { + beforeEach: function() { + this.$element = $('#diagram').dxDiagram(); + this.instance = this.$element.dxDiagram('instance'); + } +}; + +QUnit.module('DOM Layout', { + beforeEach: function() { + this.clock = sinon.useFakeTimers(); + moduleConfig.beforeEach.apply(this, arguments); + }, + afterEach: function() { + this.clock.restore(); + this.clock.reset(); + } +}, () => { + test('should return correct size of document container in default options', function(assert) { + assertSizes(assert, + this.$element.find('.dxdi-control'), + this.$element.find('.dx-diagram-drawer-wrapper'), + this.instance); + }); + test('should return correct size of document container if options panel is hidden', function(assert) { + this.instance.option('propertiesPanel.enabled', false); + this.clock.tick(10000); + assertSizes(assert, + this.$element.find('.dxdi-control'), + this.$element.find('.dx-diagram-drawer-wrapper'), + this.instance); + }); + + test('should return correct size of document container if toolbox is hidden', function(assert) { + this.instance.option('toolbox.visible', false); + this.clock.tick(10000); + assertSizes(assert, + this.$element.find('.dxdi-control'), + this.$element.find('.dx-diagram-drawer-wrapper'), + this.instance); + }); + + test('should return correct size of document container if toolbar is hidden', function(assert) { + this.instance.option('toolbar.visible', false); + this.clock.tick(10000); + assertSizes(assert, + this.$element.find('.dxdi-control'), + this.$element.find('.dx-diagram-drawer-wrapper'), + this.instance); + }); + + test('should return correct size of document container if all UI is hidden', function(assert) { + this.instance.option('toolbar.visible', false); + this.instance.option('toolbox.visible', false); + this.instance.option('propertiesPanel.enabled', false); + this.clock.tick(10000); + assertSizes(assert, + this.$element.find('.dxdi-control'), + this.$element.find('.dx-diagram-drawer-wrapper'), + this.instance); + }); + + + function assertSizes(assert, $scrollContainer, $actualContainer, inst) { + assert.equal($scrollContainer.width(), $actualContainer.width()); + assert.equal($scrollContainer.height(), $actualContainer.height()); + const coreScrollSize = inst._diagramInstance.render.view.scrollView.getSize(); + assert.equal(coreScrollSize.width, $actualContainer.width()); + assert.equal(coreScrollSize.height, $actualContainer.height()); + } +}); diff --git a/testing/tests/DevExpress.ui.widgets/diagramParts/historyToolbar.tests.js b/testing/tests/DevExpress.ui.widgets/diagramParts/historyToolbar.tests.js new file mode 100644 index 000000000000..a43f8e52d6ac --- /dev/null +++ b/testing/tests/DevExpress.ui.widgets/diagramParts/historyToolbar.tests.js @@ -0,0 +1,41 @@ +import $ from 'jquery'; +const { test } = QUnit; +import 'common.css!'; +import 'ui/diagram'; + +const FLOATING_TOOLBAR_SELECTOR = '.dx-diagram-floating-toolbar-container > .dx-diagram-toolbar'; + +const moduleConfig = { + beforeEach: function() { + this.$element = $('#diagram').dxDiagram(); + this.instance = this.$element.dxDiagram('instance'); + } +}; + +QUnit.module('History Toolbar', { + beforeEach: function() { + this.clock = sinon.useFakeTimers(); + moduleConfig.beforeEach.apply(this, arguments); + }, + afterEach: function() { + this.clock.restore(); + this.clock.reset(); + } +}, () => { + test('should not render if toolbar.visible is false', function(assert) { + let $toolbar = this.$element.find(FLOATING_TOOLBAR_SELECTOR); + assert.equal($toolbar.length, 2); + this.instance.option('historyToolbar.visible', false); + $toolbar = this.$element.find(FLOATING_TOOLBAR_SELECTOR); + assert.equal($toolbar.length, 1); + }); + test('should fill toolbar with default items', function(assert) { + const toolbar = $(this.$element.find(FLOATING_TOOLBAR_SELECTOR).get(0)).dxToolbar('instance'); + assert.equal(toolbar.option('dataSource').length, 3); + }); + test('should fill toolbar with custom items', function(assert) { + this.instance.option('historyToolbar.commands', ['copy']); + const toolbar = $(this.$element.find(FLOATING_TOOLBAR_SELECTOR).get(0)).dxToolbar('instance'); + assert.equal(toolbar.option('dataSource').length, 1); // + show properties panel + }); +}); diff --git a/testing/tests/DevExpress.ui.widgets/diagramParts/importDiagram.tests.js b/testing/tests/DevExpress.ui.widgets/diagramParts/importDiagram.tests.js index e3accec6774d..b19e08e65455 100644 --- a/testing/tests/DevExpress.ui.widgets/diagramParts/importDiagram.tests.js +++ b/testing/tests/DevExpress.ui.widgets/diagramParts/importDiagram.tests.js @@ -6,7 +6,7 @@ SystemJS.config({ }); define(function(require) { - const getDiagram = require('ui/diagram/diagram_importer').getDiagram; + const getDiagram = require('ui/diagram/diagram.importer').getDiagram; QUnit.module('Import devexpress-diagram', function() { QUnit.test('throw an error if the devexpress-diagram script isn\'t referenced', function(assert) { diff --git a/testing/tests/DevExpress.ui.widgets/diagramParts/mainToolbar.tests.js b/testing/tests/DevExpress.ui.widgets/diagramParts/mainToolbar.tests.js new file mode 100644 index 000000000000..59649dbde723 --- /dev/null +++ b/testing/tests/DevExpress.ui.widgets/diagramParts/mainToolbar.tests.js @@ -0,0 +1,151 @@ +import $ from 'jquery'; +const { test } = QUnit; +import 'common.css!'; +import 'ui/diagram'; +import { DiagramCommand } from 'devexpress-diagram'; +import { SIMPLE_DIAGRAM } from '../diagram.tests.js'; + +const MAIN_TOOLBAR_SELECTOR = '.dx-diagram-toolbar-wrapper > .dx-diagram-toolbar'; +const CONTEXT_MENU_SELECTOR = 'div:not(.dx-diagram-toolbar-wrapper):not(.dx-diagram-floating-toolbar-container) > .dx-has-context-menu'; +const TOOLBAR_ITEM_ACTIVE_CLASS = 'dx-format-active'; +const DX_MENU_ITEM_SELECTOR = '.dx-menu-item'; + +const moduleConfig = { + beforeEach: function() { + this.$element = $('#diagram').dxDiagram(); + this.instance = this.$element.dxDiagram('instance'); + } +}; + +QUnit.module('Main Toolbar', { + beforeEach: function() { + this.clock = sinon.useFakeTimers(); + moduleConfig.beforeEach.apply(this, arguments); + }, + afterEach: function() { + this.clock.restore(); + this.clock.reset(); + } +}, () => { + test('should not render if toolbar.visible is false', function(assert) { + this.instance.option('toolbar.visible', false); + const $toolbar = this.$element.find(MAIN_TOOLBAR_SELECTOR); + assert.equal($toolbar.length, 0); + }); + test('should fill toolbar with default items', function(assert) { + const toolbar = this.$element.find(MAIN_TOOLBAR_SELECTOR).dxToolbar('instance'); + assert.ok(toolbar.option('dataSource').length > 10); + }); + test('should fill toolbar with custom items', function(assert) { + this.instance.option('toolbar.commands', ['exportSvg']); + let toolbar = this.$element.find(MAIN_TOOLBAR_SELECTOR).dxToolbar('instance'); + assert.equal(toolbar.option('dataSource').length, 2); // + show properties panel + + this.instance.option('propertiesPanel.enabled', false); + toolbar = this.$element.find(MAIN_TOOLBAR_SELECTOR).dxToolbar('instance'); + assert.equal(toolbar.option('dataSource').length, 1); + this.instance.option('propertiesPanel.enabled', true); + this.instance.option('propertiesPanel.collapsible', false); + toolbar = this.$element.find(MAIN_TOOLBAR_SELECTOR).dxToolbar('instance'); + assert.equal(toolbar.option('dataSource').length, 1); + }); + test('should enable items on diagram request', function(assert) { + const undoButton = findToolbarItem(this.$element, 'undo').dxButton('instance'); + assert.ok(undoButton.option('disabled')); + this.instance._diagramInstance.commandManager.getCommand(DiagramCommand.PageLandscape).execute(true); + assert.notOk(undoButton.option('disabled')); + }); + test('should activate items on diagram request', function(assert) { + assert.ok(findToolbarItem(this.$element, 'center').hasClass(TOOLBAR_ITEM_ACTIVE_CLASS)); + assert.notOk(findToolbarItem(this.$element, 'left').hasClass(TOOLBAR_ITEM_ACTIVE_CLASS)); + this.instance._diagramInstance.commandManager.getCommand(DiagramCommand.TextLeftAlign).execute(true); + assert.notOk(findToolbarItem(this.$element, 'center').hasClass(TOOLBAR_ITEM_ACTIVE_CLASS)); + assert.ok(findToolbarItem(this.$element, 'left').hasClass(TOOLBAR_ITEM_ACTIVE_CLASS)); + }); + test('button should raise diagram commands', function(assert) { + assert.notOk(this.instance._diagramInstance.commandManager.getCommand(DiagramCommand.TextLeftAlign).getState().value); + findToolbarItem(this.$element, 'left').trigger('dxclick'); + assert.ok(this.instance._diagramInstance.commandManager.getCommand(DiagramCommand.TextLeftAlign).getState().value); + }); + test('selectBox should raise diagram commands', function(assert) { + assert.equal(this.instance._diagramInstance.commandManager.getCommand(DiagramCommand.FontName).getState().value, 'Arial'); + const fontSelectBox = this.$element.find(MAIN_TOOLBAR_SELECTOR).find('.dx-selectbox').eq(0).dxSelectBox('instance'); + fontSelectBox.option('value', 'Arial Black'); + assert.equal(this.instance._diagramInstance.commandManager.getCommand(DiagramCommand.FontName).getState().value, 'Arial Black'); + }); + test('selectboxes with icon items should be replaced with select buttons', function(assert) { + const $selectButtonTemplates = this.$element.find(MAIN_TOOLBAR_SELECTOR).find('.dx-diagram-select-b').find('.dx-dropdowneditor-field-template-wrapper'); + assert.ok($selectButtonTemplates.length > 0, 'select buttons are rendered'); + const selectButtonsCount = $selectButtonTemplates.length; + assert.equal($selectButtonTemplates.find('.dx-diagram-i').length, selectButtonsCount, 'icons are rendered'); + assert.equal($selectButtonTemplates.find('.dx-textbox')[0].offsetWidth, 0, 'textbox is hidden'); + }); + test('colorboxes should be replaced with color buttons', function(assert) { + const $selectButtonTemplates = this.$element.find(MAIN_TOOLBAR_SELECTOR).find('.dx-diagram-color-b').find('.dx-dropdowneditor-field-template-wrapper'); + assert.ok($selectButtonTemplates.length > 0, 'color buttons are rendered'); + const selectButtonsCount = $selectButtonTemplates.length; + assert.equal($selectButtonTemplates.find('.dx-diagram-i, .dx-icon').length, selectButtonsCount, 'icons are rendered'); + assert.equal($selectButtonTemplates.find('.dx-textbox')[0].offsetWidth, 0, 'textbox is hidden'); + }); + test('colorbuttons should show an active color', function(assert) { + const colorButton = this.$element.find(MAIN_TOOLBAR_SELECTOR).find('.dx-diagram-color-b').first(); + assert.equal(getToolbarIcon(colorButton).css('borderBottomColor'), 'rgb(0, 0, 0)'); + this.instance._diagramInstance.commandManager.getCommand(DiagramCommand.FontColor).execute('rgb(255, 0, 0)'); + assert.equal(getToolbarIcon(colorButton).css('borderBottomColor'), 'rgb(255, 0, 0)', 'button changed via command'); + colorButton.find('.dx-dropdowneditor-button').trigger('dxclick'); + const $overlayContent = $('.dx-colorbox-overlay'); + $overlayContent.find('.dx-colorview-label-hex').find('.dx-textbox').dxTextBox('instance').option('value', '00ff00'); + $overlayContent.find('.dx-colorview-buttons-container .dx-colorview-apply-button').trigger('dxclick'); + assert.equal(this.instance._diagramInstance.commandManager.getCommand(DiagramCommand.FontColor).getState().value, '#00ff00', 'color changed by color button'); + assert.equal(getToolbarIcon(colorButton).css('borderBottomColor'), 'rgb(0, 255, 0)', 'button changed via coloredit'); + }); + test('colorbutton should show dropdown on icon click', function(assert) { + const colorButton = this.$element.find(MAIN_TOOLBAR_SELECTOR).find('.dx-diagram-color-b').first(); + const colorBox = colorButton.find('.dx-colorbox').dxColorBox('instance'); + getToolbarIcon(colorButton).trigger('dxclick'); + assert.ok(colorBox.option('opened'), true); + }); + test('diagram should be focused after change font family', function(assert) { + const fontSelectBox = this.$element.find(MAIN_TOOLBAR_SELECTOR).find('.dx-selectbox').eq(0).dxSelectBox('instance'); + fontSelectBox.focus(); + fontSelectBox.open(); + const item = $(document).find('.dx-list-item-content').filter(function() { + return $(this).text().toLowerCase().indexOf('arial black') >= 0; + }); + assert.notEqual(document.activeElement, this.instance._diagramInstance.render.input.inputElement); + item.trigger('dxclick'); + assert.equal(document.activeElement, this.instance._diagramInstance.render.input.inputElement); + }); + test('diagram should be focused after set font bold', function(assert) { + const boldButton = findToolbarItem(this.$element, 'bold'); + assert.notEqual(document.activeElement, this.instance._diagramInstance.render.input.inputElement); + boldButton.trigger('dxclick'); + assert.equal(document.activeElement, this.instance._diagramInstance.render.input.inputElement); + }); + test('Auto Layout button should be disabled when there is no selection', function(assert) { + const button = findToolbarItem(this.$element, 'auto layout').dxButton('instance'); + assert.ok(button.option('disabled')); + }); + test('Auto Layout button should be disabled in Read Only mode', function(assert) { + this.instance.option('contextMenu.commands', ['selectAll']); + this.instance._diagramInstance.commandManager.getCommand(DiagramCommand.Import).execute(SIMPLE_DIAGRAM); + const contextMenu = this.$element.find(CONTEXT_MENU_SELECTOR).dxContextMenu('instance'); + contextMenu.show(); + $(contextMenu.itemsContainer().find(DX_MENU_ITEM_SELECTOR).eq(0)).trigger('dxclick'); // Select All + const button = findToolbarItem(this.$element, 'auto layout').dxButton('instance'); + assert.notOk(button.option('disabled')); + this.instance.option('readOnly', true); + assert.ok(button.option('disabled')); + }); +}); + +function getToolbarIcon(button) { + return button.find('.dx-dropdowneditor-field-template-wrapper').find('.dx-diagram-i, .dx-icon'); +} +function findToolbarItem($diagramElement, label) { + return $diagramElement.find(MAIN_TOOLBAR_SELECTOR) + .find('.dx-widget') + .filter(function() { + return $(this).text().toLowerCase().indexOf(label) >= 0; + }); +} diff --git a/testing/tests/DevExpress.ui.widgets/diagramParts/options.tests.js b/testing/tests/DevExpress.ui.widgets/diagramParts/options.tests.js new file mode 100644 index 000000000000..8ff3596d7262 --- /dev/null +++ b/testing/tests/DevExpress.ui.widgets/diagramParts/options.tests.js @@ -0,0 +1,240 @@ +import $ from 'jquery'; +const { test } = QUnit; +import 'common.css!'; +import 'ui/diagram'; +import { DiagramCommand, DataLayoutType } from 'devexpress-diagram'; + +const moduleConfig = { + beforeEach: function() { + this.$element = $('#diagram').dxDiagram(); + this.instance = this.$element.dxDiagram('instance'); + } +}; + +QUnit.module('Options', moduleConfig, () => { + test('should change readOnly property', function(assert) { + assert.notOk(this.instance._diagramInstance.settings.readOnly); + this.instance.option('readOnly', true); + assert.ok(this.instance._diagramInstance.settings.readOnly); + this.instance.option('readOnly', false); + assert.notOk(this.instance._diagramInstance.settings.readOnly); + }); + test('should change zoomLevel property', function(assert) { + assert.equal(this.instance._diagramInstance.settings.zoomLevel, 1); + this.instance.option('zoomLevel', 1.5); + assert.equal(this.instance._diagramInstance.settings.zoomLevel, 1.5); + this.instance.option('zoomLevel', 1); + assert.equal(this.instance._diagramInstance.settings.zoomLevel, 1); + }); + test('should sync zoomLevel property', function(assert) { + assert.equal(this.instance.option('zoomLevel'), 1); + this.instance._diagramInstance.commandManager.getCommand(DiagramCommand.ZoomLevel).execute(1.5); + assert.equal(this.instance.option('zoomLevel'), 1.5); + }); + test('should change zoomLevel object property', function(assert) { + assert.equal(this.instance._diagramInstance.settings.zoomLevel, 1); + assert.equal(this.instance._diagramInstance.settings.zoomLevelItems.length, 7); + this.instance.option('zoomLevel', { value: 1.5, items: [ 1, 1.5 ] }); + assert.equal(this.instance._diagramInstance.settings.zoomLevel, 1.5); + assert.equal(this.instance._diagramInstance.settings.zoomLevelItems.length, 2); + this.instance.option('zoomLevel', 1); + assert.equal(this.instance._diagramInstance.settings.zoomLevel, 1); + assert.equal(this.instance._diagramInstance.settings.zoomLevelItems.length, 2); + }); + test('should sync zoomLevel object property', function(assert) { + this.instance.option('zoomLevel', { value: 1.5, items: [ 1, 1.5, 2 ] }); + assert.equal(this.instance.option('zoomLevel.value'), 1.5); + this.instance._diagramInstance.commandManager.getCommand(DiagramCommand.ZoomLevel).execute(2); + assert.equal(this.instance.option('zoomLevel.value'), 2); + }); + test('should change autoZoom property', function(assert) { + assert.equal(this.instance._diagramInstance.settings.autoZoom, 0); + this.instance.option('autoZoom', 'fitContent'); + assert.equal(this.instance._diagramInstance.settings.autoZoom, 1); + this.instance.option('autoZoom', 'fitWidth'); + assert.equal(this.instance._diagramInstance.settings.autoZoom, 2); + this.instance.option('autoZoom', 'disabled'); + assert.equal(this.instance._diagramInstance.settings.autoZoom, 0); + }); + test('should sync autoZoom property', function(assert) { + assert.equal(this.instance.option('autoZoom'), 'disabled'); + this.instance._diagramInstance.commandManager.getCommand(DiagramCommand.SwitchAutoZoom).execute(1); + assert.equal(this.instance.option('autoZoom'), 'fitContent'); + }); + test('should change fullScreen property', function(assert) { + assert.notOk(this.instance._diagramInstance.settings.fullscreen); + this.instance.option('fullScreen', true); + assert.ok(this.instance._diagramInstance.settings.fullscreen); + this.instance.option('fullScreen', false); + assert.notOk(this.instance._diagramInstance.settings.fullscreen); + }); + test('should sync fullScreen property', function(assert) { + assert.equal(this.instance.option('fullScreen'), false); + this.instance._diagramInstance.commandManager.getCommand(DiagramCommand.Fullscreen).execute(true); + assert.equal(this.instance.option('fullScreen'), true); + }); + test('should change showGrid property', function(assert) { + assert.ok(this.instance._diagramInstance.settings.showGrid); + this.instance.option('showGrid', false); + assert.notOk(this.instance._diagramInstance.settings.showGrid); + this.instance.option('showGrid', true); + assert.ok(this.instance._diagramInstance.settings.showGrid); + }); + test('should sync showGrid property', function(assert) { + assert.equal(this.instance.option('showGrid'), true); + this.instance._diagramInstance.commandManager.getCommand(DiagramCommand.ShowGrid).execute(false); + assert.equal(this.instance.option('showGrid'), false); + }); + test('should change snapToGrid property', function(assert) { + assert.ok(this.instance._diagramInstance.settings.snapToGrid); + this.instance.option('snapToGrid', false); + assert.notOk(this.instance._diagramInstance.settings.snapToGrid); + this.instance.option('snapToGrid', true); + assert.ok(this.instance._diagramInstance.settings.snapToGrid); + }); + test('should sync snapToGrid property', function(assert) { + assert.equal(this.instance.option('snapToGrid'), true); + this.instance._diagramInstance.commandManager.getCommand(DiagramCommand.SnapToGrid).execute(false); + assert.equal(this.instance.option('snapToGrid'), false); + }); + test('should change gridSize property', function(assert) { + assert.equal(this.instance._diagramInstance.settings.gridSize, 180); + this.instance.option('gridSize', 0.25); + assert.equal(this.instance._diagramInstance.settings.gridSize, 360); + this.instance.option('gridSize', 0.125); + assert.equal(this.instance._diagramInstance.settings.gridSize, 180); + }); + test('should sync gridSize property', function(assert) { + assert.equal(this.instance.option('gridSize'), 0.125); + this.instance._diagramInstance.commandManager.getCommand(DiagramCommand.GridSize).execute(0.25); + assert.equal(this.instance.option('gridSize'), 0.25); + }); + test('should change gridSize object property', function(assert) { + assert.equal(this.instance._diagramInstance.settings.gridSize, 180); + assert.equal(this.instance._diagramInstance.settings.gridSizeItems.length, 4); + this.instance.option('gridSize', { value: 0.25, items: [0.25, 1] }); + assert.equal(this.instance._diagramInstance.settings.gridSize, 360); + assert.equal(this.instance._diagramInstance.settings.gridSizeItems.length, 2); + this.instance.option('gridSize', 0.125); + assert.equal(this.instance._diagramInstance.settings.gridSize, 180); + assert.equal(this.instance._diagramInstance.settings.gridSizeItems.length, 2); + }); + test('should sync gridSize object property', function(assert) { + this.instance.option('gridSize', { value: 0.25, items: [0.125, 0.25, 1] }); + assert.equal(this.instance.option('gridSize.value'), 0.25); + this.instance._diagramInstance.commandManager.getCommand(DiagramCommand.GridSize).execute(1); + assert.equal(this.instance.option('gridSize.value'), 1); + }); + test('should change viewUnits property', function(assert) { + assert.equal(this.instance._diagramInstance.settings.viewUnits, 0); + this.instance.option('viewUnits', 'cm'); + assert.equal(this.instance._diagramInstance.settings.viewUnits, 1); + this.instance.option('viewUnits', 'in'); + assert.equal(this.instance._diagramInstance.settings.viewUnits, 0); + }); + test('should sync viewUnits property', function(assert) { + assert.equal(this.instance.option('viewUnits'), 'in'); + this.instance._diagramInstance.commandManager.getCommand(DiagramCommand.ViewUnits).execute(1); + assert.equal(this.instance.option('viewUnits'), 'cm'); + }); + test('should change units property', function(assert) { + assert.equal(this.instance._diagramInstance.model.units, 0); + this.instance.option('units', 'cm'); + assert.equal(this.instance._diagramInstance.model.units, 1); + this.instance.option('units', 'in'); + assert.equal(this.instance._diagramInstance.model.units, 0); + }); + test('should change pageSize property', function(assert) { + assert.equal(this.instance._diagramInstance.model.pageSize.width, 8391); + assert.equal(this.instance._diagramInstance.model.pageSize.height, 11906); + this.instance.option('pageSize', { width: 3, height: 5 }); + assert.equal(this.instance._diagramInstance.model.pageSize.width, 4320); + assert.equal(this.instance._diagramInstance.model.pageSize.height, 7200); + }); + test('should sync pageSize property', function(assert) { + this.instance.option('pageSize', { width: 3, height: 5 }); + assert.equal(this.instance.option('pageSize.width'), 3); + assert.equal(this.instance.option('pageSize.height'), 5); + this.instance._diagramInstance.commandManager.getCommand(DiagramCommand.PageSize).execute({ width: 4, height: 6 }); + assert.equal(this.instance.option('pageSize.width'), 4); + assert.equal(this.instance.option('pageSize.height'), 6); + }); + test('should change pageSize object property', function(assert) { + assert.equal(this.instance._diagramInstance.model.pageSize.width, 8391); + assert.equal(this.instance._diagramInstance.model.pageSize.height, 11906); + assert.equal(this.instance._diagramInstance.settings.pageSizeItems.length, 11); + this.instance.option('pageSize', { width: 3, height: 5, items: [{ width: 3, height: 5, text: 'A10' }] }); + assert.equal(this.instance._diagramInstance.model.pageSize.width, 4320); + assert.equal(this.instance._diagramInstance.model.pageSize.height, 7200); + assert.equal(this.instance._diagramInstance.settings.pageSizeItems.length, 1); + }); + test('should sync pageSize object property', function(assert) { + this.instance.option('pageSize', { width: 3, height: 5, items: [{ width: 3, height: 5, text: 'A10' }, { width: 4, height: 6, text: 'A11' }] }); + assert.equal(this.instance.option('pageSize.width'), 3); + assert.equal(this.instance.option('pageSize.height'), 5); + this.instance._diagramInstance.commandManager.getCommand(DiagramCommand.PageSize).execute({ width: 4, height: 6 }); + assert.equal(this.instance.option('pageSize.width'), 4); + assert.equal(this.instance.option('pageSize.height'), 6); + }); + test('should change pageOrientation property', function(assert) { + assert.equal(this.instance._diagramInstance.model.pageLandscape, false); + this.instance.option('pageOrientation', 'landscape'); + assert.equal(this.instance._diagramInstance.model.pageLandscape, true); + this.instance.option('pageOrientation', 'portrait'); + assert.equal(this.instance._diagramInstance.model.pageLandscape, false); + }); + test('should sync pageOrientation property', function(assert) { + assert.equal(this.instance.option('pageOrientation'), 'portrait'); + this.instance._diagramInstance.commandManager.getCommand(DiagramCommand.PageLandscape).execute(1); + assert.equal(this.instance.option('pageOrientation'), 'landscape'); + }); + test('should change pageColor property', function(assert) { + assert.equal(this.instance._diagramInstance.model.pageColor, -1); // FFFFFF + this.instance.option('pageColor', 'red'); + assert.equal(this.instance._diagramInstance.model.pageColor, -65536); // FF0000 + this.instance.option('pageColor', 'white'); + assert.equal(this.instance._diagramInstance.model.pageColor, -1); // FFFFFF + }); + test('should sync pageColor property', function(assert) { + assert.equal(this.instance.option('pageColor'), '#ffffff'); + this.instance._diagramInstance.commandManager.getCommand(DiagramCommand.PageColor).execute('red'); + assert.equal(this.instance.option('pageColor'), '#ff0000'); // FF0000 + }); + test('should change simpleView property', function(assert) { + assert.equal(this.instance._diagramInstance.settings.simpleView, false); + this.instance.option('simpleView', true); + assert.equal(this.instance._diagramInstance.settings.simpleView, true); + this.instance.option('simpleView', false); + assert.equal(this.instance._diagramInstance.settings.simpleView, false); + }); + test('should sync simpleView property', function(assert) { + assert.equal(this.instance.option('simpleView'), false); + this.instance._diagramInstance.commandManager.getCommand(DiagramCommand.ToggleSimpleView).execute(true); + assert.equal(this.instance.option('simpleView'), true); + }); + test('should return correct autoLayout parameters based on the nodes.autoLayout option', function(assert) { + assert.equal(this.instance.option('nodes.autoLayout'), 'auto'); + assert.deepEqual(this.instance._getDataBindingLayoutParameters(), { type: DataLayoutType.Sugiyama }); + + this.instance.option('nodes.leftExpr', 'left'); + this.instance.option('nodes.topExpr', 'left'); + assert.equal(this.instance._getDataBindingLayoutParameters(), undefined); + this.instance.option('nodes.autoLayout', { type: 'auto' }); + assert.equal(this.instance._getDataBindingLayoutParameters(), undefined); + + this.instance.option('nodes.leftExpr', ''); + assert.deepEqual(this.instance._getDataBindingLayoutParameters(), { type: DataLayoutType.Sugiyama }); + this.instance.option('nodes.topExpr', ''); + assert.deepEqual(this.instance._getDataBindingLayoutParameters(), { type: DataLayoutType.Sugiyama }); + + this.instance.option('nodes.autoLayout', 'off'); + assert.equal(this.instance._getDataBindingLayoutParameters(), undefined); + this.instance.option('nodes.autoLayout', { type: 'off' }); + assert.equal(this.instance._getDataBindingLayoutParameters(), undefined); + + this.instance.option('nodes.autoLayout', 'tree'); + assert.deepEqual(this.instance._getDataBindingLayoutParameters(), { type: DataLayoutType.Tree }); + this.instance.option('nodes.autoLayout', { type: 'tree' }); + assert.deepEqual(this.instance._getDataBindingLayoutParameters(), { type: DataLayoutType.Tree }); + }); +}); diff --git a/testing/tests/DevExpress.ui.widgets/diagramParts/propertiesPanel.tests.js b/testing/tests/DevExpress.ui.widgets/diagramParts/propertiesPanel.tests.js new file mode 100644 index 000000000000..1dd94ac2b3b1 --- /dev/null +++ b/testing/tests/DevExpress.ui.widgets/diagramParts/propertiesPanel.tests.js @@ -0,0 +1,31 @@ +import $ from 'jquery'; +const { test } = QUnit; +import 'common.css!'; +import 'ui/diagram'; + +const PROPERTIES_PANEL_ACCORDION_SELECTOR = '.dx-diagram-right-panel .dx-accordion'; +const PROPERTIES_PANEL_FORM_SELECTOR = '.dx-diagram-right-panel .dx-accordion .dx-form'; + +const moduleConfig = { + beforeEach: function() { + this.$element = $('#diagram').dxDiagram(); + this.instance = this.$element.dxDiagram('instance'); + } +}; + +QUnit.module('Properties Panel', moduleConfig, () => { + test('should not render if propertiesPanel.enabled is false', function(assert) { + this.instance.option('propertiesPanel.enabled', false); + const $accordion = this.$element.find(PROPERTIES_PANEL_ACCORDION_SELECTOR); + assert.equal($accordion.length, 0); + }); + test('should fill properties panel with default items', function(assert) { + const form = this.$element.find(PROPERTIES_PANEL_FORM_SELECTOR).dxForm('instance'); + assert.ok(form.option('items').length > 1); + }); + test('should fill toolbox with custom items', function(assert) { + this.instance.option('propertiesPanel.groups', [{ commands: ['units'] }]); + const form = this.$element.find(PROPERTIES_PANEL_FORM_SELECTOR).dxForm('instance'); + assert.equal(form.option('items').length, 1); + }); +}); diff --git a/testing/tests/DevExpress.ui.widgets/diagramParts/toolbox.tests.js b/testing/tests/DevExpress.ui.widgets/diagramParts/toolbox.tests.js new file mode 100644 index 000000000000..37f1b0b23e21 --- /dev/null +++ b/testing/tests/DevExpress.ui.widgets/diagramParts/toolbox.tests.js @@ -0,0 +1,42 @@ +import $ from 'jquery'; +const { test } = QUnit; +import 'common.css!'; +import 'ui/diagram'; + +const TOOLBOX_SCROLLVIEW_SELECTOR = '.dx-diagram-toolbox-panel .dx-scrollview'; +const TOOLBOX_ACCORDION_SELECTOR = '.dx-diagram-toolbox-panel .dx-accordion'; + +const moduleConfig = { + beforeEach: function() { + this.$element = $('#diagram').dxDiagram(); + this.instance = this.$element.dxDiagram('instance'); + } +}; + +QUnit.module('Toolbox', moduleConfig, () => { + test('should not render if toolbox.visible is false', function(assert) { + this.instance.option('toolbox.visible', false); + const $accordion = $('body').find(TOOLBOX_ACCORDION_SELECTOR); + assert.equal($accordion.length, 0); + }); + test('should fill toolbox with default items', function(assert) { + const accordion = $('body').find(TOOLBOX_ACCORDION_SELECTOR).dxAccordion('instance'); + assert.ok(accordion.option('dataSource').length > 1); + }); + test('should fill toolbox with custom items', function(assert) { + this.instance.option('toolbox.groups', ['general']); + const accordion = $('body').find(TOOLBOX_ACCORDION_SELECTOR).dxAccordion('instance'); + assert.equal(accordion.option('dataSource').length, 1); + }); + test('call .update() after accordion item collapsing/expanding', function(assert) { + const clock = sinon.useFakeTimers(); + const $scrollView = $('body').find(TOOLBOX_SCROLLVIEW_SELECTOR); + const scrollView = $scrollView.dxScrollView('instance'); + const updateSpy = sinon.spy(scrollView, 'update'); + const $accordion = $('body').find(TOOLBOX_ACCORDION_SELECTOR); + $accordion.find('.dx-accordion-item-title').first().trigger('dxclick'); + clock.tick(2000); + assert.equal(updateSpy.callCount, 1, 'scrollView.update() called once'); + clock.restore(); + }); +}); diff --git a/testing/tests/DevExpress.ui.widgets/diagramParts/viewToolbar.tests.js b/testing/tests/DevExpress.ui.widgets/diagramParts/viewToolbar.tests.js new file mode 100644 index 000000000000..1df77432ddca --- /dev/null +++ b/testing/tests/DevExpress.ui.widgets/diagramParts/viewToolbar.tests.js @@ -0,0 +1,58 @@ +import $ from 'jquery'; +const { test } = QUnit; +import 'common.css!'; +import 'ui/diagram'; + +const FLOATING_TOOLBAR_SELECTOR = '.dx-diagram-floating-toolbar-container > .dx-diagram-toolbar'; +const DIAGRAM_FULLSCREEN_CLASS = 'dx-diagram-fullscreen'; + +const moduleConfig = { + beforeEach: function() { + this.$element = $('#diagram').dxDiagram(); + this.instance = this.$element.dxDiagram('instance'); + } +}; + +QUnit.module('View Toolbar', { + beforeEach: function() { + this.clock = sinon.useFakeTimers(); + moduleConfig.beforeEach.apply(this, arguments); + }, + afterEach: function() { + this.clock.restore(); + this.clock.reset(); + } +}, () => { + test('should not render if toolbar.visible is false', function(assert) { + let $toolbar = this.$element.find(FLOATING_TOOLBAR_SELECTOR); + assert.equal($toolbar.length, 2); + this.instance.option('viewToolbar.visible', false); + $toolbar = this.$element.find(FLOATING_TOOLBAR_SELECTOR); + assert.equal($toolbar.length, 1); + }); + test('should fill toolbar with default items', function(assert) { + const toolbar = $(this.$element.find(FLOATING_TOOLBAR_SELECTOR).get(1)).dxToolbar('instance'); + assert.equal(toolbar.option('dataSource').length, 6); + }); + test('should fill toolbar with custom items', function(assert) { + this.instance.option('viewToolbar.commands', ['copy']); + const toolbar = $(this.$element.find(FLOATING_TOOLBAR_SELECTOR).get(1)).dxToolbar('instance'); + assert.equal(toolbar.option('dataSource').length, 1); // + show properties panel + }); + test('should toggle fullscreen class name on button click', function(assert) { + assert.notOk(this.$element.hasClass(DIAGRAM_FULLSCREEN_CLASS)); + const fullScreenButton = findToolbarItem(this.$element, 'full screen'); + fullScreenButton.trigger('dxclick'); + assert.ok(this.$element.hasClass(DIAGRAM_FULLSCREEN_CLASS)); + fullScreenButton.trigger('dxclick'); + assert.notOk(this.$element.hasClass(DIAGRAM_FULLSCREEN_CLASS)); + }); +}); + +function findToolbarItem($diagramElement, label) { + return $($diagramElement.find(FLOATING_TOOLBAR_SELECTOR).get(1)) + .find('.dx-widget') + .filter(function() { + return $(this).text().toLowerCase().indexOf(label) >= 0; + }); +} diff --git a/testing/tests/DevExpress.ui.widgets/draggable.tests.js b/testing/tests/DevExpress.ui.widgets/draggable.tests.js index 94a71176093f..f83a8a6ee0c0 100644 --- a/testing/tests/DevExpress.ui.widgets/draggable.tests.js +++ b/testing/tests/DevExpress.ui.widgets/draggable.tests.js @@ -1035,8 +1035,6 @@ QUnit.module('clone', moduleConfig); QUnit.test('Clone an element when dragging', function(assert) { // arrange - let $cloneElement; - this.createDraggable({ clone: true }); @@ -1045,7 +1043,8 @@ QUnit.test('Clone an element when dragging', function(assert) { this.pointer.down().move(10, 10); // assert - $cloneElement = $('body').children('.dx-draggable-dragging').children('#draggable'); + const $cloneElement = $('body').children('.dx-draggable-dragging').children('#draggable'); + assert.strictEqual($cloneElement.length, 1, 'cloned element'); assert.ok($cloneElement.parent().hasClass('dx-draggable-dragging'), 'parent of cloned element has dragging class'); assert.ok(this.$element.hasClass('dx-draggable-source'), 'element has source class'); @@ -1055,6 +1054,28 @@ QUnit.test('Clone an element when dragging', function(assert) { assert.equal($cloneElement.parent().css('z-index'), MAX_INTEGER, 'z-index of the cloned element'); this.checkPosition(10, 10, assert, $cloneElement); this.checkPosition(0, 0, assert); + + assert.notOk($cloneElement.hasClass('dx-rtl'), 'clone has not dx-rtl class'); + assert.equal($cloneElement.css('direction'), 'ltr', 'clone\'s direction is ltr'); +}); + +// T859557 +QUnit.test('Clone\'s direction should be rtl if rtlEnabled: true', function(assert) { + // arrange + this.createDraggable({ + clone: true, + rtlEnabled: true + }); + + // act + this.pointer.down().move(10, 10); + + // assert + const $cloneElement = $('body').children('.dx-draggable-dragging'); + + assert.strictEqual($cloneElement.length, 1, 'cloned element'); + assert.ok($cloneElement.hasClass('dx-rtl'), 'clone has dx-rtl class'); + assert.equal($cloneElement.css('direction'), 'rtl', 'clone\'s direction is rtl'); }); QUnit.test('Remove cloned element after the drop end', function(assert) { diff --git a/testing/tests/DevExpress.ui.widgets/dropDownButton.tests.js b/testing/tests/DevExpress.ui.widgets/dropDownButton.tests.js index abf01d6003f2..49e41689d703 100644 --- a/testing/tests/DevExpress.ui.widgets/dropDownButton.tests.js +++ b/testing/tests/DevExpress.ui.widgets/dropDownButton.tests.js @@ -15,6 +15,7 @@ const DROP_DOWN_BUTTON_ACTION_CLASS = 'dx-dropdownbutton-action'; const DROP_DOWN_BUTTON_TOGGLE_CLASS = 'dx-dropdownbutton-toggle'; const BUTTON_GROUP_WRAPPER = 'dx-buttongroup-wrapper'; const BUTTON_TEXT = 'dx-button-text'; +const LIST_GROUP_HEADER_CLASS = 'dx-list-group-header'; QUnit.testStart(() => { const markup = @@ -469,6 +470,19 @@ QUnit.module('list integration', {}, () => { assert.strictEqual(list.option('keyExpr'), 'this', 'keyExpr is \'this\''); }); + QUnit.test('deferRendering option change', function(assert) { + const dropDownButton = new DropDownButton('#dropDownButton', { + items: ['Item 1'] + }); + + const list = getList(dropDownButton); + assert.strictEqual(list, undefined, 'list has not been rendered'); + + dropDownButton.option('deferRendering', false); + const $listItems = getList(dropDownButton).itemElements(); + assert.strictEqual($listItems.eq(0).text(), 'Item 1', 'list has been rendered'); + }); + QUnit.test('data expressions should work with dropDownButton', function(assert) { const dropDownButton = new DropDownButton('#dropDownButton', { items: [{ key: 1, name: 'Item 1', icon: 'box' }], @@ -494,11 +508,45 @@ QUnit.module('list integration', {}, () => { useSelectMode: false }); - const list = getList(dropDownButton); + let list = getList(dropDownButton); assert.strictEqual(list.option('grouped'), true, 'grouped option transfered'); assert.strictEqual(list.option('noDataText'), 'No data', 'noDataText option transfered'); assert.strictEqual(list.option('selectionMode'), 'none', 'selectionMode is none for useSelectMode: false'); + + dropDownButton.option({ + grouped: false, + noDataText: 'nothing', + useSelectMode: true + }); + + list = getList(dropDownButton); + + assert.strictEqual(list.option('grouped'), false, 'grouped option transfered'); + assert.strictEqual(list.option('noDataText'), 'nothing', 'noDataText option transfered'); + assert.strictEqual(list.option('selectionMode'), 'single', 'selectionMode is single for useSelectMode: true'); + }); + + QUnit.test('groupTemplate should be transfered to list', function(assert) { + const dropDownButton = new DropDownButton('#dropDownButton', { + items: [{ key: 1, name: 'Item 1', icon: 'box' }], + deferRendering: false, + grouped: true, + groupTemplate: (data) => { + return $('
').text(`${data.key}: ${data.name}`); + } + }); + const $element = dropDownButton.$element(); + + let groupHeaders = $element.find(`.${LIST_GROUP_HEADER_CLASS}`); + assert.equal(groupHeaders.eq(0).text(), '1: Item 1', 'groupTemplate is transfered to list on init'); + + dropDownButton.option('groupTemplate', (data) => { + return $('
').text(`Group #${data.key}`); + }); + + groupHeaders = $element.find(`.${LIST_GROUP_HEADER_CLASS}`); + assert.equal(groupHeaders.eq(0).text(), 'Group #1', 'groupTemplate is transfered to list after option change'); }); QUnit.test('list should have single selection mode if useSelectMode: true', function(assert) { @@ -746,6 +794,18 @@ QUnit.module('common use cases', { assert.strictEqual(getActionButton(this.dropDownButton).text(), 'Trial for Visual Studio', 'action button has been changed'); }); + QUnit.test('Widget should work correct if new selected item has key is 0', function(assert) { + this.dropDownButton.option({ + items: [{ id: 0, name: 'Test 0' }, { id: 1, name: 'Test 1' }], + selectedItemKey: 1, + useSelectMode: true, + opened: true + }); + + eventsEngine.trigger(this.list.itemElements().eq(0), 'dxclick'); + assert.strictEqual(getActionButton(this.dropDownButton).text(), 'Test 0', 'action button text is correct'); + }); + QUnit.test('custom item should be redefined after selection if useSelectMode is changed to true at runtime', function(assert) { this.dropDownButton.option({ useSelectMode: false, @@ -827,6 +887,45 @@ QUnit.module('common use cases', { assert.strictEqual(selectionChangeHandler.callCount, 2, 'onSelectionChange is raised'); }); + QUnit.test('click on item should raise selectionChanged - subscription by "on" method', function(assert) { + const selectionChangeHandler = sinon.spy(); + const items = [{ + id: 1, name: 'a' + }, { + id: 2, name: 'b' + }]; + + this.dropDownButton.option({ + items, + useSelectMode: true + }); + + this.dropDownButton.on('selectionChanged', selectionChangeHandler); + + const firstListItems = getList(this.dropDownButton).itemElements(); + eventsEngine.trigger(firstListItems[0], 'dxclick'); + + assert.strictEqual(selectionChangeHandler.callCount, 1, 'selectionChanged is raised'); + }); + + QUnit.test('click on item should change selectedItem option', function(assert) { + const items = [{ + id: 1, name: 'a' + }, { + id: 2, name: 'b' + }]; + + this.dropDownButton.option({ + items, + useSelectMode: true + }); + + const firstListItems = getList(this.dropDownButton).itemElements(); + eventsEngine.trigger(firstListItems[0], 'dxclick'); + + assert.strictEqual(this.dropDownButton.option('selectedItem'), items[0], 'selectedItem is correct'); + }); + QUnit.test('spindown secondary icon should not be rendered when showArrowIcon is false', function(assert) { this.dropDownButton.option({ splitButton: false, @@ -1018,6 +1117,19 @@ QUnit.module('items changing', { }); } }, () => { + QUnit.test('items option runtime change', function(assert) { + this.dropDownButton.option({ + items: [{ + id: 10, name: 'changed' + }], + deferRendering: false + }); + + const $firstItem = getList(this.dropDownButton).itemElements().eq(0); + + assert.strictEqual($firstItem.text(), 'changed', 'items has been changed'); + }); + QUnit.test('changing of items should load new selected item', function(assert) { this.dropDownButton.option({ selectedItemKey: 2 @@ -1201,6 +1313,29 @@ QUnit.module('events', {}, () => { assert.strictEqual($(e.itemElement).get(0), $item.get(0), 'itemElement is correct'); }); + QUnit.test('itemClick event - subscription using "on" method', function(assert) { + const handler = sinon.spy(); + const dropDownButton = new DropDownButton('#dropDownButton2', { + items: [1, 2, 3] + }); + + dropDownButton.on('itemClick', handler); + + dropDownButton.open(); + const $item = getList(dropDownButton).itemElements().eq(0); + + eventsEngine.trigger($item, 'dxclick'); + const e = handler.getCall(0).args[0]; + + assert.strictEqual(handler.callCount, 1, 'handler was called'); + assert.strictEqual(Object.keys(e).length, 5, 'event has 5 properties'); + assert.strictEqual(e.component, dropDownButton, 'component is correct'); + assert.strictEqual(e.element, dropDownButton.element(), 'element is correct'); + assert.strictEqual(e.event.type, 'dxclick', 'event is correct'); + assert.strictEqual(e.itemData, 1, 'itemData is correct'); + assert.strictEqual($(e.itemElement).get(0), $item.get(0), 'itemElement is correct'); + }); + QUnit.test('onItemClick event change', function(assert) { const handler = sinon.spy(); const dropDownButton = new DropDownButton('#dropDownButton2', { @@ -1216,6 +1351,55 @@ QUnit.module('events', {}, () => { assert.strictEqual(handler.callCount, 1, 'handler was called'); }); + QUnit.test('keyExpr option change', function(assert) { + const items = [{ + name: 'A', id: 1 + }, { + name: 'B', id: 2 + }]; + + const dropDownButton = new DropDownButton('#dropDownButton2', { + items, + keyExpr: 'name', + selectedItemKey: 'B', + useSelectMode: true, + displayExpr: 'name' + }); + + assert.strictEqual(dropDownButton.option('text'), 'B', 'value is correct'); + + dropDownButton.option('keyExpr', 'id'); + dropDownButton.option('selectedItemKey', 'A'); + assert.strictEqual(dropDownButton.option('text'), '', 'text is empty because keyExpt has been changed'); + + dropDownButton.option('selectedItemKey', 1); + assert.strictEqual(dropDownButton.option('text'), 'A', 'value is correct'); + }); + + QUnit.test('focusStateEnabled option change', function(assert) { + const dropDownButton = new DropDownButton('#dropDownButton2'); + + dropDownButton.option('focusStateEnabled', false); + + assert.strictEqual(dropDownButton.$element().attr('tabindex'), undefined, 'element is not focusable'); + }); + + QUnit.test('itemClick event change - subscription by "on" method', function(assert) { + const handler = sinon.spy(); + + const dropDownButton = new DropDownButton('#dropDownButton2', { + items: [1, 2, 3] + }); + + dropDownButton.open(); + dropDownButton.on('itemClick', handler); + + const $item = getList(dropDownButton).itemElements().eq(0); + eventsEngine.trigger($item, 'dxclick'); + + assert.strictEqual(handler.callCount, 1, 'handler was called'); + }); + QUnit.test('onButtonClick event', function(assert) { const handler = sinon.spy(); const dropDownButton = new DropDownButton('#dropDownButton2', { @@ -1252,6 +1436,21 @@ QUnit.module('events', {}, () => { assert.strictEqual(handler.callCount, 1, 'handler was called'); }); + QUnit.test('buttonClick - subscription using "on" method', function(assert) { + const handler = sinon.spy(); + const dropDownButton = new DropDownButton('#dropDownButton2', { + items: [1, 2, 3], + splitButton: false + }); + + dropDownButton.on('buttonClick', handler); + + const $actionButton = getActionButton(dropDownButton); + eventsEngine.trigger($actionButton, 'dxclick'); + + assert.strictEqual(handler.callCount, 1, 'handler was called'); + }); + QUnit.test('onButtonClick event change', function(assert) { const handler = sinon.spy(); const dropDownButton = new DropDownButton('#dropDownButton2', { @@ -1268,6 +1467,145 @@ QUnit.module('events', {}, () => { assert.strictEqual(handler.callCount, 1, 'handler was called'); }); + QUnit.test('selectedItemKey option change should raise selectionChanged event', function(assert) { + const handler = sinon.spy(); + const dropDownButton = new DropDownButton('#dropDownButton2', { + items: [1, 2, 3], + splitButton: true, + selectedItemKey: 2, + onSelectionChanged: handler + }); + + dropDownButton.option('selectedItemKey', 3); + + assert.strictEqual(handler.callCount, 1, 'selectionChanged has been raised'); + }); + + QUnit.test('selectedItemKey option change should raise selectionChanged event - subscription using "on" method', function(assert) { + const handler = sinon.spy(); + const dropDownButton = new DropDownButton('#dropDownButton2', { + items: [1, 2, 3], + splitButton: true, + selectedItemKey: 2 + }); + + dropDownButton.on('selectionChanged', handler); + dropDownButton.option('selectedItemKey', 3); + + assert.strictEqual(handler.callCount, 1, 'selectionChanged has been raised'); + }); + + QUnit.test('selectedItemKey option change should change selectedItem option', function(assert) { + const dropDownButton = new DropDownButton('#dropDownButton2', { + items: [1, 2, 3], + splitButton: true, + selectedItemKey: 2 + }); + + dropDownButton.option('selectedItemKey', 3); + + assert.strictEqual(dropDownButton.option('selectedItem'), 3, 'selectedItem is correct'); + }); + + QUnit.test('onContentReady should be fired after widget rendering and take into account Popup rendering', function(assert) { + const contentReadyHandler = sinon.spy(); + + const dropDownButton = new DropDownButton('#dropDownButton2', { + dataSource: { + load: sinon.stub().returns([1, 2, 3]), + byKey: sinon.stub().returns(1) + }, + deferRendering: true, + onContentReady: contentReadyHandler + }); + + assert.strictEqual(contentReadyHandler.callCount, 1, 'Widget is ready'); + dropDownButton.open(); + assert.strictEqual(contentReadyHandler.callCount, 3, 'Popup is ready, then List is ready'); + }); + + QUnit.test('onContentReady should be fired after widget rendering', function(assert) { + const contentReadyHandler = sinon.spy(); + + const dropDownButton = new DropDownButton('#dropDownButton2', { + dataSource: { + load: sinon.stub().returns([1, 2, 3]), + byKey: sinon.stub().returns(1) + }, + opened: true, + deferRendering: false, + onContentReady: contentReadyHandler + }); + + assert.strictEqual(contentReadyHandler.callCount, 2, 'Popup is ready, then List is ready'); + + dropDownButton.option('dataSource', ['first', 'second', 'third']); + assert.strictEqual(contentReadyHandler.callCount, 3, 'List is ready after updating Popup content'); + }); + + QUnit.test('onContentReady should be fired after widget rendering when subscription uses "on" method', function(assert) { + const contentReadyHandler = sinon.spy(); + + const dropDownButton = new DropDownButton('#dropDownButton2', { + dataSource: { + load: sinon.stub().returns([1, 2, 3]), + byKey: sinon.stub().returns(1) + }, + deferRendering: true + }); + + dropDownButton.on('contentReady', contentReadyHandler); + dropDownButton.open(); + assert.strictEqual(contentReadyHandler.callCount, 2, 'Popup is ready, then List is ready'); + + dropDownButton.option('dataSource', [1, 2, 3]); + assert.strictEqual(contentReadyHandler.callCount, 3, 'List is ready after updating Popup content'); + }); + + QUnit.test('onContentReady should be fired after widget with custom content template rendering', function(assert) { + const contentReadyHandler = sinon.spy(); + const firstTemplateHandler = sinon.stub().returns('Template 1'); + const secondTemplateHandler = sinon.stub().returns('Template 2'); + + const dropDownButton = new DropDownButton('#dropDownButton2', { + dataSource: { + load: sinon.stub().returns([1, 2, 3]), + byKey: sinon.stub().returns(1) + }, + dropDownContentTemplate: firstTemplateHandler, + deferRendering: false, + onContentReady: contentReadyHandler, + opened: true + }); + + assert.strictEqual(contentReadyHandler.callCount, 1, 'event is fired'); + + dropDownButton.option('dropDownContentTemplate', secondTemplateHandler); + assert.strictEqual(contentReadyHandler.callCount, 2, 'event is fired after template change'); + }); + + QUnit.test('onContentReady should be fired after widget with custom content template rendering - subscription uses "on" method', function(assert) { + const contentReadyHandler = sinon.spy(); + const firstTemplateHandler = sinon.stub().returns('Template 1'); + const secondTemplateHandler = sinon.stub().returns('Template 2'); + + const dropDownButton = new DropDownButton('#dropDownButton2', { + dataSource: { + load: sinon.stub().returns([1, 2, 3]), + byKey: sinon.stub().returns(1) + }, + dropDownContentTemplate: firstTemplateHandler, + deferRendering: true + }); + + dropDownButton.on('contentReady', contentReadyHandler); + dropDownButton.open(); + assert.strictEqual(contentReadyHandler.callCount, 1, 'event is fired'); + + dropDownButton.option('dropDownContentTemplate', secondTemplateHandler); + assert.strictEqual(contentReadyHandler.callCount, 2, 'event is fired after template change'); + }); + QUnit.test('onSelectionChanged event', function(assert) { const handler = sinon.spy(); const dropDownButton = new DropDownButton('#dropDownButton2', { @@ -1290,6 +1628,28 @@ QUnit.module('events', {}, () => { assert.strictEqual(e.item, 1, 'item is correct'); }); + QUnit.test('onSelectionChanged option runtime change', function(assert) { + const firstHandler = sinon.spy(); + const secondHandler = sinon.spy(); + const dropDownButton = new DropDownButton('#dropDownButton2', { + items: [1, 2, 3], + selectedItemKey: 2, + onSelectionChanged: firstHandler + }); + + dropDownButton.open(); + + const $firstItem = getList(dropDownButton).itemElements().eq(0); + eventsEngine.trigger($firstItem, 'dxclick'); + assert.strictEqual(firstHandler.callCount, 1, 'first handler was called'); + + dropDownButton.option('onSelectionChanged', secondHandler); + + const $secondItem = getList(dropDownButton).itemElements().eq(1); + eventsEngine.trigger($secondItem, 'dxclick'); + assert.strictEqual(secondHandler.callCount, 1, 'second handler was called'); + }); + QUnit.test('onSelectionChanged event with data expressions', function(assert) { const handler = sinon.spy(); const items = [{ id: 1, text: 'Item 1' }, { id: 2, text: 'Item 2' }]; @@ -1367,6 +1727,120 @@ QUnit.module('keyboard navigation', { assert.strictEqual(handler.callCount, 2, 'action button pressed twice'); }); + QUnit.testInActiveWindow('enter/space press should raise itemClick event when list item is focused', function(assert) { + const handler = sinon.spy(); + this.dropDownButton.option('onItemClick', handler); + + this.keyboard + .press('right') + .press('enter') + .press('down'); + + const listKeyboard = keyboardMock(getList(this.dropDownButton).element()); + + listKeyboard.press('enter'); + assert.strictEqual(handler.callCount, 1, 'itemClick has been raised'); + + listKeyboard + .press('down') + .press('space'); + assert.strictEqual(handler.callCount, 2, 'itemClick has been raised'); + }); + + QUnit.testInActiveWindow('enter/space press should raise itemClick event when list item is focused - subscription by "on" method', function(assert) { + const handler = sinon.spy(); + + this.dropDownButton.on('itemClick', handler); + + this.keyboard + .press('right') + .press('enter') + .press('down'); + + const listKeyboard = keyboardMock(getList(this.dropDownButton).element()); + + listKeyboard.press('enter'); + assert.strictEqual(handler.callCount, 1, 'itemClick has been raised'); + + listKeyboard + .press('down') + .press('space'); + assert.strictEqual(handler.callCount, 2, 'itemClick has been raised'); + }); + + QUnit.test('enter/space press should raise selectionChanged event when list item is focused', function(assert) { + const handler = sinon.spy(); + + this.dropDownButton.option('onSelectionChanged', handler); + + this.keyboard + .press('right') + .press('enter') + .press('down'); + + const listKeyboard = keyboardMock(getList(this.dropDownButton).element()); + + listKeyboard.press('enter'); + assert.strictEqual(handler.callCount, 1, 'selectionChanged is raised'); + + listKeyboard + .press('down') + .press('space'); + assert.strictEqual(handler.callCount, 2, 'selectionChanged has been raised'); + }); + + QUnit.test('enter/space press should change selectedItem option when list item is focused', function(assert) { + const items = this.dropDownButton.option('items'); + + this.keyboard + .press('right') + .press('enter') + .press('down'); + + const listKeyboard = keyboardMock(getList(this.dropDownButton).element()); + + listKeyboard.press('enter'); + + assert.strictEqual(this.dropDownButton.option('selectedItem'), items[0], 'selectedItem is correct'); + + listKeyboard + .press('down') + .press('space'); + assert.strictEqual(this.dropDownButton.option('selectedItem'), items[1], 'selectedItem is correct'); + }); + + QUnit.test('enter/space press should raise selectionChanged event when list item is focused - subscription using "on" method', function(assert) { + const handler = sinon.spy(); + + this.dropDownButton.on('selectionChanged', handler); + + this.keyboard + .press('right') + .press('enter') + .press('down'); + + const listKeyboard = keyboardMock(getList(this.dropDownButton).element()); + + listKeyboard.press('enter'); + assert.strictEqual(handler.callCount, 1, 'onSelectionChanged is raised'); + + listKeyboard + .press('down') + .press('space'); + assert.strictEqual(handler.callCount, 2, 'selectionChanged has been raised'); + }); + + QUnit.testInActiveWindow('enter/space press should rise buttonClick event when action button is focused - subscription using "on" method', function(assert) { + const handler = sinon.spy(); + this.dropDownButton.on('buttonClick', handler); + + this.keyboard.press('enter'); + assert.strictEqual(handler.callCount, 1, 'buttonClick event has been raised after enter press'); + + this.keyboard.press('space'); + assert.strictEqual(handler.callCount, 2, 'buttonClick event has been raised after space press'); + }); + QUnit.testInActiveWindow('toggle button should be clicked on enter or space', function(assert) { this.keyboard.press('right').press('enter'); @@ -1538,4 +2012,30 @@ QUnit.module('custom content template', {}, () => { assert.deepEqual(templateHandler.getCall(0).args[0], dropDownButton.getDataSource(), 'data is correct'); }); + + QUnit.test('itemTemplate option', function(assert) { + const items = [ + { id: 1, name: 'A' }, + { id: 2, name: 'B' } + ]; + + const dropDownButton = new DropDownButton('#dropDownButton2', { + items, + deferRendering: false, + itemTemplate: function(itemData) { + return $('
') + .text(`${ itemData.id }: ${ itemData.name }`); + } + }); + + let $listItems = getList(dropDownButton).itemElements(); + assert.strictEqual($listItems.eq(0).text(), '1: A', 'itemTemlate has changed item text'); + + dropDownButton.option('itemTemplate', function(itemData) { + return $('
') + .text(`#${ itemData.id }`); + }); + $listItems = getList(dropDownButton).itemElements(); + assert.strictEqual($listItems.eq(0).text(), '#1', 'itemTemlate has changed item text after option change'); + }); }); diff --git a/testing/tests/DevExpress.ui.widgets/fileManager.tests.js b/testing/tests/DevExpress.ui.widgets/fileManager.tests.js index d189d5908c26..c7d8554a1c0a 100644 --- a/testing/tests/DevExpress.ui.widgets/fileManager.tests.js +++ b/testing/tests/DevExpress.ui.widgets/fileManager.tests.js @@ -19,7 +19,6 @@ import './fileManagerParts/fileItemsController.tests.js'; import './fileManagerParts/common.tests.js'; -import './fileManagerParts/ajaxProvider.tests.js'; import './fileManagerParts/arrayProvider.tests.js'; import './fileManagerParts/remoteProvider.tests.js'; import './fileManagerParts/customProvider.tests.js'; diff --git a/testing/tests/DevExpress.ui.widgets/fileManagerParts/adaptivity.tests.js b/testing/tests/DevExpress.ui.widgets/fileManagerParts/adaptivity.tests.js index a737af97c644..a572c3151600 100644 --- a/testing/tests/DevExpress.ui.widgets/fileManagerParts/adaptivity.tests.js +++ b/testing/tests/DevExpress.ui.widgets/fileManagerParts/adaptivity.tests.js @@ -38,12 +38,12 @@ const moduleConfig = { this.$element = $('#fileManager') .css('width', 350) .dxFileManager({ - fileProvider: createTestFileSystem(), + fileSystemProvider: createTestFileSystem(), permissions: { create: true, copy: true, move: true, - remove: true, + delete: true, rename: true, upload: true } diff --git a/testing/tests/DevExpress.ui.widgets/fileManagerParts/ajaxProvider.tests.js b/testing/tests/DevExpress.ui.widgets/fileManagerParts/ajaxProvider.tests.js deleted file mode 100644 index 58e537325ef3..000000000000 --- a/testing/tests/DevExpress.ui.widgets/fileManagerParts/ajaxProvider.tests.js +++ /dev/null @@ -1,52 +0,0 @@ -const { test } = QUnit; -import ajaxMock from '../../../helpers/ajaxMock.js'; - -import AjaxFileProvider from 'ui/file_manager/file_provider/ajax'; - -const fileItems = [ - { - name: 'F1', - isDirectory: true, - children: [ { name: 'File1.1.txt' } ] - }, - { - name: 'F2', - isDirectory: true - } -]; - -const moduleConfig = { - beforeEach: function() { - this.options = { - url: 'url-to-js-file' - }; - this.provider = new AjaxFileProvider(this.options); - }, - - afterEach: function() { - ajaxMock.clear(); - } -}; - -QUnit.module('Ajax File Provider', moduleConfig, () => { - - test('get directory file items', function(assert) { - const done = assert.async(); - - ajaxMock.setup({ - url: this.options.url, - responseText: fileItems - }); - - this.provider.getItems('') - .done(dirs => { - assert.equal(dirs.length, 2); - assert.equal(dirs[0].name, 'F1'); - assert.ok(dirs[0].isDirectory); - assert.equal(dirs[1].name, 'F2'); - assert.ok(dirs[1].isDirectory); - done(); - }); - }); - -}); diff --git a/testing/tests/DevExpress.ui.widgets/fileManagerParts/arrayProvider.tests.js b/testing/tests/DevExpress.ui.widgets/fileManagerParts/arrayProvider.tests.js index 71427d1954fc..164a40d992c8 100644 --- a/testing/tests/DevExpress.ui.widgets/fileManagerParts/arrayProvider.tests.js +++ b/testing/tests/DevExpress.ui.widgets/fileManagerParts/arrayProvider.tests.js @@ -1,9 +1,9 @@ const { test } = QUnit; import 'ui/file_manager'; -import ArrayFileProvider from 'ui/file_manager/file_provider/array'; -import { FileManagerRootItem } from 'ui/file_manager/file_provider/file_provider'; -import { ErrorCode } from 'ui/file_manager/ui.file_manager.common'; +import ObjectFileSystemProvider from 'file_management/object_provider'; +import FileSystemItem from 'file_management/file_system_item'; +import ErrorCode from 'file_management/errors'; import { fileSaver } from 'exporter/file_saver'; import { createUploaderFiles, createUploadInfo } from '../../../helpers/fileManagerHelpers.js'; @@ -49,7 +49,9 @@ const moduleConfig = { ] }; - this.provider = new ArrayFileProvider(this.options); + this.provider = new ObjectFileSystemProvider(this.options); + + this.rootItem = new FileSystemItem('', true); sinon.stub(fileSaver, 'saveAs', (fileName, format, data) => { if(fileSaver._onTestSaveAs) { @@ -68,30 +70,42 @@ const moduleConfig = { QUnit.module('Array File Provider', moduleConfig, () => { test('get directory file items', function(assert) { - let items = this.provider.getItems(); - assert.equal(items.length, 2); - assert.equal(items[0].name, 'F1'); - assert.ok(items[0].hasSubDirs); - assert.equal(items[1].name, 'F2'); - assert.notOk(items[1].hasSubDirs); - - let pathInfo = [ { key: 'F1', name: 'F1' } ]; - items = this.provider.getItems(pathInfo); - assert.equal(items.length, 3); - assert.equal(items[0].name, 'F1.1'); - assert.notOk(items[0].hasSubDirs); - assert.equal(items[1].name, 'F1.2'); - assert.notOk(items[1].hasSubDirs); - assert.equal(items[2].name, 'F1.3'); - assert.ok(items[2].hasSubDirs); - - pathInfo = [ - { key: 'F1', name: 'F1' }, - { key: 'F1/F1.2', name: 'F1.2' } - ]; - items = this.provider.getItems(pathInfo); - assert.equal(items.length, 1); - assert.equal(items[0].name, 'File1.2.txt'); + const done1 = assert.async(); + const done2 = assert.async(); + const done3 = assert.async(); + + const dir1 = new FileSystemItem('F1', true); + const dir2 = new FileSystemItem('F1/F1.2', true); + + this.provider.getItems(this.rootItem) + .done(items => { + done1(); + + assert.equal(items.length, 2); + assert.equal(items[0].name, 'F1'); + assert.ok(items[0].hasSubDirs); + assert.equal(items[1].name, 'F2'); + assert.notOk(items[1].hasSubDirs); + }) + .then(() => this.provider.getItems(dir1)) + .done(items => { + done2(); + + assert.equal(items.length, 3); + assert.equal(items[0].name, 'F1.1'); + assert.notOk(items[0].hasSubDirs); + assert.equal(items[1].name, 'F1.2'); + assert.notOk(items[1].hasSubDirs); + assert.equal(items[2].name, 'F1.3'); + assert.ok(items[2].hasSubDirs); + }) + .then(() => this.provider.getItems(dir2)) + .done(items => { + done3(); + + assert.equal(items.length, 1); + assert.equal(items[0].name, 'File1.2.txt'); + }); }); test('getItems method generates ids for items with duplicate names', function(assert) { @@ -104,97 +118,200 @@ QUnit.module('Array File Provider', moduleConfig, () => { const testResult = [false, false, true, false, false, true]; this.options.data.push(...data); - const items = this.provider.getItems(); - assert.strictEqual(items.length, testResult.length, 'item count is correct'); - - testResult.forEach((generated, index) => { - const item = items[index]; - const obj = this.options.data[index]; - - assert.strictEqual(item.name, obj.name, 'item name valid'); - - if(generated) { - assert.notStrictEqual(item.key, obj.name, 'item has non default key'); - assert.ok(obj.__KEY__, 'data object key is generated'); - assert.ok(obj.__KEY__.length > 10, 'generated key string is big'); - } else { - assert.strictEqual(item.key, obj.name, 'item has default key'); - assert.notOk(obj.__KEY__, 'data object key not specified'); - } - }); + + const done = assert.async(); + + this.provider.getItems(this.rootItem) + .done(items => { + done(); + assert.strictEqual(items.length, testResult.length, 'item count is correct'); + + testResult.forEach((generated, index) => { + const item = items[index]; + const obj = this.options.data[index]; + + assert.strictEqual(item.name, obj.name, 'item name valid'); + + if(generated) { + assert.notStrictEqual(item.key, obj.name, 'item has non default key'); + assert.ok(obj.__KEY__, 'data object key is generated'); + assert.ok(obj.__KEY__.length > 10, 'generated key string is big'); + } else { + assert.strictEqual(item.key, obj.name, 'item has default key'); + assert.notOk(obj.__KEY__, 'data object key not specified'); + } + }); + + }); }); test('move directory', function(assert) { - const pathInfo = [ { key: 'F2', name: 'F2' } ]; + const dir = new FileSystemItem('F2', true); + + let items = null; + let subItemsCount = -1; + const done = assert.async(5); - let items = this.provider.getItems(); - const subItemsCount = this.provider.getItems(pathInfo).length; - this.provider.moveItems([ items[0] ], items[1]); + this.provider.getItems(this.rootItem) + .then(result => { + done(); + + items = result; + return this.provider.getItems(dir); + }) + .then(subItems => { + done(); + + subItemsCount = subItems.length; + + const deferreds = this.provider.moveItems([ items[0] ], items[1]); + assert.strictEqual(deferreds.length, 1, 'deferreds same count as the items'); + return deferreds[0]; + }) + .then(result => { + done(); + + assert.strictEqual(result, undefined, 'resolved with no result'); + + return this.provider.getItems(this.rootItem); + }) + .then(result => { + done(); + + items = result; + return this.provider.getItems(dir); + }) + .done(subItems => { + done(); - items = this.provider.getItems(); - const newSubItemsCount = this.provider.getItems(pathInfo).length; - assert.equal(items.length, 1); - assert.ok(items[0].hasSubDirs); - assert.strictEqual(newSubItemsCount, subItemsCount + 1, 'sub item count has increased'); + assert.equal(items.length, 1); + assert.ok(items[0].hasSubDirs); + assert.strictEqual(subItems.length, subItemsCount + 1, 'sub item count has increased'); + }); }); test('copy directory', function(assert) { - const pathInfo = [ { key: 'F2', name: 'F2' } ]; + const dir = new FileSystemItem('F2', true); + + let items = null; + let subItemsCount = -1; + const done = assert.async(5); + + this.provider.getItems(this.rootItem) + .then(result => { + done(); + + items = result; + return this.provider.getItems(dir); + }) + .then(subItems => { + done(); + + subItemsCount = subItems.length; + + const deferreds = this.provider.copyItems([ items[0] ], items[1]); + assert.strictEqual(deferreds.length, 1, 'deferreds same count as the items'); + return deferreds[0]; + }) + .then(result => { + done(); + + assert.strictEqual(result, undefined, 'resolved with no result'); - let items = this.provider.getItems(); - const subItemsCount = this.provider.getItems(pathInfo).length; - this.provider.copyItems([ items[0] ], items[1]); + return this.provider.getItems(this.rootItem); + }) + .then(result => { + done(); + + items = result; + assert.equal(items.length, 2, 'source dir preserved'); + assert.ok(items[0].hasSubDirs, 'source dir items preserved'); - items = this.provider.getItems(); - assert.equal(items.length, 2, 'source dir preserved'); - assert.ok(items[0].hasSubDirs, 'source dir items preserved'); + return this.provider.getItems(dir); + }) + .done(subItems => { + done(); - const newSubItemsCount = this.provider.getItems(pathInfo).length; - assert.strictEqual(newSubItemsCount, subItemsCount + 1, 'sub item count has increased'); + assert.strictEqual(subItems.length, subItemsCount + 1, 'sub item count has increased'); + }); }); test('copy directory to root directory does not change root\'s hasSubDir property', function(assert) { - const root = new FileManagerRootItem(); - const pathInfo = [ { key: 'F1', name: 'F1' } ]; + const root = new FileSystemItem(); + const dir = new FileSystemItem('F1', true); assert.strictEqual(root.hasSubDirs, undefined, 'root hasSubDirs property is undefined'); - const itemCount = this.provider.getItems().length; - const items = this.provider.getItems(pathInfo); + let items = null; + let itemCount = -1; + const done = assert.async(4); - this.provider.copyItems([ items[1] ], root); - const newItemCount = this.provider.getItems().length; + this.provider.getItems(this.rootItem) + .then(result => { + done(); - assert.strictEqual(root.hasSubDirs, undefined, 'root hasSubDirs property is undefined'); - assert.strictEqual(newItemCount, itemCount + 1, 'sub item count has increased'); + itemCount = result.length; + return this.provider.getItems(dir); + }) + .then(result => { + done(); + + items = result; + + const deferreds = this.provider.copyItems([ items[1] ], root); + return deferreds[0]; + }) + .then(() => { + done(); + + return this.provider.getItems(this.rootItem); + }) + .then(result => { + done(); + + assert.strictEqual(root.hasSubDirs, undefined, 'root hasSubDirs property is undefined'); + assert.strictEqual(result.length, itemCount + 1, 'sub item count has increased'); + }); }); test('throw error when try moving folder with incorrect parameters', function(assert) { - let errorCount = 0; - let lastErrorId = -1; - const items = this.provider.getItems(); - - try { - this.provider.moveItems([ items[0] ], items[0]); - } catch(e) { - errorCount++; - lastErrorId = e.errorId; - } - assert.equal(items[0].name, 'F1'); - assert.equal(errorCount, 1); - assert.equal(lastErrorId, ErrorCode.Other); - - const pathInfo = [ { key: 'F1', name: 'F1' } ]; - const subFolders = this.provider.getItems(pathInfo); - try { - this.provider.moveItems([ subFolders[0] ], subFolders[0]); - } catch(e) { - errorCount++; - lastErrorId = e.errorId; - } - assert.equal(subFolders[0].name, 'F1.1'); - assert.equal(errorCount, 2); - assert.equal(lastErrorId, ErrorCode.Other); + let items = null; + let subFolders = null; + + const done = assert.async(4); + + this.provider.getItems(this.rootItem) + .then(result => { + done(); + + items = result; + + const deferreds = this.provider.moveItems([ items[0] ], items[0]); + return deferreds[0]; + }) + .then(null, error => { + done(); + + assert.equal(items[0].name, 'F1'); + assert.equal(error.errorId, ErrorCode.Other); + + const dir = new FileSystemItem('F1', true); + return this.provider.getItems(dir); + }) + .then(result => { + done(); + + subFolders = result; + + const deferreds = this.provider.moveItems([ subFolders[0] ], subFolders[0]); + return deferreds[0]; + }) + .then(null, error => { + done(); + + assert.equal(subFolders[0].name, 'F1.1'); + assert.equal(error.errorId, ErrorCode.Other); + }); }); test('throw error when try moving directory into it\'s subdirectory', function(assert) { @@ -206,155 +323,233 @@ QUnit.module('Array File Provider', moduleConfig, () => { isDirectory: true }); - let errorCount = 0; - let lastErrorId = -1; - const items = this.provider.getItems(); + let items = null; + let subFolders = null; + + const done = assert.async(4); - const pathInfo = [ { key: 1, name: 'F1' } ]; - const subFolders = this.provider.getItems(pathInfo); + this.provider.getItems(this.rootItem) + .then(result => { + done(); - assert.equal(items[0].name, 'F1', 'folder name is correct'); - assert.equal(subFolders[0].name, 'F1.1', 'subfolder name is correct'); + items = result; - try { - this.provider.moveItems([ items[0] ], subFolders[0]); - } catch(e) { - errorCount++; - lastErrorId = e.errorId; - } + const dir = new FileSystemItem('F1', true, [ 1 ]); + return this.provider.getItems(dir); + }) + .then(result => { + done(); - assert.equal(errorCount, 1, 'error is raised'); - assert.equal(lastErrorId, ErrorCode.Other, 'error code is correct'); + subFolders = result; + assert.equal(items[0].name, 'F1', 'folder name is correct'); + assert.equal(subFolders[0].name, 'F1.1', 'subfolder name is correct'); + + const deferreds = this.provider.moveItems([ items[0] ], subFolders[0]); + return deferreds[0]; + }) + .then(null, error => { + done(); - errorCount = 0; - try { - this.provider.moveItems([ items[2] ], subFolders[0]); - } catch(e) { - errorCount++; - } + assert.equal(error.errorId, ErrorCode.Other, 'error code is correct'); - assert.equal(errorCount, 0, 'error is not raised'); + const deferreds = this.provider.moveItems([ items[2] ], subFolders[0]); + return deferreds[0]; + }) + .then(result => { + done(); + + assert.strictEqual(result, undefined, 'resolved with no result'); + }); }); test('throw error when try copying folder with incorrect parameters', function(assert) { - let errorCount = 0; - let lastErrorId = -1; - const folders = this.provider.getItems(); - - try { - this.provider.copyItems([ folders[0] ], folders[0]); - } catch(e) { - errorCount++; - lastErrorId = e.errorId; - } - assert.equal(folders[0].name, 'F1'); - assert.equal(errorCount, 1); - assert.equal(lastErrorId, ErrorCode.Other); - - const pathInfo = [ { key: 'F1', name: 'F1' } ]; - const subFolders = this.provider.getItems(pathInfo); - try { - this.provider.copyItems([ subFolders[0] ], subFolders[0]); - } catch(e) { - errorCount++; - lastErrorId = e.errorId; - } - assert.equal(subFolders[0].name, 'F1.1'); - assert.equal(errorCount, 2); - assert.equal(lastErrorId, ErrorCode.Other); + let items = null; + let subFolders = null; + + const done = assert.async(4); + + this.provider.getItems(this.rootItem) + .then(result => { + done(); + + items = result; + + const deferreds = this.provider.copyItems([ items[0] ], items[0]); + return deferreds[0]; + }) + .then(null, error => { + done(); + + assert.equal(items[0].name, 'F1'); + assert.equal(error.errorId, ErrorCode.Other); + + const dir = new FileSystemItem('F1', true); + return this.provider.getItems(dir); + }) + .then(result => { + done(); + + subFolders = result; + + const deferreds = this.provider.copyItems([ subFolders[0] ], subFolders[0]); + return deferreds[0]; + }) + .then(null, error => { + done(); + + assert.equal(subFolders[0].name, 'F1.1'); + assert.equal(error.errorId, ErrorCode.Other); + }); }); test('create new folder with existing name', function(assert) { - this.provider.createFolder(new FileManagerRootItem(), 'F1'); - - const dirs = this.provider.getItems(); - assert.equal(dirs[0].name, 'F1'); - assert.equal(dirs[0].key, 'F1'); - assert.equal(dirs[1].name, 'F2'); - assert.equal(dirs[1].key, 'F2'); - assert.equal(dirs[2].name, 'F1'); - assert.notEqual(dirs[2].key, 'F1'); - assert.ok(dirs[2].key.length > 1); + const done = assert.async(2); + + const root = new FileSystemItem('', true); + this.provider.createDirectory(root, 'F1') + .then(result => { + done(); + + assert.strictEqual(result, undefined, 'resolved with no result'); + return this.provider.getItems(this.rootItem); + }) + .then(dirs => { + done(); + + assert.equal(dirs[0].name, 'F1'); + assert.equal(dirs[0].key, 'F1'); + assert.equal(dirs[1].name, 'F2'); + assert.equal(dirs[1].key, 'F2'); + assert.equal(dirs[2].name, 'F1'); + assert.notEqual(dirs[2].key, 'F1'); + assert.ok(dirs[2].key.length > 1); + }); }); test('throw error on creating new directory in unexisting directory', function(assert) { - let errorCount = 0; - let errorId = 0; - - const f1Dir = this.provider.getItems()[0]; - this.options.data.splice(0, this.options.data.length); - - try { - this.provider.createFolder(f1Dir, 'NewDir'); - } catch(e) { - errorCount++; - errorId = e.errorId; - } - assert.equal(errorCount, 1); - assert.equal(errorId, ErrorCode.DirectoryNotFound); + const done = assert.async(2); + + this.provider.getItems(this.rootItem) + .then(([ f1Dir ]) => { + done(); + + this.options.data.splice(0, this.options.data.length); + return this.provider.createDirectory(f1Dir, 'NewDir'); + }) + .then(null, ({ errorId }) => { + done(); + + assert.equal(errorId, ErrorCode.DirectoryNotFound); + }); }); test('rename file item with existing name', function(assert) { - const fileItems = this.provider.getItems(); - this.provider.renameItem(fileItems[0], 'F2'); + let fileItems = null; + + const done = assert.async(2); + + this.provider.getItems(this.rootItem) + .then(result => { + done(); + + fileItems = result; + return this.provider.renameItem(fileItems[0], 'F2'); + }) + .then(result => { + done(); + + assert.strictEqual(result, undefined, 'resolved with no result'); - assert.equal(fileItems[0].name, 'F2'); - assert.notEqual(fileItems[0].key, fileItems[1].key); + assert.equal(fileItems[0].name, 'F2'); + assert.notEqual(fileItems[0].key, fileItems[1].key); - assert.equal(fileItems[1].name, 'F2'); - assert.equal(fileItems[1].key, 'F2'); + assert.equal(fileItems[1].name, 'F2'); + assert.equal(fileItems[1].key, 'F2'); + }); }); test('delete directory', function(assert) { - let fileItems = this.provider.getItems(); - assert.equal(fileItems[0].name, 'F1'); - assert.equal(fileItems[1].name, 'F2'); - assert.equal(fileItems.length, 2); - - this.provider.deleteItems([ fileItems[0] ]); - fileItems = this.provider.getItems(); - assert.equal(fileItems[0].name, 'F2'); - assert.equal(fileItems.length, 1); + let fileItems = null; + + const done = assert.async(3); + + this.provider.getItems(this.rootItem) + .then(result => { + done(); + + fileItems = result; + assert.equal(fileItems[0].name, 'F1'); + assert.equal(fileItems[1].name, 'F2'); + assert.equal(fileItems.length, 2); + + const deferreds = this.provider.deleteItems([ fileItems[0] ]); + assert.strictEqual(deferreds.length, 1, 'deferreds count is same as the items count'); + return deferreds[0]; + }) + .then(result => { + done(); + + assert.strictEqual(result, undefined, 'resolved with no result'); + return this.provider.getItems(this.rootItem); + }) + .then(result => { + done(); + + fileItems = result; + assert.equal(fileItems[0].name, 'F2'); + assert.equal(fileItems.length, 1); + }); }); test('throw exception if remove unexisting directory', function(assert) { - let errorCount = 0; - let errorId = 0; - - const f1Dir = this.provider.getItems()[0]; - this.options.data.splice(0, this.options.data.length); - - try { - this.provider.deleteItems([ f1Dir ]); - } catch(e) { - errorCount++; - errorId = e.errorId; - } - assert.equal(errorCount, 1); - assert.equal(errorId, ErrorCode.DirectoryNotFound); + const done = assert.async(2); + + this.provider.getItems(this.rootItem) + .then(([ f1Dir ]) => { + done(); + + this.options.data.splice(0, this.options.data.length); + const deferreds = this.provider.deleteItems([ f1Dir ]); + return deferreds[0]; + }) + .then(null, ({ errorId }) => { + done(); + + assert.equal(errorId, ErrorCode.DirectoryNotFound); + }); }); test('upload file', function(assert) { - const done1 = assert.async(); - const done2 = assert.async(); + const done = assert.async(4); - const dir = new FileManagerRootItem(); - const initialCount = this.provider.getItems().length; + const dir = new FileSystemItem('', true); + let initialCount = -1; const file = createUploaderFiles(1)[0]; let uploadInfo = createUploadInfo(file); - this.provider.uploadFileChunk(file, uploadInfo, dir) + this.provider.getItems(this.rootItem) + .then(items => { + done(); + + initialCount = items.length; + return this.provider.uploadFileChunk(file, uploadInfo, dir); + }) .then(() => { - done1(); + done(); uploadInfo = createUploadInfo(file, 1, uploadInfo.customData); return this.provider.uploadFileChunk(file, uploadInfo, dir); }) - .then(() => { - done2(); + .then(result => { + done(); + + assert.strictEqual(result, undefined, 'resolved with no result'); + return this.provider.getItems(this.rootItem); + }) + .then(items => { + done(); - const items = this.provider.getItems(); const uploadedFile = items.filter(item => item.name === file.name && !item.isDirectory)[0]; assert.strictEqual(items.length, initialCount + 1, 'item count increased'); @@ -365,7 +560,9 @@ QUnit.module('Array File Provider', moduleConfig, () => { test('download single file', function(assert) { const content = 'Test content 1'; - const done = assert.async(); + const done = assert.async(2); + + let file = null; fileSaver._onTestSaveAs = (fileName, format, data) => { done(); @@ -373,19 +570,21 @@ QUnit.module('Array File Provider', moduleConfig, () => { assert.strictEqual(data.size, content.length, 'file size is correct'); }; - const pathInfo = [ - { key: 'F1', name: 'F1' }, - { key: 'F1/F1.2', name: 'F1.2' } - ]; - const file = this.provider.getItems(pathInfo)[0]; + const dir = new FileSystemItem('F1/F1.2', true); - file.dataItem.content = window.btoa(content); + this.provider.getItems(dir) + .then(([ file1 ]) => { + done(); - this.provider.downloadItems([ file ]); + file = file1; + file.dataItem.content = window.btoa(content); + + this.provider.downloadItems([ file ]); + }); }); test('download multiple files', function(assert) { - const done = assert.async(); + const done = assert.async(2); fileSaver._onTestSaveAs = (fileName, format, data) => { done(); @@ -398,15 +597,16 @@ QUnit.module('Array File Provider', moduleConfig, () => { content: window.btoa('Test content 2') }); - const pathInfo = [ - { key: 'F1', name: 'F1' }, - { key: 'F1/F1.2', name: 'F1.2' } - ]; - const files = this.provider.getItems(pathInfo); + const dir = new FileSystemItem('F1/F1.2', true); - files[0].dataItem.content = window.btoa('Test content 1'); + this.provider.getItems(dir) + .then(files => { + done(); - this.provider.downloadItems(files); + files[0].dataItem.content = window.btoa('Test content 1'); + + this.provider.downloadItems(files); + }); }); }); diff --git a/testing/tests/DevExpress.ui.widgets/fileManagerParts/common.tests.js b/testing/tests/DevExpress.ui.widgets/fileManagerParts/common.tests.js index 9d14e09437af..14f8d3e2ea55 100644 --- a/testing/tests/DevExpress.ui.widgets/fileManagerParts/common.tests.js +++ b/testing/tests/DevExpress.ui.widgets/fileManagerParts/common.tests.js @@ -1,20 +1,8 @@ const { test } = QUnit; -import { getPathParts, getEscapedFileName } from 'ui/file_manager/ui.file_manager.utils'; +import { getPathParts, getEscapedFileName } from 'file_management/utils'; +import FileSystemItem from 'file_management/file_system_item'; -const moduleConfig = { - - beforeEach: function() { - this.clock = sinon.useFakeTimers(); - this.clock.tick(400); - }, - - afterEach: function() { - this.clock.restore(); - } - -}; - -QUnit.module('Commands', moduleConfig, () => { +QUnit.module('Common tests', () => { test('getPathParts() function must correctly separate path string', function(assert) { const testData = { 'Files/Documents': ['Files', 'Documents'], @@ -57,4 +45,36 @@ QUnit.module('Commands', moduleConfig, () => { } }); + test('create FileSystemItem by public constructor', function(assert) { + const testData = { + '1': { + path: 'folder1', + isDir: true, + name: 'folder1', + key: 'folder1', + pathInfo: [] + }, + '2': { + path: 'folder1/file1', + isDir: false, + pathKeys: [ '7', '11' ], + name: 'file1', + key: '11', + pathInfo: [ { key: '7', name: 'folder1' }] + } + }; + + for(const key in testData) { + const testCase = testData[key]; + + const item = new FileSystemItem(testCase.path, testCase.isDir, testCase.pathKeys); + + assert.strictEqual(item.name, testCase.name, `${key}: name correct`); + assert.strictEqual(item.key, testCase.key, `${key}: key correct`); + assert.strictEqual(item.isDirectory, testCase.isDir, `${key}: isDirectory correct`); + assert.strictEqual(item.relativeName, testCase.path, `${key}: relativeName correct`); + assert.deepEqual(item.pathInfo, testCase.pathInfo, `${key}: pathInfo correct`); + } + }); + }); diff --git a/testing/tests/DevExpress.ui.widgets/fileManagerParts/contextMenu.tests.js b/testing/tests/DevExpress.ui.widgets/fileManagerParts/contextMenu.tests.js index 45bd334eece0..74fecdd2d6b5 100644 --- a/testing/tests/DevExpress.ui.widgets/fileManagerParts/contextMenu.tests.js +++ b/testing/tests/DevExpress.ui.widgets/fileManagerParts/contextMenu.tests.js @@ -14,7 +14,7 @@ const moduleConfig = { fx.off = true; this.$element = $('#fileManager').dxFileManager({ - fileProvider: fileSystem, + fileSystemProvider: fileSystem, itemView: { showFolders: false }, @@ -22,7 +22,7 @@ const moduleConfig = { create: true, copy: true, move: true, - remove: true, + delete: true, rename: true, upload: true } diff --git a/testing/tests/DevExpress.ui.widgets/fileManagerParts/customProvider.tests.js b/testing/tests/DevExpress.ui.widgets/fileManagerParts/customProvider.tests.js index fa24b3bda36d..c0c494b2ecb0 100644 --- a/testing/tests/DevExpress.ui.widgets/fileManagerParts/customProvider.tests.js +++ b/testing/tests/DevExpress.ui.widgets/fileManagerParts/customProvider.tests.js @@ -1,10 +1,11 @@ -import { FileManagerItem } from 'ui/file_manager/file_provider/file_provider'; -import CustomFileProvider from 'ui/file_manager/file_provider/custom'; +import { when } from 'core/utils/deferred'; +import FileSystemItem from 'file_management/file_system_item'; +import CustomFileSystemProvider from 'file_management/custom_provider'; import { createSampleFileItems } from '../../../helpers/fileManagerHelpers.js'; const { test } = QUnit; -const { filesPathInfo, itemData, fileManagerItems } = createSampleFileItems(); +const { filesPathInfo, itemData, fileSystemItems } = createSampleFileItems(); const moduleConfig = { @@ -17,11 +18,10 @@ const moduleConfig = { moveItem: sinon.spy((item, destinationDir) => `moved ${item.name}`), copyItem: sinon.spy((item, destinationDir) => `copied ${item.name}`), uploadFileChunk: sinon.spy((fileData, chunksInfo, destinationDir) => 'uploaded'), - abortFileUpload: sinon.spy((fileData, chunksInfo, destinationDir) => 'aborted'), - uploadChunkSize: 1000 + abortFileUpload: sinon.spy((fileData, chunksInfo, destinationDir) => 'aborted') }; - this.provider = new CustomFileProvider(this.options); + this.provider = new CustomFileSystemProvider(this.options); } }; @@ -31,113 +31,159 @@ QUnit.module('Custom file provider', moduleConfig, () => { test('get directory file items', function(assert) { const done = assert.async(); - this.provider.getItems(filesPathInfo) + const filesDir = new FileSystemItem('Root/Files', true); + + this.provider.getItems(filesDir) .done(items => { - assert.deepEqual(items, fileManagerItems, 'items acquired'); + assert.deepEqual(items, fileSystemItems, 'items acquired'); assert.strictEqual(this.options.getItems.callCount, 1, 'getItems called once'); - assert.deepEqual(this.options.getItems.args[0][0], filesPathInfo, 'getItems arguments are valid'); + assert.deepEqual(this.options.getItems.args[0][0], filesDir, 'getItems arguments are valid'); done(); }); }); test('rename item', function(assert) { - const item = new FileManagerItem(filesPathInfo, 'Documents'); - const result = this.provider.renameItem(item, 'Test 1'); + const done = assert.async(); + + const item = new FileSystemItem(filesPathInfo, 'Documents'); - assert.strictEqual(result, 'renamed', 'result acquired'); - assert.strictEqual(this.options.renameItem.callCount, 1, 'renameItem called once'); - assert.deepEqual(this.options.renameItem.args[0][0], item, 'renameItem arguments are valid'); - assert.deepEqual(this.options.renameItem.args[0][1], 'Test 1', 'renameItem arguments are valid'); + this.provider.renameItem(item, 'Test 1') + .done(result => { + done(); + + assert.strictEqual(result, undefined, 'resolved with no result'); + assert.strictEqual(this.options.renameItem.callCount, 1, 'renameItem called once'); + assert.deepEqual(this.options.renameItem.args[0][0], item, 'renameItem arguments are valid'); + assert.deepEqual(this.options.renameItem.args[0][1], 'Test 1', 'renameItem arguments are valid'); + }); }); test('create directory', function(assert) { - const parentDir = new FileManagerItem(filesPathInfo, 'Documents'); - const result = this.provider.createFolder(parentDir, 'Test 1'); + const done = assert.async(); + + const parentDir = new FileSystemItem(filesPathInfo, 'Documents'); + this.provider.createDirectory(parentDir, 'Test 1') + .done(result => { + done(); - assert.strictEqual(result, 'created', 'result acquired'); - assert.strictEqual(this.options.createDirectory.callCount, 1, 'createDirectory called once'); - assert.deepEqual(this.options.createDirectory.args[0][0], parentDir, 'createDirectory arguments are valid'); - assert.deepEqual(this.options.createDirectory.args[0][1], 'Test 1', 'createDirectory arguments are valid'); + assert.strictEqual(result, undefined, 'resolved with no result'); + assert.strictEqual(this.options.createDirectory.callCount, 1, 'createDirectory called once'); + assert.deepEqual(this.options.createDirectory.args[0][0], parentDir, 'createDirectory arguments are valid'); + assert.deepEqual(this.options.createDirectory.args[0][1], 'Test 1', 'createDirectory arguments are valid'); + }); }); test('delete items', function(assert) { + const done = assert.async(); + const items = [ - new FileManagerItem(filesPathInfo, 'Documents'), - new FileManagerItem(filesPathInfo, 'Article.txt') + new FileSystemItem(filesPathInfo, 'Documents'), + new FileSystemItem(filesPathInfo, 'Article.txt') ]; - const result = this.provider.deleteItems(items); - assert.deepEqual(result, [ 'deleted Documents', 'deleted Article.txt' ], 'result acquired'); - assert.strictEqual(this.options.deleteItem.callCount, 2, 'deleteItem called one time for each item'); - assert.deepEqual(this.options.deleteItem.args[0][0], items[0], 'deleteItem arguments are valid'); - assert.deepEqual(this.options.deleteItem.args[1][0], items[1], 'deleteItem arguments are valid'); + const deferreds = this.provider.deleteItems(items); + assert.strictEqual(deferreds.length, 2, 'result contains deferrred for each item'); + + when.apply(null, deferreds) + .done((res1, res2) => { + done(); + + assert.strictEqual(res1, undefined, 'resolved with no result'); + assert.strictEqual(res2, undefined, 'resolved with no result'); + assert.strictEqual(this.options.deleteItem.callCount, 2, 'deleteItem called one time for each item'); + assert.deepEqual(this.options.deleteItem.args[0][0], items[0], 'deleteItem arguments are valid'); + assert.deepEqual(this.options.deleteItem.args[1][0], items[1], 'deleteItem arguments are valid'); + }); }); test('move items', function(assert) { + const done = assert.async(); + const items = [ - new FileManagerItem(filesPathInfo, 'Documents'), - new FileManagerItem(filesPathInfo, 'Article.txt') + new FileSystemItem(filesPathInfo, 'Documents'), + new FileSystemItem(filesPathInfo, 'Article.txt') ]; - const destinationDir = new FileManagerItem(filesPathInfo, 'Music'); - const result = this.provider.moveItems(items, destinationDir); - - assert.deepEqual(result, [ 'moved Documents', 'moved Article.txt' ], 'result acquired'); - assert.strictEqual(this.options.moveItem.callCount, 2, 'moveItem called one time for each item'); - assert.deepEqual(this.options.moveItem.args[0][0], items[0], 'moveItem arguments are valid'); - assert.deepEqual(this.options.moveItem.args[0][1], destinationDir, 'moveItem arguments are valid'); - assert.deepEqual(this.options.moveItem.args[1][0], items[1], 'moveItem arguments are valid'); - assert.deepEqual(this.options.moveItem.args[1][1], destinationDir, 'moveItem arguments are valid'); + const destinationDir = new FileSystemItem(filesPathInfo, 'Music'); + + const deferreds = this.provider.moveItems(items, destinationDir); + assert.strictEqual(deferreds.length, 2, 'result contains deferrred for each item'); + + when.apply(null, deferreds) + .done((res1, res2) => { + done(); + + assert.strictEqual(res1, undefined, 'resolved with no result'); + assert.strictEqual(res2, undefined, 'resolved with no result'); + assert.strictEqual(this.options.moveItem.callCount, 2, 'moveItem called one time for each item'); + assert.deepEqual(this.options.moveItem.args[0][0], items[0], 'moveItem arguments are valid'); + assert.deepEqual(this.options.moveItem.args[0][1], destinationDir, 'moveItem arguments are valid'); + assert.deepEqual(this.options.moveItem.args[1][0], items[1], 'moveItem arguments are valid'); + assert.deepEqual(this.options.moveItem.args[1][1], destinationDir, 'moveItem arguments are valid'); + }); }); test('copy items', function(assert) { + const done = assert.async(); + const items = [ - new FileManagerItem(filesPathInfo, 'Documents'), - new FileManagerItem(filesPathInfo, 'Article.txt') + new FileSystemItem(filesPathInfo, 'Documents'), + new FileSystemItem(filesPathInfo, 'Article.txt') ]; - const destinationDir = new FileManagerItem(filesPathInfo, 'Music'); - const result = this.provider.copyItems(items, destinationDir); - - assert.deepEqual(result, [ 'copied Documents', 'copied Article.txt' ], 'result acquired'); - assert.strictEqual(this.options.copyItem.callCount, 2, 'copyItem called one time for each item'); - assert.deepEqual(this.options.copyItem.args[0][0], items[0], 'copyItem arguments are valid'); - assert.deepEqual(this.options.copyItem.args[0][1], destinationDir, 'copyItem arguments are valid'); - assert.deepEqual(this.options.copyItem.args[1][0], items[1], 'copyItem arguments are valid'); - assert.deepEqual(this.options.copyItem.args[1][1], destinationDir, 'copyItem arguments are valid'); + const destinationDir = new FileSystemItem(filesPathInfo, 'Music'); + + const deferreds = this.provider.copyItems(items, destinationDir); + assert.strictEqual(deferreds.length, 2, 'result contains deferrred for each item'); + + when.apply(null, deferreds) + .done((res1, res2) => { + done(); + + assert.strictEqual(res1, undefined, 'resolved with no result'); + assert.strictEqual(res2, undefined, 'resolved with no result'); + assert.strictEqual(this.options.copyItem.callCount, 2, 'copyItem called one time for each item'); + assert.deepEqual(this.options.copyItem.args[0][0], items[0], 'copyItem arguments are valid'); + assert.deepEqual(this.options.copyItem.args[0][1], destinationDir, 'copyItem arguments are valid'); + assert.deepEqual(this.options.copyItem.args[1][0], items[1], 'copyItem arguments are valid'); + assert.deepEqual(this.options.copyItem.args[1][1], destinationDir, 'copyItem arguments are valid'); + }); }); test('upload file chunk', function(assert) { + const done = assert.async(); + const fileData = { name: 'Test1.txt' }; const chunksInfo = { chunkIndex: 1 }; - const destinationDir = new FileManagerItem(filesPathInfo, 'Documents'); - const result = this.provider.uploadFileChunk(fileData, chunksInfo, destinationDir); - - assert.deepEqual(result, 'uploaded', 'result acquired'); - assert.strictEqual(this.options.uploadFileChunk.callCount, 1, 'uploadFileChunk called once'); - assert.deepEqual(this.options.uploadFileChunk.args[0][0], fileData, 'uploadFileChunk arguments are valid'); - assert.deepEqual(this.options.uploadFileChunk.args[0][1], chunksInfo, 'uploadFileChunk arguments are valid'); - assert.deepEqual(this.options.uploadFileChunk.args[0][2], destinationDir, 'uploadFileChunk arguments are valid'); + const destinationDir = new FileSystemItem(filesPathInfo, 'Documents'); + + this.provider.uploadFileChunk(fileData, chunksInfo, destinationDir) + .done(result => { + done(); + + assert.strictEqual(result, undefined, 'resolved with no result'); + assert.strictEqual(this.options.uploadFileChunk.callCount, 1, 'uploadFileChunk called once'); + assert.deepEqual(this.options.uploadFileChunk.args[0][0], fileData, 'uploadFileChunk arguments are valid'); + assert.deepEqual(this.options.uploadFileChunk.args[0][1], chunksInfo, 'uploadFileChunk arguments are valid'); + assert.deepEqual(this.options.uploadFileChunk.args[0][2], destinationDir, 'uploadFileChunk arguments are valid'); + }); }); test('abort file upload', function(assert) { + const done = assert.async(); + const fileData = { name: 'Test1.txt' }; const chunksInfo = { chunkIndex: 1 }; - const destinationDir = new FileManagerItem(filesPathInfo, 'Documents'); - const result = this.provider.abortFileUpload(fileData, chunksInfo, destinationDir); - - assert.deepEqual(result, 'aborted', 'result acquired'); - assert.strictEqual(this.options.abortFileUpload.callCount, 1, 'abortFileUpload called once'); - assert.deepEqual(this.options.abortFileUpload.args[0][0], fileData, 'abortFileUpload arguments are valid'); - assert.deepEqual(this.options.abortFileUpload.args[0][1], chunksInfo, 'abortFileUpload arguments are valid'); - assert.deepEqual(this.options.abortFileUpload.args[0][2], destinationDir, 'abortFileUpload arguments are valid'); - }); + const destinationDir = new FileSystemItem(filesPathInfo, 'Documents'); - test('upload chunk size', function(assert) { - let size = this.provider.getFileUploadChunkSize(); - assert.strictEqual(size, this.options.uploadChunkSize, 'result acquired'); + this.provider.abortFileUpload(fileData, chunksInfo, destinationDir) + .done(result => { + done(); - const provider = new CustomFileProvider(); - size = provider.getFileUploadChunkSize(); - assert.ok(size > 100000, 'default value used'); + assert.strictEqual(result, undefined, 'resolved with no result'); + assert.strictEqual(this.options.abortFileUpload.callCount, 1, 'abortFileUpload called once'); + assert.deepEqual(this.options.abortFileUpload.args[0][0], fileData, 'abortFileUpload arguments are valid'); + assert.deepEqual(this.options.abortFileUpload.args[0][1], chunksInfo, 'abortFileUpload arguments are valid'); + assert.deepEqual(this.options.abortFileUpload.args[0][2], destinationDir, 'abortFileUpload arguments are valid'); + }); }); }); diff --git a/testing/tests/DevExpress.ui.widgets/fileManagerParts/detailsView.tests.js b/testing/tests/DevExpress.ui.widgets/fileManagerParts/detailsView.tests.js index 46d5a3de2f4b..a08a7ea7067d 100644 --- a/testing/tests/DevExpress.ui.widgets/fileManagerParts/detailsView.tests.js +++ b/testing/tests/DevExpress.ui.widgets/fileManagerParts/detailsView.tests.js @@ -16,7 +16,7 @@ const moduleConfig = { mode: 'details', showParentFolder: false }, - fileProvider: [ + fileSystemProvider: [ { name: 'Folder 1', isDirectory: true @@ -81,7 +81,7 @@ const getSelectedItemNames = fileManager => fileManager.getSelectedItems().map(i const prepareParentDirectoryTesting = (context, singleSelection) => { const fileManager = context.$element.dxFileManager('instance'); fileManager.option({ - fileProvider: createTestFileSystem(), + fileSystemProvider: createTestFileSystem(), currentPath: 'Folder 1', selectionMode: singleSelection ? 'single' : 'multiple', itemView: { @@ -105,7 +105,7 @@ QUnit.module('Details View', moduleConfig, () => { test('Using custom formats of JSON files', function(assert) { $('#fileManager') .dxFileManager('instance') - .option('fileProvider', { + .option('fileSystemProvider', { data: [ { title: 'Folder', @@ -126,11 +126,11 @@ QUnit.module('Details View', moduleConfig, () => { }); this.clock.tick(400); - assert.ok(getCellValueInDetailsView(this.$element, 1, 2).indexOf('Folder') === 0); + assert.strictEqual(getCellValueInDetailsView(this.$element, 1, 2).indexOf('Folder'), 0); assert.equal(getCellValueInDetailsView(this.$element, 1, 3).trim(), '2/2/2000'); assert.equal(getCellValueInDetailsView(this.$element, 1, 4).trim(), ''); - assert.ok(getCellValueInDetailsView(this.$element, 2, 2).indexOf('Title.txt') === 0); + assert.strictEqual(getCellValueInDetailsView(this.$element, 2, 2).indexOf('Title.txt'), 0); assert.equal(getCellValueInDetailsView(this.$element, 2, 3).trim(), '1/1/2000'); assert.equal(getCellValueInDetailsView(this.$element, 2, 4).trim(), '55 B'); }); @@ -151,19 +151,18 @@ QUnit.module('Details View', moduleConfig, () => { }); test('Raise the SelectedFileOpened event', function(assert) { - let eventCounter = 0; + const spy = sinon.spy(); const fileManagerInstance = $('#fileManager').dxFileManager('instance'); - fileManagerInstance.option('onSelectedFileOpened', e => { - eventCounter++; - }); + fileManagerInstance.option('onSelectedFileOpened', spy); getCellInDetailsView(this.$element, 2, 2).trigger('dxdblclick'); this.clock.tick(800); - assert.equal(eventCounter, 1); + assert.equal(spy.callCount, 1); + assert.equal(spy.args[0][0].file.name, '1.txt', 'file passed as argument'); getCellInDetailsView(this.$element, 1, 2).trigger('dxdblclick'); this.clock.tick(800); - assert.equal(eventCounter, 1); + assert.equal(spy.callCount, 1); }); test('Apply sorting by click on file type column header', function(assert) { @@ -203,7 +202,7 @@ QUnit.module('Details View', moduleConfig, () => { test('\'Back\' directory must not be sortable', function(assert) { this.wrapper.getInstance().option({ - fileProvider: createTestFileSystem(), + fileSystemProvider: createTestFileSystem(), currentPath: 'Folder 1', itemView: { showParentFolder: true @@ -235,7 +234,9 @@ QUnit.module('Details View', moduleConfig, () => { assert.deepEqual(getSelectedItemNames(fileManager), [], 'no selection'); - this.wrapper.getRowNameCellInDetailsView(2).trigger('dxclick'); + this.wrapper.getRowNameCellInDetailsView(2) + .trigger('dxpointerdown') + .trigger('dxclick'); this.wrapper.getRowNameCellInDetailsView(2).trigger(pointerEvents.up); this.clock.tick(400); @@ -243,7 +244,9 @@ QUnit.module('Details View', moduleConfig, () => { assert.ok(this.wrapper.isDetailsRowFocused(2), 'first directory focused'); assert.deepEqual(getSelectedItemNames(fileManager), [ 'Folder 1.1' ], 'first directory in selection'); - this.wrapper.getRowNameCellInDetailsView(1).trigger('dxclick'); + this.wrapper.getRowNameCellInDetailsView(1) + .trigger('dxpointerdown') + .trigger('dxclick'); this.wrapper.getRowNameCellInDetailsView(1).trigger(pointerEvents.up); this.clock.tick(400); @@ -264,7 +267,7 @@ QUnit.module('Details View', moduleConfig, () => { for(let i = 2; i <= 5; i++) { const e = $.Event('dxclick'); e.ctrlKey = i !== 1; - this.wrapper.getRowNameCellInDetailsView(i).trigger(e).trigger(pointerEvents.up); + this.wrapper.getRowNameCellInDetailsView(i).trigger(pointerEvents.down).trigger(e); this.clock.tick(400); } @@ -273,7 +276,7 @@ QUnit.module('Details View', moduleConfig, () => { const e = $.Event('dxclick'); e.ctrlKey = true; - this.wrapper.getRowNameCellInDetailsView(1).trigger(e).trigger(pointerEvents.up); + this.wrapper.getRowNameCellInDetailsView(1).trigger(pointerEvents.down).trigger(e); assert.strictEqual(this.wrapper.getSelectAllCheckBoxState(), 'checked', 'select all is checked'); assert.deepEqual(getSelectedItemNames(fileManager), allNames, 'all items in selection'); @@ -303,16 +306,16 @@ QUnit.module('Details View', moduleConfig, () => { assert.deepEqual(getSelectedItemNames(fileManager), [], 'no selection'); + this.wrapper.getRowNameCellInDetailsView(2).trigger(pointerEvents.down); this.wrapper.getRowNameCellInDetailsView(2).trigger('dxclick'); - this.wrapper.getRowNameCellInDetailsView(2).trigger(pointerEvents.up); this.clock.tick(400); assert.notOk(this.wrapper.isDetailsRowSelected(2), 'first directory selected'); assert.ok(this.wrapper.isDetailsRowFocused(2), 'first directory focused'); assert.deepEqual(getSelectedItemNames(fileManager), [ 'Folder 1.1' ], 'first directory in selection'); + this.wrapper.getRowNameCellInDetailsView(1).trigger(pointerEvents.down); this.wrapper.getRowNameCellInDetailsView(1).trigger('dxclick'); - this.wrapper.getRowNameCellInDetailsView(1).trigger(pointerEvents.up); this.clock.tick(400); assert.notOk(this.wrapper.isDetailsRowSelected(2), 'first directory is not selected'); diff --git a/testing/tests/DevExpress.ui.widgets/fileManagerParts/editing.tests.js b/testing/tests/DevExpress.ui.widgets/fileManagerParts/editing.tests.js index 42b4dbbfbddf..ff4763a79c46 100644 --- a/testing/tests/DevExpress.ui.widgets/fileManagerParts/editing.tests.js +++ b/testing/tests/DevExpress.ui.widgets/fileManagerParts/editing.tests.js @@ -3,6 +3,7 @@ import 'ui/file_manager'; import pointerEvents from 'events/pointer'; import FileUploader from 'ui/file_uploader'; import fx from 'animation/fx'; +import CustomFileSystemProvider from 'file_management/custom_provider'; import { Consts, FileManagerWrapper, FileManagerProgressPanelWrapper, createTestFileSystem, createUploaderFiles, stubFileReader } from '../../../helpers/fileManagerHelpers.js'; const { test } = QUnit; @@ -19,7 +20,7 @@ const moduleConfig = { FileUploaderInternals.changeFileInputRenderer(() => $('
')); this.$element = $('#fileManager').dxFileManager({ - fileProvider: fileSystem, + fileSystemProvider: fileSystem, selectionMode: 'single', itemView: { showFolders: false, @@ -29,13 +30,14 @@ const moduleConfig = { create: true, copy: true, move: true, - remove: true, + delete: true, rename: true, upload: true, download: true } }); + this.fileManager = this.$element.dxFileManager('instance'); this.wrapper = new FileManagerWrapper(this.$element); this.progressPanelWrapper = new FileManagerProgressPanelWrapper(this.$element); @@ -107,7 +109,7 @@ QUnit.module('Editing operations', moduleConfig, () => { let $cell = this.wrapper.getRowNameCellInDetailsView(1); assert.equal(this.wrapper.getDetailsItemName(0), 'File 1.txt', 'has target file'); - $cell.trigger(pointerEvents.up).click(); + $cell.trigger(pointerEvents.down).click(); this.clock.tick(400); this.wrapper.getToolbarButton('Rename').trigger('dxclick'); @@ -128,7 +130,7 @@ QUnit.module('Editing operations', moduleConfig, () => { test('create folder in folders area from items area without folders', function(assert) { const $cell = this.wrapper.getRowNameCellInDetailsView(1); - $cell.trigger(pointerEvents.up).click(); + $cell.trigger(pointerEvents.down).click(); const $row = $cell.parent(); assert.ok($row.hasClass(Consts.FOCUSED_ROW_CLASS), 'file selected'); @@ -152,7 +154,7 @@ QUnit.module('Editing operations', moduleConfig, () => { test('create folder in folders area from items area without folders by Enter in dialog input', function(assert) { const $cell = this.wrapper.getRowNameCellInDetailsView(1); - $cell.trigger(pointerEvents.up).click(); + $cell.trigger(pointerEvents.down).click(); const $row = $cell.parent(); assert.ok($row.hasClass(Consts.FOCUSED_ROW_CLASS), 'file selected'); @@ -239,8 +241,8 @@ QUnit.module('Editing operations', moduleConfig, () => { $folderNodes = this.wrapper.getFolderNodes(); assert.equal($folderNodes.length, initialCount - 1, 'folders count decreased'); - assert.ok($folderNodes.eq(1).find('span').text().indexOf('Folder 1') === -1, 'first folder is not target folder'); - assert.ok($folderNodes.eq(2).find('span').text().indexOf('Folder 1') === -1, 'second folder is not target folder'); + assert.strictEqual($folderNodes.eq(1).find('span').text().indexOf('Folder 1'), -1, 'first folder is not target folder'); + assert.strictEqual($folderNodes.eq(2).find('span').text().indexOf('Folder 1'), -1, 'second folder is not target folder'); assert.equal(this.wrapper.getFocusedItemText(), 'Files', 'root folder selected'); }); @@ -251,7 +253,7 @@ QUnit.module('Editing operations', moduleConfig, () => { assert.equal(this.wrapper.getDetailsItemName(0), 'File 1.txt', 'has target file'); const $cell = this.wrapper.getRowNameCellInDetailsView(1); - $cell.trigger(pointerEvents.up).click(); + $cell.trigger(pointerEvents.down).click(); this.clock.tick(400); this.wrapper.getToolbarButton('Delete').trigger('dxclick'); @@ -259,8 +261,8 @@ QUnit.module('Editing operations', moduleConfig, () => { const $rows = this.wrapper.getRowsInDetailsView(); assert.equal($rows.length, initialCount - 1, 'files count decreased'); - assert.ok($rows.eq(0).text().indexOf('File 1.txt') === -1, 'first folder is not target folder'); - assert.ok($rows.eq(1).text().indexOf('File 1.txt') === -1, 'second folder is not target folder'); + assert.strictEqual($rows.eq(0).text().indexOf('File 1.txt'), -1, 'first folder is not target folder'); + assert.strictEqual($rows.eq(1).text().indexOf('File 1.txt'), -1, 'second folder is not target folder'); assert.equal(this.wrapper.getFocusedItemText(), 'Files', 'root folder selected'); }); @@ -277,7 +279,7 @@ QUnit.module('Editing operations', moduleConfig, () => { assert.equal(this.wrapper.getDetailsItemName(0), 'File 1-1.txt', 'has target file'); const $cell = this.wrapper.getRowNameCellInDetailsView(1); - $cell.trigger(pointerEvents.up).click(); + $cell.trigger(pointerEvents.down).click(); this.clock.tick(400); this.wrapper.getToolbarButton('Delete').trigger('dxclick'); @@ -285,8 +287,8 @@ QUnit.module('Editing operations', moduleConfig, () => { $rows = this.wrapper.getRowsInDetailsView(); assert.equal($rows.length, initialCount - 1, 'files count decreased'); - assert.ok($rows.eq(0).text().indexOf('File 1-1.txt') === -1, 'first folder is not target folder'); - assert.ok($rows.eq(1).text().indexOf('File 1-1.txt') === -1, 'second folder is not target folder'); + assert.strictEqual($rows.eq(0).text().indexOf('File 1-1.txt'), -1, 'first folder is not target folder'); + assert.strictEqual($rows.eq(1).text().indexOf('File 1-1.txt'), -1, 'second folder is not target folder'); assert.equal(this.wrapper.getFocusedItemText(), 'Folder 1', 'sub folder selected'); }); @@ -300,13 +302,13 @@ QUnit.module('Editing operations', moduleConfig, () => { $folderNode.trigger('dxclick'); this.clock.tick(400); - this.wrapper.getToolbarButton('Move').trigger('dxclick'); + this.wrapper.getToolbarButton('Move to').trigger('dxclick'); this.clock.tick(400); $folderNodes = this.wrapper.getFolderNodes(true); $folderNodes.eq(3).trigger('dxclick'); - this.wrapper.getDialogButton('Select').trigger('dxclick'); + this.wrapper.getDialogButton('Move').trigger('dxclick'); this.clock.tick(400); assert.equal(this.wrapper.getFocusedItemText(), 'Folder 3', 'destination folder should be selected'); @@ -337,13 +339,13 @@ QUnit.module('Editing operations', moduleConfig, () => { $folderNode.trigger('dxclick'); this.clock.tick(400); - this.wrapper.getToolbarButton('Copy').trigger('dxclick'); + this.wrapper.getToolbarButton('Copy to').trigger('dxclick'); this.clock.tick(400); $folderNodes = this.wrapper.getFolderNodes(true); $folderNodes.eq(3).trigger('dxclick'); - this.wrapper.getDialogButton('Select').trigger('dxclick'); + this.wrapper.getDialogButton('Copy').trigger('dxclick'); this.clock.tick(400); assert.equal(this.wrapper.getFocusedItemText(), 'Folder 3', 'target folder should be selected'); @@ -368,16 +370,16 @@ QUnit.module('Editing operations', moduleConfig, () => { const $cell = $cells.eq(0); assert.equal(this.wrapper.getDetailsItemName(0), 'File 1.txt', 'has target file'); - $cell.trigger(pointerEvents.up).click(); + $cell.trigger(pointerEvents.down).click(); this.clock.tick(400); - this.wrapper.getToolbarButton('Move').trigger('dxclick'); + this.wrapper.getToolbarButton('Move to').trigger('dxclick'); this.clock.tick(400); let $folderNodes = this.wrapper.getFolderNodes(true); $folderNodes.eq(3).trigger('dxclick'); - this.wrapper.getDialogButton('Select').trigger('dxclick'); + this.wrapper.getDialogButton('Move').trigger('dxclick'); this.clock.tick(400); assert.equal(this.wrapper.getFocusedItemText(), 'Folder 3', 'destination folder should be selected'); @@ -400,10 +402,10 @@ QUnit.module('Editing operations', moduleConfig, () => { const $cell = $cells.eq(0); assert.equal(this.wrapper.getDetailsItemName(0), 'File 1.txt', 'has target file'); - $cell.trigger(pointerEvents.up).click(); + $cell.trigger(pointerEvents.down).click(); this.clock.tick(400); - this.wrapper.getToolbarButton('Copy').trigger('dxclick'); + this.wrapper.getToolbarButton('Copy to').trigger('dxclick'); this.clock.tick(400); assert.equal(this.wrapper.getFocusedItemText(), 'Files', 'root folder selected'); @@ -411,7 +413,7 @@ QUnit.module('Editing operations', moduleConfig, () => { let $folderNodes = this.wrapper.getFolderNodes(true); $folderNodes.eq(3).trigger('dxclick'); - this.wrapper.getDialogButton('Select').trigger('dxclick'); + this.wrapper.getDialogButton('Copy').trigger('dxclick'); this.clock.tick(400); assert.equal(this.wrapper.getDetailsItemName(0), 'File 1.txt', 'file moved to another folder'); @@ -429,7 +431,7 @@ QUnit.module('Editing operations', moduleConfig, () => { test('rename file failed for not allowed extension', function(assert) { assert.equal(this.wrapper.getDetailsItemName(0), 'File 1.txt', 'has target file'); - this.wrapper.getRowNameCellInDetailsView(1).trigger(pointerEvents.up).click(); + this.wrapper.getRowNameCellInDetailsView(1).trigger(pointerEvents.down).click(); this.clock.tick(400); this.wrapper.getToolbarButton('Rename').trigger('dxclick'); @@ -451,7 +453,7 @@ QUnit.module('Editing operations', moduleConfig, () => { assert.equal(this.wrapper.getDetailsItemName(0), 'File 1.txt', 'has target file'); - this.wrapper.getRowNameCellInDetailsView(1).trigger(pointerEvents.up).click(); + this.wrapper.getRowNameCellInDetailsView(1).trigger(pointerEvents.down).click(); this.clock.tick(400); this.wrapper.getToolbarButton('Download').filter(':visible').trigger('dxclick'); @@ -485,6 +487,35 @@ QUnit.module('Editing operations', moduleConfig, () => { assert.strictEqual(this.wrapper.getDetailsCellText('File Size', uploadedFileIndex), '293 KB', 'file size is correct'); }); + test('upload chunkSize option', function(assert) { + const uploadChunkSpy = sinon.spy(); + const chunkSize = 50000; + + this.fileManager.option({ + fileSystemProvider: new CustomFileSystemProvider({ + uploadFileChunk: uploadChunkSpy + }), + upload: { chunkSize } + }); + + this.clock.tick(400); + + this.wrapper.getToolbarButton('Upload').filter(':visible').trigger('dxclick'); + + const file = createUploaderFiles(1)[0]; + this.wrapper.setUploadInputFile([ file ]); + this.clock.tick(400); + + assert.strictEqual(uploadChunkSpy.callCount, 6, 'uploadFileChunk called for each chunk'); + + for(let i = 0; i < 6; i++) { + const uploadInfo = uploadChunkSpy.args[i][1]; + assert.strictEqual(uploadInfo.chunkCount, 6, `chunkCount correct for ${i} chunk`); + assert.strictEqual(uploadInfo.chunkIndex, i, `chunkIndex correct for ${i} chunk`); + assert.strictEqual(uploadInfo.bytesUploaded, i * chunkSize, `bytesUploaded correct for ${i} chunk`); + } + }); + test('copying file must be completed in progress panel and current directory must be changed to the destination', function(assert) { const longPath = 'Files/Folder 1/Folder 1.1/Folder 1.1.1/Folder 1.1.1.1/Folder 1.1.1.1.1'; assert.equal(this.progressPanelWrapper.getInfos().length, 0, 'there is no operations'); @@ -494,10 +525,10 @@ QUnit.module('Editing operations', moduleConfig, () => { const $cell = $cells.eq(0); assert.equal(this.wrapper.getDetailsItemName(0), 'File 1.txt', 'has target file'); - $cell.trigger(pointerEvents.up).click(); + $cell.trigger(pointerEvents.down).click(); this.clock.tick(400); - this.wrapper.getToolbarButton('Copy').trigger('dxclick'); + this.wrapper.getToolbarButton('Copy to').trigger('dxclick'); this.clock.tick(400); this.wrapper.getFolderToggle(1, true).trigger('dxclick'); this.clock.tick(400); @@ -510,7 +541,7 @@ QUnit.module('Editing operations', moduleConfig, () => { this.wrapper.getFolderNode(5, true).trigger('dxclick'); this.clock.tick(400); - this.wrapper.getDialogButton('Select').trigger('dxclick'); + this.wrapper.getDialogButton('Copy').trigger('dxclick'); this.clock.tick(1200); assert.equal(this.wrapper.getDetailsItemName(0), 'Special deep file.txt', 'has specail file'); @@ -562,7 +593,7 @@ QUnit.module('Editing operations', moduleConfig, () => { this.clock.tick(800); const items = this.wrapper.getRowsInDetailsView(); - assert.ok((initialItemsLength + 1) === items.length, 'One item added'); + assert.strictEqual(items.length, initialItemsLength + 1, 'One item added'); assert.ok(items.eq(items.length - 1).text().indexOf('Untitled directory') > -1, 'Directory created'); assert.equal(this.progressPanelWrapper.getInfos()[0].common.commonText, 'Created a directory inside Files', 'common text is correct'); }); diff --git a/testing/tests/DevExpress.ui.widgets/fileManagerParts/editingProgress.tests.js b/testing/tests/DevExpress.ui.widgets/fileManagerParts/editingProgress.tests.js index 3294b4e332c4..08583d8d8e96 100644 --- a/testing/tests/DevExpress.ui.widgets/fileManagerParts/editingProgress.tests.js +++ b/testing/tests/DevExpress.ui.widgets/fileManagerParts/editingProgress.tests.js @@ -1,11 +1,11 @@ import $ from 'jquery'; import fx from 'animation/fx'; import { Deferred } from 'core/utils/deferred'; -import ArrayFileProvider from 'ui/file_manager/file_provider/array'; -import { ErrorCode } from 'ui/file_manager/ui.file_manager.common'; +import ObjectFileSystemProvider from 'file_management/object_provider'; +import ErrorCode from 'file_management/errors'; import FileItemsController from 'ui/file_manager/file_items_controller'; import { createTestFileSystem, createUploaderFiles, stubFileReader } from '../../../helpers/fileManagerHelpers.js'; -import TestFileProvider from '../../../helpers/fileManager/file_provider.test.js'; +import TestFileSystemProvider from '../../../helpers/fileManager/file_provider.test.js'; import FileManagerProgressPanelMock from '../../../helpers/fileManager/notification.progress_panel.mock.js'; import FileManagerNotificationControlMock from '../../../helpers/fileManager/notification.mock.js'; import FileManagerFileUploaderMock from '../../../helpers/fileManager/file_uploader.mock.js'; @@ -34,7 +34,7 @@ const moduleConfig = { const createController = (context, providerOptions) => { const data = createTestFileSystem(); - const arrayProvider = new ArrayFileProvider({ data }); + const arrayProvider = new ObjectFileSystemProvider({ data }); stubFileReader(arrayProvider); @@ -42,7 +42,7 @@ const createController = (context, providerOptions) => { provider: arrayProvider }; const config = $.extend(true, defaultConfig, providerOptions || {}); - const provider = new TestFileProvider(config); + const provider = new TestFileSystemProvider(config); context.controller = new FileItemsController({ fileProvider: provider, diff --git a/testing/tests/DevExpress.ui.widgets/fileManagerParts/fileItemsController.tests.js b/testing/tests/DevExpress.ui.widgets/fileManagerParts/fileItemsController.tests.js index 3622ed4f33ad..e81638dfd11a 100644 --- a/testing/tests/DevExpress.ui.widgets/fileManagerParts/fileItemsController.tests.js +++ b/testing/tests/DevExpress.ui.widgets/fileManagerParts/fileItemsController.tests.js @@ -1,7 +1,7 @@ const { test } = QUnit; import FileItemsController from 'ui/file_manager/file_items_controller'; -import { ErrorCode } from 'ui/file_manager/ui.file_manager.common'; +import ErrorCode from 'file_management/errors'; import { createUploaderFiles, createUploadInfo, stubFileReader } from '../../../helpers/fileManagerHelpers.js'; import { isString } from 'core/utils/type'; @@ -397,7 +397,7 @@ QUnit.module('FileItemsController tests', moduleConfig, () => { test('upload fails when max file size exceeded', function(assert) { this.controller = new FileItemsController({ fileProvider: this.data, - maxUploadFileSize: 400000 + uploadMaxFileSize: 400000 }); stubFileReaderInProvider(this.controller); @@ -490,14 +490,19 @@ QUnit.module('FileItemsController tests', moduleConfig, () => { this.clock.tick(100); }); - test('root direcotry key is unique', function(assert) { + test('root directory object has valid properties', function(assert) { const rootDir = this.controller.getCurrentDirectory(); - const rootKey = rootDir.fileItem.key; + const rootItem = rootDir.fileItem; - assert.ok(isString(rootKey), 'root key has type of string'); - assert.ok(rootKey.length > 10, 'root key contains many characters'); - assert.ok(rootKey.indexOf('Files') === -1, 'root key doesn\'t contain root directory name'); - assert.ok(rootKey.indexOf('__dxfmroot_') === 0, 'root key starts with internal prefix'); + assert.strictEqual(rootItem.key, '', 'root key is empty string'); + assert.strictEqual(rootItem.path, '', 'root path is empty string'); + assert.strictEqual(rootItem.name, '', 'root name is empty string'); + assert.strictEqual(rootDir.getDisplayName(), 'Files', 'root info name has default value'); + + assert.ok(isString(rootDir.getInternalKey()), 'root info key has type of string'); + assert.ok(rootDir.getInternalKey(), 'root info key is not empty'); + + assert.ok(rootItem.isRoot(), 'root has root flag'); }); }); diff --git a/testing/tests/DevExpress.ui.widgets/fileManagerParts/markup.tests.js b/testing/tests/DevExpress.ui.widgets/fileManagerParts/markup.tests.js index 275cbe8ecbd9..ae20f349403d 100644 --- a/testing/tests/DevExpress.ui.widgets/fileManagerParts/markup.tests.js +++ b/testing/tests/DevExpress.ui.widgets/fileManagerParts/markup.tests.js @@ -6,7 +6,7 @@ import { FileManagerWrapper, createTestFileSystem, Consts } from '../../../helpe const getDefaultConfig = () => { return { - fileProvider: createTestFileSystem(), + fileSystemProvider: createTestFileSystem(), itemView: { mode: 'thumbnails' }, @@ -14,7 +14,7 @@ const getDefaultConfig = () => { create: true, copy: true, move: true, - remove: true, + delete: true, rename: true, upload: true } @@ -68,7 +68,7 @@ QUnit.module('Markup rendering', moduleConfig, () => { fileSystem[1].name = 'Folder 2 test 11111111 testtesttestest 22222 test test 1111111 test 1 222222'; this.prepareFileManager({ - fileProvider: fileSystem, + fileSystemProvider: fileSystem, itemView: { mode: 'details' }, @@ -85,7 +85,7 @@ QUnit.module('Markup rendering', moduleConfig, () => { test('active area switches on itemView and dirsPanel click', function(assert) { this.prepareFileManager({ - fileProvider: createTestFileSystem() + fileSystemProvider: createTestFileSystem() }); const dirsPanel = this.wrapper.getDirsPanel(); const itemsView = this.wrapper.getItemsView(); diff --git a/testing/tests/DevExpress.ui.widgets/fileManagerParts/navigation.tests.js b/testing/tests/DevExpress.ui.widgets/fileManagerParts/navigation.tests.js index a40a04c3b342..a408d37e4705 100644 --- a/testing/tests/DevExpress.ui.widgets/fileManagerParts/navigation.tests.js +++ b/testing/tests/DevExpress.ui.widgets/fileManagerParts/navigation.tests.js @@ -16,7 +16,7 @@ const moduleConfig = { fx.off = true; this.$element = $('#fileManager').dxFileManager({ - fileProvider: fileSystem, + fileSystemProvider: fileSystem, itemView: { mode: 'thumbnails' }, @@ -24,7 +24,7 @@ const moduleConfig = { create: true, copy: true, move: true, - remove: true, + delete: true, rename: true, upload: true } @@ -240,7 +240,7 @@ QUnit.module('Navigation operations', moduleConfig, () => { let dir = inst.getCurrentDirectory(); assert.strictEqual(dir.relativeName, '', 'directory has empty relative name'); assert.ok(dir.isDirectory, 'directory has directory flag'); - assert.ok(dir.isRoot, 'directory has root flag'); + assert.ok(dir.isRoot(), 'directory has root flag'); inst.option('currentPath', 'Folder 1/Folder 1.1'); this.clock.tick(800); @@ -248,34 +248,34 @@ QUnit.module('Navigation operations', moduleConfig, () => { dir = inst.getCurrentDirectory(); assert.strictEqual(dir.relativeName, 'Folder 1/Folder 1.1', 'directory has correct relative name'); assert.ok(dir.isDirectory, 'directory has directory flag'); - assert.notOk(dir.isRoot, 'directory has not root flag'); + assert.notOk(dir.isRoot(), 'directory has not root flag'); }); test('change current directory by public API', function(assert) { const inst = this.wrapper.getInstance(); - assert.equal(inst.option('currentPath'), ''); + const spy = sinon.spy(); - const that = this; - let onCurrentDirectoryChangedCounter = 0; - inst.option('onCurrentDirectoryChanged', function() { - onCurrentDirectoryChangedCounter++; - }); + assert.equal(inst.option('currentPath'), ''); + inst.option('onCurrentDirectoryChanged', spy); inst.option('currentPath', 'Folder 1/Folder 1.1'); this.clock.tick(800); - assert.equal(onCurrentDirectoryChangedCounter, 1); + assert.equal(spy.callCount, 1); + assert.equal(spy.args[0][0].directory.path, 'Folder 1/Folder 1.1', 'directory passed as argument'); assert.equal(inst.option('currentPath'), 'Folder 1/Folder 1.1', 'The option \'currentPath\' was changed'); - const $folder1Node = that.wrapper.getFolderNode(1); + const $folder1Node = this.wrapper.getFolderNode(1); assert.equal($folder1Node.find('span').text(), 'Folder 1'); - const $folder11Node = that.wrapper.getFolderNode(2); + const $folder11Node = this.wrapper.getFolderNode(2); assert.equal($folder11Node.find('span').text(), 'Folder 1.1'); inst.option('currentPath', ''); this.clock.tick(800); + assert.equal(spy.callCount, 2); + assert.equal(spy.args[1][0].directory.path, '', 'directory argument updated'); assert.equal(this.wrapper.getFocusedItemText(), 'Files', 'root folder selected'); assert.equal(this.wrapper.getBreadcrumbsPath(), 'Files', 'breadcrumbs refrers to the root folder'); }); @@ -446,7 +446,7 @@ QUnit.module('Navigation operations', moduleConfig, () => { const incorrectOptionValue = 'Docu//me//nts'; const incorrectName = 'Docu/me/nts'; const fileProvider = createFileProviderWithIncorrectName(incorrectName); - inst.option('fileProvider', fileProvider); + inst.option('fileSystemProvider', fileProvider); let counter = 0; inst.option('onOptionChanged', (e) => { e.name === 'currentPath' && counter++; }); @@ -501,7 +501,7 @@ QUnit.module('Navigation operations', moduleConfig, () => { const incorrectPartialName = 'Docu/'; let fileProvider = createFileProviderWithIncorrectName(incorrectName); fileProvider = fileProvider.concat(createFileProviderWithIncorrectName(incorrectPartialName, true)); - inst.option('fileProvider', fileProvider); + inst.option('fileSystemProvider', fileProvider); inst.option('currentPath', incorrectOptionValue); this.clock.tick(400); @@ -524,7 +524,7 @@ QUnit.module('Navigation operations', moduleConfig, () => { test('\'Back\' directory must have attributes of the represented directory', function(assert) { const fileManager = this.wrapper.getInstance(); fileManager.option({ - fileProvider: [ + fileSystemProvider: [ { name: 'Folder 1', isDirectory: true, diff --git a/testing/tests/DevExpress.ui.widgets/fileManagerParts/remoteProvider.tests.js b/testing/tests/DevExpress.ui.widgets/fileManagerParts/remoteProvider.tests.js index f73ccfbba7cb..e636573a3d36 100644 --- a/testing/tests/DevExpress.ui.widgets/fileManagerParts/remoteProvider.tests.js +++ b/testing/tests/DevExpress.ui.widgets/fileManagerParts/remoteProvider.tests.js @@ -1,14 +1,14 @@ import 'ui/file_manager'; -import { FileManagerItem } from 'ui/file_manager/file_provider/file_provider'; +import FileSystemItem from 'file_management/file_system_item'; -import RemoteFileProvider from 'ui/file_manager/file_provider/remote'; +import RemoteFileSystemProvider from 'file_management/remote_provider'; import ajaxMock from '../../../helpers/ajaxMock.js'; import { createSampleFileItems } from '../../../helpers/fileManagerHelpers.js'; import { when } from 'core/utils/deferred'; const { test } = QUnit; -const { filesPathInfo, itemData, fileManagerItems } = createSampleFileItems(); +const { filesPathInfo, itemData, fileSystemItems } = createSampleFileItems(); const moduleConfig = { @@ -17,7 +17,7 @@ const moduleConfig = { endpointUrl: '/api/endpoint' }; - this.provider = new RemoteFileProvider(this.options); + this.provider = new RemoteFileSystemProvider(this.options); }, afterEach: function() { @@ -40,14 +40,11 @@ QUnit.module('Remote Provider', moduleConfig, () => { callback: request => assert.equal(request.method, 'GET') }); - const pathInfo = [ - { key: 'Root', name: 'Root' }, - { key: 'Root/Files', name: 'Files' } - ]; + const filesDir = new FileSystemItem('Root/Files', true); - this.provider.getItems(pathInfo) + this.provider.getItems(filesDir) .done(folders => { - assert.deepEqual(folders, fileManagerItems, 'folders received'); + assert.deepEqual(folders, fileSystemItems, 'folders received'); done(); }); }); @@ -63,8 +60,8 @@ QUnit.module('Remote Provider', moduleConfig, () => { callback: request => assert.equal(request.method, 'POST') }); - const parentFolder = new FileManagerItem(filesPathInfo, 'Documents'); - this.provider.createFolder(parentFolder, 'Test 1') + const parentFolder = new FileSystemItem(filesPathInfo, 'Documents'); + this.provider.createDirectory(parentFolder, 'Test 1') .done(result => { assert.ok(result.success, 'folder created'); done(); @@ -82,7 +79,7 @@ QUnit.module('Remote Provider', moduleConfig, () => { callback: request => assert.equal(request.method, 'POST') }); - const item = new FileManagerItem(filesPathInfo, 'Documents'); + const item = new FileSystemItem(filesPathInfo, 'Documents'); this.provider.renameItem(item, 'Test 1') .done(result => { assert.ok(result.success, 'item renamed'); @@ -101,7 +98,7 @@ QUnit.module('Remote Provider', moduleConfig, () => { callback: request => assert.equal(request.method, 'POST') }); - const item = new FileManagerItem(filesPathInfo, 'Documents'); + const item = new FileSystemItem(filesPathInfo, 'Documents'); const deferreds = this.provider.deleteItems([ item ]); when.apply(null, deferreds) .done(result => { @@ -121,8 +118,8 @@ QUnit.module('Remote Provider', moduleConfig, () => { callback: request => assert.equal(request.method, 'POST') }); - const item = new FileManagerItem(filesPathInfo, 'Documents'); - const destinationFolder = new FileManagerItem(filesPathInfo, 'Images'); + const item = new FileSystemItem(filesPathInfo, 'Documents'); + const destinationFolder = new FileSystemItem(filesPathInfo, 'Images'); const deferreds = this.provider.moveItems([ item ], destinationFolder); when.apply(null, deferreds) .done(result => { @@ -142,8 +139,8 @@ QUnit.module('Remote Provider', moduleConfig, () => { callback: request => assert.equal(request.method, 'POST') }); - const item = new FileManagerItem(filesPathInfo, 'Documents'); - const destinationFolder = new FileManagerItem(filesPathInfo, 'Images'); + const item = new FileSystemItem(filesPathInfo, 'Documents'); + const destinationFolder = new FileSystemItem(filesPathInfo, 'Images'); const deferreds = this.provider.copyItems([ item ], destinationFolder); when.apply(null, deferreds) .done(result => { @@ -164,8 +161,8 @@ QUnit.module('Remote Provider', moduleConfig, () => { } }); - const item = new FileManagerItem(filesPathInfo, 'Article.txt'); - this.provider.getItemContent([ item ]) + const item = new FileSystemItem(filesPathInfo, 'Article.txt'); + this.provider.getItemsContent([ item ]) .done(result => { assert.strictEqual(result.byteLength, 5, 'item content acquired'); done(); @@ -173,15 +170,15 @@ QUnit.module('Remote Provider', moduleConfig, () => { }); test('generation end point', function(assert) { - let provider = new RemoteFileProvider({ + let provider = new RemoteFileSystemProvider({ endpointUrl: 'myEndpoint' }); - assert.ok(provider._getEndpointUrl('myCommand', { }).indexOf('myEndpoint?command=myCommand') !== -1); + assert.notStrictEqual(provider._getEndpointUrl('myCommand', { }).indexOf('myEndpoint?command=myCommand'), -1); - provider = new RemoteFileProvider({ + provider = new RemoteFileSystemProvider({ endpointUrl: 'myEndpoint?param1=value' }); - assert.ok(provider._getEndpointUrl('myCommand', { }).indexOf('myEndpoint?param1=value&command=myCommand') !== -1); + assert.notStrictEqual(provider._getEndpointUrl('myCommand', { }).indexOf('myEndpoint?param1=value&command=myCommand'), -1); }); }); diff --git a/testing/tests/DevExpress.ui.widgets/fileManagerParts/toolbar.tests.js b/testing/tests/DevExpress.ui.widgets/fileManagerParts/toolbar.tests.js index 78a54bed507b..bd136eaba498 100644 --- a/testing/tests/DevExpress.ui.widgets/fileManagerParts/toolbar.tests.js +++ b/testing/tests/DevExpress.ui.widgets/fileManagerParts/toolbar.tests.js @@ -29,7 +29,7 @@ const createFileManager = useThumbnailViewMode => { const viewMode = useThumbnailViewMode ? 'thumbnails' : 'details'; $('#fileManager').dxFileManager({ - fileProvider: fileSystem, + fileSystemProvider: fileSystem, itemView: { mode: viewMode, showFolders: false, @@ -39,7 +39,7 @@ const createFileManager = useThumbnailViewMode => { create: true, copy: true, move: true, - remove: true, + delete: true, rename: true, upload: true } @@ -165,7 +165,7 @@ QUnit.module('Toolbar', moduleConfig, () => { create: false, copy: false, move: false, - remove: false, + delete: false, rename: false, upload: false }); @@ -225,7 +225,7 @@ QUnit.module('Toolbar', moduleConfig, () => { location: 'after' }, { - name: 'viewSwitcher', + name: 'switchView', location: 'before' }] }); @@ -270,7 +270,7 @@ QUnit.module('Toolbar', moduleConfig, () => { name: 'separator', location: 'after' }, - 'viewSwitcher', + 'switchView', { ID: 42, name: 'commandName', @@ -305,7 +305,7 @@ QUnit.module('Toolbar', moduleConfig, () => { name: 'separator', location: 'after' }, - 'viewSwitcher', + 'switchView', { name: 'commandName', locateInMenu: 'always', @@ -374,7 +374,7 @@ QUnit.module('Toolbar', moduleConfig, () => { name: 'separator', location: 'after' }, - 'viewSwitcher' + 'switchView' ] }); this.clock.tick(400); diff --git a/testing/tests/DevExpress.ui.widgets/filterBuilderParts/commonTests.js b/testing/tests/DevExpress.ui.widgets/filterBuilderParts/commonTests.js index 8c43874cd44c..7ab9809f7189 100644 --- a/testing/tests/DevExpress.ui.widgets/filterBuilderParts/commonTests.js +++ b/testing/tests/DevExpress.ui.widgets/filterBuilderParts/commonTests.js @@ -123,7 +123,7 @@ QUnit.module('Rendering', function() { assert.ok(!$fieldButton.hasClass(ACTIVE_CLASS)); assert.equal(container.find('.' + FILTER_BUILDER_ITEM_OPERATION_CLASS).text(), 'Contains'); assert.equal(container.find('.' + FILTER_BUILDER_ITEM_VALUE_CLASS).text(), ''); - assert.ok($('.dx-filterbuilder-fields').length === 0); + assert.strictEqual($('.dx-filterbuilder-fields').length, 0); }); QUnit.test('editorElement argument of onEditorPreparing option is correct', function(assert) { @@ -205,7 +205,7 @@ QUnit.module('Rendering', function() { selectMenuItem(3); - assert.ok($('.dx-filterbuilder-group-operations').length === 0); + assert.strictEqual($('.dx-filterbuilder-group-operations').length, 0); $groupButton.trigger('dxclick'); assert.equal(getSelectedMenuText(), 'Not Or'); @@ -229,7 +229,7 @@ QUnit.module('Rendering', function() { selectMenuItem(3); - assert.ok($('.dx-filterbuilder-operations').length === 0); + assert.strictEqual($('.dx-filterbuilder-operations').length, 0); assert.equal(container.find('.' + FILTER_BUILDER_ITEM_VALUE_CLASS).length, 1); $operationButton.trigger('dxclick'); diff --git a/testing/tests/DevExpress.ui.widgets/gantt.tests.js b/testing/tests/DevExpress.ui.widgets/gantt.tests.js index e6ce4252279c..d9c617ef440d 100644 --- a/testing/tests/DevExpress.ui.widgets/gantt.tests.js +++ b/testing/tests/DevExpress.ui.widgets/gantt.tests.js @@ -27,6 +27,7 @@ const SPLITTER_SELECTOR = '.dx-splitter'; const POPUP_SELECTOR = '.dx-popup-normal'; const GANTT_VIEW_HORIZONTAL_BORDER_SELECTOR = '.dx-gantt-hb'; const TIME_MARKER_SELECTOR = '.dx-gantt-tm'; +const TIME_INTERVAL_SELECTOR = '.dx-gantt-ti'; const OVERLAY_WRAPPER_SELECTOR = '.dx-overlay-wrapper'; const CONTEXT_MENU_SELECTOR = '.dx-context-menu'; const INPUT_TEXT_EDITOR_SELECTOR = '.dx-texteditor-input'; @@ -97,7 +98,7 @@ QUnit.module('Markup', moduleConfig, () => { test('should render treeList', function(assert) { this.createInstance(tasksOnlyOptions); const treeListElements = this.$element.find(TREELIST_SELECTOR); - assert.ok(treeListElements.length === 1); + assert.strictEqual(treeListElements.length, 1); }); test('should render task wrapper for each task', function(assert) { this.createInstance(allSourcesOptions); @@ -625,9 +626,9 @@ QUnit.module('Context Menu', moduleConfig, () => { QUnit.module('Time Markers', moduleConfig, () => { test('render', function(assert) { const timeMarkers = [ - { dateTime: tasks[0].start, title: 'Start' }, - { dateTime: new Date(2019, 2, 1) }, - { dateTime: () => tasks[tasks.length - 1].end, title: 'End', cssClass: 'end' } + { start: tasks[0].start, title: 'First' }, + { start: new Date(2019, 2, 1) }, + { start: new Date(2019, 5, 5), end: () => tasks[tasks.length - 1].end, title: 'Interval', cssClass: 'end' } ]; const options = { tasks: { dataSource: tasks }, @@ -638,6 +639,8 @@ QUnit.module('Time Markers', moduleConfig, () => { const $timeMarkers = this.$element.find(TIME_MARKER_SELECTOR); assert.equal($timeMarkers.length, timeMarkers.length, 'all time markers are rendered'); + const $timeIntervals = this.$element.find(TIME_INTERVAL_SELECTOR); + assert.equal($timeIntervals.length, 1, 'all time intervals are rendered'); assert.ok($timeMarkers.eq(2).hasClass(timeMarkers[2].cssClass), 'custom cssClass rendered'); assert.equal($timeMarkers.eq(0).attr('title'), timeMarkers[0].title, 'title rendered'); }); @@ -646,10 +649,21 @@ QUnit.module('Time Markers', moduleConfig, () => { this.clock.tick(); let $timeMarkers = this.$element.find(TIME_MARKER_SELECTOR); - assert.equal($timeMarkers.length, 0, 'gantt has not time markers'); + assert.equal($timeMarkers.length, 0, 'gantt has no time markers'); + let $timeIntervals = this.$element.find(TIME_INTERVAL_SELECTOR); + assert.equal($timeIntervals.length, 0, 'gantt has no time intervals'); + + this.instance.option('timeMarkers', [ + { start: tasks[0].start }, + { start: tasks[tasks.length - 1].start, end: tasks[tasks.length - 1].end } + ]); + $timeMarkers = this.$element.find(TIME_MARKER_SELECTOR); + assert.equal($timeMarkers.length, 2, 'gantt has time markers'); + $timeIntervals = this.$element.find(TIME_INTERVAL_SELECTOR); + assert.equal($timeIntervals.length, 1, 'gantt has time interval'); - this.instance.option('timeMarkers', [{ dateTime: tasks[0].start, title: 'Start' }]); + this.instance.option('timeMarkers', []); $timeMarkers = this.$element.find(TIME_MARKER_SELECTOR); - assert.equal($timeMarkers.length, 1, 'gantt has a time marker'); + assert.equal($timeMarkers.length, 0, 'gantt has no time markers'); }); }); diff --git a/testing/tests/DevExpress.ui.widgets/init_dispose_widget_bundled_tests.js b/testing/tests/DevExpress.ui.widgets/init_dispose_widget_bundled_tests.js new file mode 100644 index 000000000000..a40ddca49677 --- /dev/null +++ b/testing/tests/DevExpress.ui.widgets/init_dispose_widget_bundled_tests.js @@ -0,0 +1,58 @@ +import GoogleStaticProvider from 'ui/map/provider.google_static'; +import fx from 'animation/fx'; +import { each } from 'core/utils/iterator'; +import 'bundles/modules/parts/widgets-all'; + +const { module: testModule, test } = QUnit; + +testModule('Init and dispose', { + before: function() { + this.element = document.createElement('div'); + document.getElementById('qunit-fixture').appendChild(this.element); + }, + after: function() { + const { parentNode } = this.element; + if(parentNode) { + parentNode.removeChild(this.element); + } + } +}, function() { + fx.off = true; + GoogleStaticProvider.remapConstant('/mapURL?'); + + const getOptions = function(componentName, assert, done) { + const options = { + onInitialized: () => { + assert.ok(true, `${componentName} initialized`); + }, + onDisposing: () => { + assert.ok(true, `${componentName} disposed`); + done(); + } + }; + + switch(componentName) { + case 'dxValidator': + options.adapter = {}; + break; + case 'dxMap': + options.provider = 'googleStatic'; + break; + } + + return options; + }; + + each(DevExpress.ui, function(componentName, componentConstructor) { + if(componentName.indexOf('dx') !== 0) { + return; + } + + test(componentName, function(assert) { + assert.expect(2); + const done = assert.async(); + const instance = new componentConstructor(this.element, getOptions(componentName, assert, done)); + instance.dispose(); + }); + }); +}); diff --git a/testing/tests/DevExpress.ui.widgets/listParts/editingUITests.js b/testing/tests/DevExpress.ui.widgets/listParts/editingUITests.js index 3e584f7db4af..5388f12ad795 100644 --- a/testing/tests/DevExpress.ui.widgets/listParts/editingUITests.js +++ b/testing/tests/DevExpress.ui.widgets/listParts/editingUITests.js @@ -855,7 +855,7 @@ QUnit.test('inkRipple feedback should not be broken if swipe in opposite directi clock.tick(100); const inkRippleShowingWave = $item.find(toSelector(INKRIPPLE_WAVE_SHOWING_CLASS)); - assert.ok(inkRippleShowingWave.length === 1, 'inkripple feedback works right after swipe in opposite direction'); + assert.strictEqual(inkRippleShowingWave.length, 1, 'inkripple feedback works right after swipe in opposite direction'); pointer.start('touch').up(); clock.restore(); @@ -2493,8 +2493,8 @@ QUnit.module('reordering decorator', { }); const REORDER_HANDLE_CLASS = 'dx-list-reorder-handle'; -const REOREDERING_ITEM_CLASS = 'dx-sortable-source-hidden'; -const REOREDERING_ITEM_GHOST_CLASS = 'dx-list-item-ghost-reordering'; +const REORDERING_ITEM_CLASS = 'dx-sortable-source-hidden'; +const REORDERING_ITEM_GHOST_CLASS = 'dx-list-item-ghost-reordering'; const reorderingPointerMock = ($item, clock, usePixel) => { const itemOffset = $item.offset().top; @@ -2656,9 +2656,9 @@ QUnit.test('reordering class should be present on item during drag', function(as pointer.dragStart().drag(10); this.clock.tick(); - assert.ok($item.hasClass(REOREDERING_ITEM_CLASS), 'class was added'); + assert.ok($item.hasClass(REORDERING_ITEM_CLASS), 'class was added'); pointer.dragEnd(); - assert.ok(!$item.hasClass(REOREDERING_ITEM_CLASS), 'class was removed'); + assert.ok(!$item.hasClass(REORDERING_ITEM_CLASS), 'class was removed'); }); QUnit.test('reordering should not be possible if item disabled', function(assert) { @@ -2671,7 +2671,7 @@ QUnit.test('reordering should not be possible if item disabled', function(assert const pointer = reorderingPointerMock($item, this.clock, true); pointer.dragStart().drag(10); - assert.ok(!$item.hasClass(REOREDERING_ITEM_CLASS), 'class was not added'); + assert.ok(!$item.hasClass(REORDERING_ITEM_CLASS), 'class was not added'); }); QUnit.test('list item should be duplicated on drag start', function(assert) { @@ -2686,13 +2686,41 @@ QUnit.test('list item should be duplicated on drag start', function(assert) { pointer.dragStart().drag(10); this.clock.tick(); - let $ghostItem = $list.find(toSelector(REOREDERING_ITEM_GHOST_CLASS)); + let $ghostItem = $list.find(toSelector(REORDERING_ITEM_GHOST_CLASS)); assert.strictEqual($ghostItem.text(), $item.text(), 'correct item was duplicated'); assert.strictEqual($ghostItem.offset().top, $item.offset().top + 10, 'correct ghost position'); - assert.ok(!$ghostItem.hasClass(REOREDERING_ITEM_CLASS), 'reordering class is not present'); + assert.ok(!$ghostItem.hasClass(REORDERING_ITEM_CLASS), 'reordering class is not present'); pointer.dragEnd(); - $ghostItem = $list.find(toSelector(REOREDERING_ITEM_GHOST_CLASS)); + $ghostItem = $list.find(toSelector(REORDERING_ITEM_GHOST_CLASS)); + assert.strictEqual($items.length, 1, 'duplicate item was removed'); +}); + +// T859557 +QUnit.test('list item duplicate should inherit direction (rtl)', function(assert) { + const $list = $('#templated-list').dxList({ + items: ['0'], + itemDragging: { allowReordering: true }, + rtlEnabled: true + }); + + const $items = $list.find(toSelector(LIST_ITEM_CLASS)); + const $item = $items.eq(0); + const pointer = reorderingPointerMock($item, this.clock, true); + + pointer.dragStart().drag(10); + + this.clock.tick(); + let $ghostItem = $list.find(toSelector(REORDERING_ITEM_GHOST_CLASS)); + assert.strictEqual($ghostItem.text(), $item.text(), 'correct item was duplicated'); + assert.strictEqual($ghostItem.offset().top, $item.offset().top + 10, 'correct ghost position'); + assert.ok(!$ghostItem.hasClass(REORDERING_ITEM_CLASS), 'reordering class is not present'); + + assert.equal($ghostItem.css('direction'), 'rtl', 'direction is rtl'); + assert.ok($ghostItem.parent().hasClass('dx-rtl'), 'ghost\'s parent has dx-rtl class'); + + pointer.dragEnd(); + $ghostItem = $list.find(toSelector(REORDERING_ITEM_GHOST_CLASS)); assert.strictEqual($items.length, 1, 'duplicate item was removed'); }); @@ -2712,7 +2740,7 @@ QUnit.test('cached items doesn\'t contains a ghost item after reordering', funct const cachedItems = list._itemElements(); assert.strictEqual(cachedItems.length, 3, 'Cached items contains 3 items'); - assert.notOk(cachedItems.hasClass(REOREDERING_ITEM_GHOST_CLASS), 'Cached items isn\'t contain a ghost item'); + assert.notOk(cachedItems.hasClass(REORDERING_ITEM_GHOST_CLASS), 'Cached items isn\'t contain a ghost item'); }); QUnit.test('ghost item should be moved by drag', function(assert) { @@ -2727,7 +2755,7 @@ QUnit.test('ghost item should be moved by drag', function(assert) { pointer.dragStart().drag(10); this.clock.tick(); - const $ghostItem = $list.find(toSelector(REOREDERING_ITEM_GHOST_CLASS)); + const $ghostItem = $list.find(toSelector(REORDERING_ITEM_GHOST_CLASS)); const startPosition = topTranslation($ghostItem.parent()); pointer.drag(20); @@ -2926,3 +2954,26 @@ QUnit.test('items should reset positions after dragend', function(assert) { }); }); +// T856292 +QUnit.test('Drag and drop item to the top of the list should not work when allowReordering is false', function(assert) { + const $list = $('#list').dxList({ + items: ['0', '1', '2'], + itemDragging: { + allowReordering: false, + group: 'shared' + } + }); + + let $items = $list.find(toSelector(LIST_ITEM_CLASS)); + const $item3 = $items.eq(2); + const pointer = reorderingPointerMock($item3, this.clock); + + pointer.dragStart(0.5).drag(-1).drag(-1.5).dragEnd(); + + $items = $list.find(toSelector(LIST_ITEM_CLASS)); + $.each($items, (index, item) => { + const $item = $(item); + + assert.equal($item.text(), index, 'item text'); + }); +}); diff --git a/testing/tests/DevExpress.ui.widgets/overlay.tests.js b/testing/tests/DevExpress.ui.widgets/overlay.tests.js index 29192c5c42c9..2b807ac0bbda 100644 --- a/testing/tests/DevExpress.ui.widgets/overlay.tests.js +++ b/testing/tests/DevExpress.ui.widgets/overlay.tests.js @@ -1421,6 +1421,23 @@ testModule('content', moduleConfig, () => { assert.ok(newContentReadyStub.calledOnce); }); + test('content ready action should be fired if was set thought method', function(assert) { + const contentReadyStub = sinon.stub(); + const instance = $('#overlay').dxOverlay({ + onContentReady: contentReadyStub + }).dxOverlay('instance'); + + const newContentReadyStub = sinon.stub(); + instance.on('contentReady', newContentReadyStub); + + instance.show(); + instance.hide(); + instance.show(); + + assert.ok(contentReadyStub.calledOnce); + assert.ok(newContentReadyStub.calledOnce); + }); + test('content should be rendered only once after repaint', function(assert) { const contentReadyStub = sinon.stub(); const instance = $('#overlay').dxOverlay({ diff --git a/testing/tests/DevExpress.ui.widgets/popup.tests.js b/testing/tests/DevExpress.ui.widgets/popup.tests.js index 714a8ccd127c..5d2645a5ef43 100644 --- a/testing/tests/DevExpress.ui.widgets/popup.tests.js +++ b/testing/tests/DevExpress.ui.widgets/popup.tests.js @@ -1217,16 +1217,16 @@ QUnit.module('resize', { }); QUnit.test('resize callbacks', function(assert) { - let onResizeStartFired = 0; - let onResizeFired = 0; - let onResizeEndFired = 0; + const onResizeStartStub = sinon.stub(); + const onResizeStub = sinon.stub(); + const onResizeEndStub = sinon.stub(); const instance = $('#popup').dxPopup({ resizeEnabled: true, visible: true, - onResizeStart: function() { onResizeStartFired++; }, - onResize: function() { onResizeFired++; }, - onResizeEnd: function() { onResizeEndFired++; } + onResizeStart: onResizeStartStub, + onResize: onResizeStub, + onResizeEnd: onResizeEndStub }).dxPopup('instance'); const $content = instance.overlayContent(); @@ -1235,9 +1235,34 @@ QUnit.module('resize', { pointer.start().dragStart().drag(0, 50).dragEnd(); - assert.equal(onResizeStartFired, 1, 'onResizeStart fired'); - assert.equal(onResizeFired, 1, 'onResize fired'); - assert.equal(onResizeEndFired, 1, 'onResizeEnd fired'); + assert.ok(onResizeStartStub.calledOnce, 'onResizeStart fired'); + assert.ok(onResizeStub.calledOnce, 'onResize fired'); + assert.ok(onResizeEndStub.calledOnce, 'onResizeEnd fired'); + }); + + QUnit.test('resize event handlers should correctly added via "on" method', function(assert) { + const onResizeStartStub = sinon.stub(); + const onResizeStub = sinon.stub(); + const onResizeEndStub = sinon.stub(); + + const instance = $('#popup').dxPopup({ + resizeEnabled: true + }).dxPopup('instance'); + + instance.on('resize', onResizeStub); + instance.on('resizeStart', onResizeStartStub); + instance.on('resizeEnd', onResizeEndStub); + instance.show(); + + const $content = instance.overlayContent(); + const $handle = $content.find('.dx-resizable-handle-top'); + const pointer = pointerMock($handle); + + pointer.start().dragStart().drag(0, 50).dragEnd(); + + assert.ok(onResizeStartStub.calledOnce, 'onResizeStart fired'); + assert.ok(onResizeStub.calledOnce, 'onResize fired'); + assert.ok(onResizeEndStub.calledOnce, 'onResizeEnd fired'); }); }); @@ -1453,6 +1478,23 @@ QUnit.module('templates', () => { assert.equal($popupContent.find(toSelector('changed-test-title-renderer')).length, 1, 'option \'titleTemplate\' successfully passed to the popup widget'); }); + QUnit.test('titleRendered event should be fired if was set thought method', function(assert) { + assert.expect(1); + + const $element = $('#popup').dxPopup({ + visible: true, + showTitle: true + }); + const instance = $element.dxPopup('instance'); + + instance.on('titleRendered', function(e) { + assert.ok(true, 'titleRendered event handled'); + }); + + instance.option('titleTemplate', () => $('
').text('new title')); + instance.show(); + }); + QUnit.test('\'bottomTemplate\' options test', function(assert) { const $element = $('#popup').dxPopup({ visible: true, diff --git a/testing/tests/DevExpress.ui.widgets/scrollView.tests.js b/testing/tests/DevExpress.ui.widgets/scrollView.tests.js index 07a4432a3dbb..01b5f1b9b47e 100644 --- a/testing/tests/DevExpress.ui.widgets/scrollView.tests.js +++ b/testing/tests/DevExpress.ui.widgets/scrollView.tests.js @@ -304,7 +304,7 @@ QUnit.module('actions', moduleConfig, () => { pointerMock($content) .start() .down() - .move(0, $container.height() - $content.height() - $bottomPocket.height() - 1) + .move(0, $container.height() - $content.height() + $bottomPocket.height() + 0.49) .up(); }); @@ -1664,7 +1664,7 @@ QUnit.module('native pullDown strategy', { const $container = $scrollView.find('.' + SCROLLABLE_CONTAINER_CLASS); const $content = $scrollView.find('.' + SCROLLABLE_CONTENT_CLASS); const $bottomPocket = $scrollView.find('.' + SCROLLVIEW_BOTTOM_POCKET_CLASS); - $container.scrollTop($content.height() - $container.height() + $bottomPocket.height() + 1); + $container.scrollTop($content.height() - $container.height() - $bottomPocket.height() + 0.51); $($container).trigger('scroll'); }); diff --git a/testing/tests/DevExpress.ui.widgets/scrollableParts/scrollable.api.tests.js b/testing/tests/DevExpress.ui.widgets/scrollableParts/scrollable.api.tests.js index ee28d75c1d17..094debef62b2 100644 --- a/testing/tests/DevExpress.ui.widgets/scrollableParts/scrollable.api.tests.js +++ b/testing/tests/DevExpress.ui.widgets/scrollableParts/scrollable.api.tests.js @@ -702,12 +702,76 @@ class ScrollableTestHelper { QUnit.assert.equal(scrollArguments.reachedLeft, options.reachedLeft, 'reachedLeft'); QUnit.assert.equal(scrollArguments.reachedRight, options.reachedRight, 'reachedRight'); } + + checkScrollOffset(options) { + const scrollOffset = getScrollOffset(this.$scrollable); + + QUnit.assert.strictEqual(scrollOffset.left, options.left, 'scrollOffset.left'); + QUnit.assert.strictEqual(scrollOffset.top, options.top, 'scrollOffset.top'); + QUnit.assert.strictEqual(this.getMaxScrollOffset().horizontal, options.maxScrollOffset, 'horizontal maxScrollOffset'); + } } -[0, 10].forEach((pushBackValue) => { - [true, false].forEach((useNative) => { +[true, false].forEach((useNative) => { + QUnit.module(`ScrollPosition after update(), native: ${useNative}`, moduleConfig, () => { + QUnit.test('direction: horizontal, rtl: false -> scrollTo(left: center) -> scrollTo(left: max)', function() { + const helper = new ScrollableTestHelper({ direction: 'horizontal', useNative: useNative, rtlEnabled: false, pushBackValue: 0 }); + helper.checkScrollOffset({ left: 0, top: 0, maxScrollOffset: 50 }); + + helper.scrollable.update(); + helper.checkScrollOffset({ left: 0, top: 0, maxScrollOffset: 50 }); + + helper.scrollable.scrollTo({ left: 25 }); + helper.scrollable.update(); + helper.checkScrollOffset({ left: -25, top: 0, maxScrollOffset: 50 }); + + helper.scrollable.scrollTo({ left: 50 }); + helper.scrollable.update(); + helper.checkScrollOffset({ left: -50, top: 0, maxScrollOffset: 50 }); + }); + + QUnit.test('direction: horizontal, rtl: true -> scrollTo(left: center) -> scrollTo(left: 0)', function() { + const helper = new ScrollableTestHelper({ direction: 'horizontal', useNative: useNative, rtlEnabled: true, pushBackValue: 0 }); + helper.checkScrollOffset({ left: -50, top: 0, maxScrollOffset: 50 }); + + helper.scrollable.update(); + helper.checkScrollOffset({ left: -50, top: 0, maxScrollOffset: 50 }); + + helper.scrollable.scrollTo({ left: 25 }); + helper.scrollable.update(); + helper.checkScrollOffset({ left: -25, top: 0, maxScrollOffset: 50 }); + + helper.scrollable.scrollTo({ left: 0 }); + helper.scrollable.update(); + helper.checkScrollOffset({ left: 0, top: 0, maxScrollOffset: 50 }); + }); + + QUnit.test('Change content size, direction: horizontal, rtl: false -> change content size', function() { + const helper = new ScrollableTestHelper({ direction: 'horizontal', useNative: useNative, rtlEnabled: false, pushBackValue: 0 }); + helper.checkScrollOffset({ left: 0, top: 0, maxScrollOffset: 50 }); + + helper.$scrollable.find('.content1').css('width', '200px'); + helper.checkScrollOffset({ left: 0, top: 0, maxScrollOffset: 150 }); + + helper.scrollable.update(); + helper.checkScrollOffset({ left: 0, top: 0, maxScrollOffset: 150 }); + }); + + QUnit.test('direction: horizontal, rtl: true -> change content size', function() { + const helper = new ScrollableTestHelper({ direction: 'horizontal', useNative: useNative, rtlEnabled: true, pushBackValue: 0 }); + helper.checkScrollOffset({ left: -50, top: 0, maxScrollOffset: 50 }); + + helper.$scrollable.find('.content1').css('width', '200px'); + helper.checkScrollOffset({ left: -50, top: 0, maxScrollOffset: 150 }); // left should be -150 (T848870) + + helper.scrollable.update(); + helper.checkScrollOffset({ left: -50, top: 0, maxScrollOffset: 150 }); + }); + }); + + [0, 10].forEach((pushBackValue) => { QUnit.module(`Scroll arguments, native: ${useNative}, pushBackValue: ${pushBackValue}`, moduleConfig, () => { - QUnit.test('Direction: \'vertical\', rtl: false, scrollPosition: { top: 0 } -> { top: 1 } -> { top: center } -> { top: max-1 } -> { top: max }', function() { + QUnit.test('Direction: vertical, rtl: false, scrollPosition: { top: 0 } -> { top: 1 } -> { top: center } -> { top: max-1 } -> { top: max }', function() { const helper = new ScrollableTestHelper({ direction: 'vertical', useNative: useNative, rtlEnabled: false, pushBackValue: pushBackValue }); const maxOffset = helper.getMaxScrollOffset(); @@ -735,7 +799,7 @@ class ScrollableTestHelper { helper.checkScrollEvent({ reachedTop: false, reachedBottom: true, reachedLeft: undefined, reachedRight: undefined }); }); - QUnit.test('Direction: \'horizontal\', rtl: false, scrollPosition: { left: 0 } -> { left: 1 } -> { left: center } -> { left: max-1 } -> { left: max }', function() { + QUnit.test('Direction: horizontal, rtl: false, scrollPosition: { left: 0 } -> { left: 1 } -> { left: center } -> { left: max-1 } -> { left: max }', function() { const helper = new ScrollableTestHelper({ direction: 'horizontal', useNative: useNative, rtlEnabled: false, pushBackValue: pushBackValue }); const maxOffset = helper.getMaxScrollOffset(); @@ -763,7 +827,7 @@ class ScrollableTestHelper { helper.checkScrollEvent({ reachedTop: undefined, reachedBottom: undefined, reachedLeft: false, reachedRight: true }); }); - QUnit.test('Direction: \'both\', rtl: false, scrollPosition: { top: 0, left: 0 } -> { top:1, left: 1 } -> { top: center, left: center } -> { top: max-1, left: max-1 } -> { top: max, left: max }', function() { + QUnit.test('Direction: both, rtl: false, scrollPosition: { top: 0, left: 0 } -> { top:1, left: 1 } -> { top: center, left: center } -> { top: max-1, left: max-1 } -> { top: max, left: max }', function() { const helper = new ScrollableTestHelper({ direction: 'both', useNative: useNative, rtlEnabled: false, pushBackValue: pushBackValue }); const maxOffset = helper.getMaxScrollOffset(); @@ -791,7 +855,7 @@ class ScrollableTestHelper { helper.checkScrollEvent({ reachedTop: false, reachedBottom: true, reachedLeft: false, reachedRight: true }); }); - QUnit.test('Direction: \'vertical\', rtl: true, scrollPosition: { top: 0 } -> { top: 1 } -> { top: center } -> { top: max-1 } -> { top: max }', function() { + QUnit.test('Direction: vertical, rtl: true, scrollPosition: { top: 0 } -> { top: 1 } -> { top: center } -> { top: max-1 } -> { top: max }', function() { const helper = new ScrollableTestHelper({ direction: 'vertical', useNative: useNative, rtlEnabled: true, pushBackValue: pushBackValue }); const maxOffset = helper.getMaxScrollOffset(); @@ -819,7 +883,7 @@ class ScrollableTestHelper { helper.checkScrollEvent({ reachedTop: false, reachedBottom: true, reachedLeft: undefined, reachedRight: undefined }); }); - QUnit.test('Direction: \'horizontal\', rtl: true, scrollPosition: { left: max } -> { left: max-1 } -> { left: center } -> { left: 1 } -> { left: 0 }', function() { + QUnit.test('Direction: horizontal, rtl: true, scrollPosition: { left: max } -> { left: max-1 } -> { left: center } -> { left: 1 } -> { left: 0 }', function() { const helper = new ScrollableTestHelper({ direction: 'horizontal', useNative: useNative, rtlEnabled: true, pushBackValue: pushBackValue }); const maxOffset = helper.getMaxScrollOffset(); @@ -847,7 +911,7 @@ class ScrollableTestHelper { helper.checkScrollEvent({ reachedTop: undefined, reachedBottom: undefined, reachedLeft: true, reachedRight: false }); }); - QUnit.test('Direction: \'both\', rtl: true, scrollPosition: { top: 0, left: max } -> { top:1, left: max-1 } -> { top: center, left: center } -> { top: max-1, left: 1 } -> { top: max, left: 0 }', function() { + QUnit.test('Direction: both, rtl: true, scrollPosition: { top: 0, left: max } -> { top:1, left: max-1 } -> { top: center, left: center } -> { top: max-1, left: 1 } -> { top: max, left: 0 }', function() { const helper = new ScrollableTestHelper({ direction: 'both', useNative: useNative, rtlEnabled: true, pushBackValue: pushBackValue }); const maxOffset = helper.getMaxScrollOffset(); diff --git a/testing/tests/DevExpress.ui.widgets/sortable.tests.js b/testing/tests/DevExpress.ui.widgets/sortable.tests.js index b931e59dfb9e..7d6698476fc9 100644 --- a/testing/tests/DevExpress.ui.widgets/sortable.tests.js +++ b/testing/tests/DevExpress.ui.widgets/sortable.tests.js @@ -361,6 +361,24 @@ QUnit.test('option changing', function(assert) { assert.strictEqual(this.$element.children().first().text(), 'item1', 'first item is not changed'); }); +QUnit.test('Move to top if allowReordering is false', function(assert) { + // arrange + const onDragChangeSpy = sinon.spy(); + + this.createSortable({ + allowReordering: false, + dropFeedbackMode: 'indicate', + onDragChange: onDragChangeSpy + }); + + // act + pointerMock(this.$element.children().eq(1)).start().down(15, 45).move(0, -45); + + // assert + assert.strictEqual(onDragChangeSpy.callCount, 0, 'onDragChange event is not called'); + assert.strictEqual($('.dx-sortable-placeholder').length, 0, 'placeholder does not exist'); +}); + QUnit.module('placeholder and source', moduleConfig); @@ -2391,7 +2409,7 @@ QUnit.test('Placeholder position should be updated during autoscroll', function( this.clock.tick(10); currentPlaceholderOffsetTop = $(PLACEHOLDER_SELECTOR).offset().top; - assert.ok(currentPlaceholderOffsetTop !== previousPlaceholderOffsetTop, 'placeholder was updated'); + assert.notStrictEqual(currentPlaceholderOffsetTop, previousPlaceholderOffsetTop, 'placeholder was updated'); previousPlaceholderOffsetTop = currentPlaceholderOffsetTop; } diff --git a/testing/tests/DevExpress.ui.widgets/tabPanel.tests.js b/testing/tests/DevExpress.ui.widgets/tabPanel.tests.js index 4186c938f613..0b5ac479f5a6 100644 --- a/testing/tests/DevExpress.ui.widgets/tabPanel.tests.js +++ b/testing/tests/DevExpress.ui.widgets/tabPanel.tests.js @@ -33,6 +33,7 @@ QUnit.testStart(() => { const TABS_CLASS = 'dx-tabs'; const MULTIVIEW_ITEM_CLASS = 'dx-multiview-item'; const TABS_ITEM_CLASS = 'dx-tab'; +const SELECTED_TAB_CLASS = 'dx-tab-selected'; const SELECTED_ITEM_CLASS = 'dx-item-selected'; const TABPANEL_CONTAINER_CLASS = 'dx-tabpanel-container'; @@ -478,6 +479,46 @@ QUnit.module('focus policy', { $tabPanel.trigger('focusin'); assert.equal(tabNativeFocus.callCount, 0, 'native focus should not be triggered'); }); + + function checkSelectionAndFocus(tabPanel, expectedSelectedIndex) { + const $tabPanel = tabPanel.$element(); + const expectedSelectedItem = tabPanel.option('items')[expectedSelectedIndex]; + + QUnit.assert.equal(tabPanel.option('selectedItem'), expectedSelectedItem, 'tabPanel.option(selectedItem)'); + QUnit.assert.equal($tabPanel.find(`.${MULTIVIEW_ITEM_CLASS}.${SELECTED_ITEM_CLASS}`).get(0).innerText, 'content ' + expectedSelectedIndex, 'tabPanel.SELECTED_ITEM_CLASS'); + + QUnit.assert.equal(tabPanel._tabs.option('selectedItem'), expectedSelectedItem, 'tabPanel._tabs.option(selectedItem)'); + QUnit.assert.equal($tabPanel.find(`.${TABS_ITEM_CLASS}.${SELECTED_TAB_CLASS}`).get(0).innerText, 'tab ' + expectedSelectedIndex, 'tabPanel._tabs.SELECTED_TAB_CLASS'); + + if(tabPanel.option('focusStateEnabled') === true) { + QUnit.assert.equal($(tabPanel.option('focusedElement')).text(), 'content ' + expectedSelectedIndex, 'tabPanel.options(focusedElement)'); + QUnit.assert.equal($(tabPanel._tabs.option('focusedElement')).text(), 'tab ' + expectedSelectedIndex, 'tabPanel._tabs.focusedElement'); + } else { + QUnit.assert.equal(tabPanel.option('focusedElement'), null, 'tabPanel.option(focusedElement)'); + QUnit.assert.equal(tabPanel._tabs.option('focusedElement'), null, 'tabPanel._tabs.options(focusedElement)'); + } + } + + [0, 1].forEach(selectedIndex => { + ['selectedIndex', 'selectedItem'].forEach(optionName => { + QUnit.test(`focus -> setSelectedTab(${selectedIndex}) -> focus`, function(assert) { + const $tabPanel = $('#tabPanel').dxTabPanel({ + items: [{ tabTemplate: 'tab 0', template: 'content 0' }, { tabTemplate: 'tab 1', template: 'content 1' }] + }); + const tabPanel = $tabPanel.dxTabPanel('instance'); + + $tabPanel.focusin(); + if(optionName === 'selectedIndex') { + tabPanel.option('selectedIndex', selectedIndex); + } else { + tabPanel.option('selectedItem', tabPanel.option('items')[selectedIndex]); + } + $tabPanel.focusin(); + + checkSelectionAndFocus(tabPanel, selectedIndex); + }); + }); + }); }); QUnit.module('keyboard navigation', { @@ -532,7 +573,6 @@ QUnit.module('keyboard navigation', { this.clock.tick(); const tabsFocusedIndex = $(this.instance.option('focusedElement')).index(); - assert.equal(isRenderer(this.instance.option('focusedElement')), !!config().useJQuery, 'focusedElement is correct'); assert.equal(tabsFocusedIndex, 1, 'second tabs element has been focused'); assert.equal(tabsFocusedIndex, $(this.instance.option('focusedElement')).index(), 'multiView focused element is equal tabs focused element'); @@ -597,4 +637,3 @@ QUnit.module('dataSource integration', () => { assert.equal(dataSourceLoadCalled, 1, 'dataSource load called once'); }); }); - diff --git a/testing/tests/DevExpress.ui.widgets/treeViewParts/initialization.js b/testing/tests/DevExpress.ui.widgets/treeViewParts/initialization.js index c0c70988ee33..5f33f13c540e 100644 --- a/testing/tests/DevExpress.ui.widgets/treeViewParts/initialization.js +++ b/testing/tests/DevExpress.ui.widgets/treeViewParts/initialization.js @@ -1,18 +1,46 @@ /* global initTree */ import TreeViewTestWrapper from '../../../helpers/TreeViewTestHelper.js'; import $ from 'jquery'; -QUnit.module('Initialization'); +QUnit.module('Initialization', () => { + QUnit.test('Init tree view', function(assert) { + const $treeView = initTree(); + assert.ok($treeView); + }); -QUnit.test('Init tree view', function(assert) { - const $treeView = initTree(); - assert.ok($treeView); -}); + function createOptions(options) { + const result = $.extend({ dataStructure: 'plain', rootValue: 1 }, options); + if(result.dataSourceOption === 'createChildren') { + const createChildFunction = (parent) => { + return parent == null + ? [ options.testItems[options.testRootItemIndex || 0] ] + : options.testItems.filter(function(item) { return parent.itemData.id === item.parentId; }); + }; + result.createChildren = createChildFunction; + } else { + result[options.dataSourceOption] = options.testItems; + } + return result; + } + + ['items', 'dataSource', 'createChildren'].forEach((dataSourceOption) => { + [false, true].forEach((virtualModeEnabled) => { + [0, -1, 1.1, '0', 'aaa', null, undefined].forEach(rootValue => { + QUnit.test(`rootValue = ${rootValue}, dataSource: ${dataSourceOption}, virtualModeEnabled: ${virtualModeEnabled}`, function(assert) { + const options = createOptions({ + dataSourceOption, virtualModeEnabled, rootValue, testItems: [ + { id: 1, text: 'item1', parentId: rootValue }, + { id: 2, text: 'item2', parentId: 1 }] + }); + + const wrapper = new TreeViewTestWrapper(options); + const $item1 = wrapper.getElement().find('[aria-level="1"]'); + assert.notEqual(wrapper.instance, undefined); + assert.notEqual($item1.length, 0, 'item1 must be rendered'); + }); + }); -['items', 'dataSource', 'createChildren'].forEach((dataSourceOption) => { - [false, true].forEach((virtualModeEnabled) => { - QUnit.module(`Initialization with cycle/loop keys. DataSource: ${dataSourceOption}. VirtualModeEnabled: ${virtualModeEnabled} (T832760)`, () => { - QUnit.test('rootValue', function(assert) { + QUnit.test(`Initialization with cycle/loop keys. DataSource: ${dataSourceOption}. VirtualModeEnabled: ${virtualModeEnabled} (T832760)`, function(assert) { const configs = [ { rootValue: 1, expectedItemId: 2, rootItemIndex: 1 }, { rootValue: 2, expectedItemId: 3, rootItemIndex: 2 }, @@ -45,21 +73,7 @@ QUnit.test('Init tree view', function(assert) { wrapper.instance.dispose(); }); }); - - function createOptions(options) { - const result = $.extend({ dataStructure: 'plain', rootValue: 1 }, options); - if(result.dataSourceOption === 'createChildren') { - const createChildFunction = (parent) => { - return parent == null - ? [ options.testItems[options.testRootItemIndex] ] - : options.testItems.filter(function(item) { return parent.itemData.id === item.parentId; }); - }; - result.createChildren = createChildFunction; - } else { - result[options.dataSourceOption] = options.testItems; - } - return result; - } }); }); }); + diff --git a/testing/tests/DevExpress.ui/collectionWidget.tests.js b/testing/tests/DevExpress.ui/collectionWidget.tests.js index 724a9961c5a7..668e1b673968 100644 --- a/testing/tests/DevExpress.ui/collectionWidget.tests.js +++ b/testing/tests/DevExpress.ui/collectionWidget.tests.js @@ -1111,7 +1111,7 @@ module('items via markup', { const $element = $('#cmp'); const dxItemString = 'dxItem: {}'; - const $innerItem = window.test = $('
').attr('data-options', dxItemString).text('test'); + const $innerItem = $('
').attr('data-options', dxItemString).text('test'); $innerItem.appendTo($element); const component = new TestComponent('#cmp', {}); @@ -1125,7 +1125,7 @@ module('items via markup', { const $element = $('#cmp'); const dxItemString = '{ "dxItem": {} }'; - const $innerItem = window.test = $('
').attr('data-options', dxItemString).text('test'); + const $innerItem = $('
').attr('data-options', dxItemString).text('test'); $innerItem.appendTo($element); let component; try { diff --git a/testing/tests/DevExpress.ui/defaultOptions.tests.js b/testing/tests/DevExpress.ui/defaultOptions.tests.js index 3cedcfeb05b3..98cb88bf402a 100644 --- a/testing/tests/DevExpress.ui/defaultOptions.tests.js +++ b/testing/tests/DevExpress.ui/defaultOptions.tests.js @@ -120,7 +120,6 @@ testComponentDefaults(DateBox, {}, { useMaskBehavior: false, - advanceCaret: true, adaptivityEnabled: false } ); diff --git a/testing/tests/DevExpress.viz.charts/chart.part1.tests.js b/testing/tests/DevExpress.viz.charts/chart.part1.tests.js index 68fa823799d2..33316ca46a6e 100644 --- a/testing/tests/DevExpress.viz.charts/chart.part1.tests.js +++ b/testing/tests/DevExpress.viz.charts/chart.part1.tests.js @@ -2,7 +2,7 @@ const $ = require('jquery'); const noop = require('core/utils/common').noop; const vizMocks = require('../../helpers/vizMocks.js'); const commons = require('./chartParts/commons.js'); -const dataSourceModule = require('data/data_source/data_source'); +const DataSource = require('data/data_source/data_source').DataSource; const BaseChart = require('viz/chart_components/base_chart').BaseChart; const rendererModule = require('viz/core/renderers/renderer'); const layoutManagerModule = require('viz/chart_components/layout_manager'); @@ -460,7 +460,7 @@ QUnit.test('hide on reinit', function(assert) { QUnit.test('not hide on reinit, when dataSource is not loaded', function(assert) { // arrange - const ds = new dataSourceModule.DataSource(); + const ds = new DataSource(); const chart = this.createChart({ dataSource: ds }); @@ -976,7 +976,7 @@ QUnit.module('isReady', $.extend({}, commons.environment, { })); QUnit.test('isReady with not loaded dataSource', function(assert) { - const ds = new dataSourceModule.DataSource(); + const ds = new DataSource(); ds.isLoaded = sinon.stub().returns(false); const chart = this.createChart({ dataSource: ds }); diff --git a/testing/tests/DevExpress.viz.charts/chart.part6.tests.js b/testing/tests/DevExpress.viz.charts/chart.part6.tests.js index be3321963400..7f6e19312c76 100644 --- a/testing/tests/DevExpress.viz.charts/chart.part6.tests.js +++ b/testing/tests/DevExpress.viz.charts/chart.part6.tests.js @@ -139,7 +139,7 @@ QUnit.test('change series options only - populateSeries', function(assert) { }); // Assert - assert.ok(oldSeries !== chart.series, 'new series'); + assert.notStrictEqual(oldSeries, chart.series, 'new series'); assert.ok(chart.seriesDisposed, 'Series should be disposed'); assert.ok(chart.seriesFamiliesDisposed, 'SeriesFamilies should be disposed'); @@ -476,9 +476,9 @@ QUnit.test('change containerBackgroundColor option only', function(assert) { assert.ok(!valAxis.disposed); assert.ok(!argAxis.disposed); - assert.ok(stubSeries1 === chart.getAllSeries()[0], 'Series should be updated'); - assert.ok(valAxis === chart._valueAxes[0], 'Val axis should be updated'); - assert.ok(argAxis === chart._argumentAxes[0], 'Arg axis should be updated'); + assert.strictEqual(stubSeries1, chart.getAllSeries()[0], 'Series should be updated'); + assert.strictEqual(valAxis, chart._valueAxes[0], 'Val axis should be updated'); + assert.strictEqual(argAxis, chart._argumentAxes[0], 'Arg axis should be updated'); }); QUnit.test('change resolveLabelsOverlapping option only', function(assert) { @@ -503,9 +503,9 @@ QUnit.test('change resolveLabelsOverlapping option only', function(assert) { // assert assert.ok(!series.disposed); assert.ok(!seriesFamily.dispose.called); - assert.ok(stubSeries1 === chart.getAllSeries()[0], 'Series should be updated'); - assert.ok(valAxis === chart._valueAxes[0], 'Val axis should not be recreated'); - assert.ok(argAxis === chart._argumentAxes[0], 'Arg axis should not be recreated'); + assert.strictEqual(stubSeries1, chart.getAllSeries()[0], 'Series should be updated'); + assert.strictEqual(valAxis, chart._valueAxes[0], 'Val axis should not be recreated'); + assert.strictEqual(argAxis, chart._argumentAxes[0], 'Arg axis should not be recreated'); }); QUnit.test('change title option only. change title settings', function(assert) { @@ -1390,9 +1390,9 @@ QUnit.test('title option', function(assert) { title: 'changed title' }); // assert - assert.ok(series === chart.getAllSeries()[0], 'Series should not be recreated'); - assert.ok(valAxis === chart._valueAxes[0], 'Val axis should not be recreated'); - assert.ok(argAxis === chart._argumentAxes[0], 'Arg axis should not be recreated'); + assert.strictEqual(series, chart.getAllSeries()[0], 'Series should not be recreated'); + assert.strictEqual(valAxis, chart._valueAxes[0], 'Val axis should not be recreated'); + assert.strictEqual(argAxis, chart._argumentAxes[0], 'Arg axis should not be recreated'); assert.ok(onDrawn.called); }); @@ -1416,9 +1416,9 @@ QUnit.test('adaptiveLayout option', function(assert) { assert.deepEqual(this.layoutManager.setOptions.lastCall.args, [{ width: 'someWidth', height: 'someHeight' }]); - assert.ok(series === chart.getAllSeries()[0], 'Series should not be recreated'); - assert.ok(valAxis === chart._valueAxes[0], 'Val axis should not be recreated'); - assert.ok(argAxis === chart._argumentAxes[0], 'Arg axis should not be recreated'); + assert.strictEqual(series, chart.getAllSeries()[0], 'Series should not be recreated'); + assert.strictEqual(valAxis, chart._valueAxes[0], 'Val axis should not be recreated'); + assert.strictEqual(argAxis, chart._argumentAxes[0], 'Arg axis should not be recreated'); }); QUnit.test('crosshair option', function(assert) { @@ -1438,9 +1438,9 @@ QUnit.test('crosshair option', function(assert) { assert.strictEqual(commons.getTrackerStub().update.lastCall.args[0].crosshair, chart._crosshair); - assert.ok(series === chart.getAllSeries()[0], 'Series should not be recreated'); - assert.ok(valAxis === chart._valueAxes[0], 'Val axis should not be recreated'); - assert.ok(argAxis === chart._argumentAxes[0], 'Arg axis should not be recreated'); + assert.strictEqual(series, chart.getAllSeries()[0], 'Series should not be recreated'); + assert.strictEqual(valAxis, chart._valueAxes[0], 'Val axis should not be recreated'); + assert.strictEqual(argAxis, chart._argumentAxes[0], 'Arg axis should not be recreated'); }); QUnit.test('adjustOnZoom option', function(assert) { @@ -1480,9 +1480,9 @@ QUnit.test('adjustOnZoom option', function(assert) { // assert assert.strictEqual(stubSeries1.getValueAxis().adjust.callCount, 1); - assert.ok(series === chart.getAllSeries()[0], 'Series should not be recreated'); - assert.ok(valAxis === chart._valueAxes[0], 'Val axis should not be recreated'); - assert.ok(argAxis === chart._argumentAxes[0], 'Arg axis should not be recreated'); + assert.strictEqual(series, chart.getAllSeries()[0], 'Series should not be recreated'); + assert.strictEqual(valAxis, chart._valueAxes[0], 'Val axis should not be recreated'); + assert.strictEqual(argAxis, chart._argumentAxes[0], 'Arg axis should not be recreated'); }); QUnit.module('Change options - recreate series but not axes', commons.environment); @@ -1512,9 +1512,9 @@ QUnit.test('pointSelectionMode option', function(assert) { assert.equal(commons.getTrackerStub().stub('update').lastCall.args[0].pointSelectionMode, 'new-point-selection-mode'); assert.equal(chart.getAllSeries()[0].renderSettings.commonSeriesModes.pointSelectionMode, 'new-point-selection-mode'); - assert.ok(series === chart.getAllSeries()[0], 'Series should be updated'); - assert.ok(valAxis === chart._valueAxes[0], 'Val axis should not be recreated'); - assert.ok(argAxis === chart._argumentAxes[0], 'Arg axis should not be recreated'); + assert.strictEqual(series, chart.getAllSeries()[0], 'Series should be updated'); + assert.strictEqual(valAxis, chart._valueAxes[0], 'Val axis should not be recreated'); + assert.strictEqual(argAxis, chart._argumentAxes[0], 'Arg axis should not be recreated'); }); QUnit.test('seriesSelectionMode option', function(assert) { @@ -1542,9 +1542,9 @@ QUnit.test('seriesSelectionMode option', function(assert) { assert.equal(commons.getTrackerStub().stub('update').lastCall.args[0].seriesSelectionMode, 'new-series-selection-mode'); assert.equal(chart.getAllSeries()[0].renderSettings.commonSeriesModes.seriesSelectionMode, 'new-series-selection-mode'); - assert.ok(series === chart.getAllSeries()[0], 'Series should be updated'); - assert.ok(valAxis === chart._valueAxes[0], 'Val axis should not be recreated'); - assert.ok(argAxis === chart._argumentAxes[0], 'Arg axis should not be recreated'); + assert.strictEqual(series, chart.getAllSeries()[0], 'Series should be updated'); + assert.strictEqual(valAxis, chart._valueAxes[0], 'Val axis should not be recreated'); + assert.strictEqual(argAxis, chart._argumentAxes[0], 'Arg axis should not be recreated'); }); QUnit.test('useAggregation option', function(assert) { @@ -1574,9 +1574,9 @@ QUnit.test('useAggregation option', function(assert) { }); // assert - assert.ok(series === chart.getAllSeries()[0], 'Series should be updated'); - assert.ok(valAxis === chart._valueAxes[0], 'Val axis should be updated'); - assert.ok(argAxis === chart._argumentAxes[0], 'Arg axis should be updated'); + assert.strictEqual(series, chart.getAllSeries()[0], 'Series should be updated'); + assert.strictEqual(valAxis, chart._valueAxes[0], 'Val axis should be updated'); + assert.strictEqual(argAxis, chart._argumentAxes[0], 'Arg axis should be updated'); }); QUnit.test('synchronizeMultiAxes option', function(assert) { @@ -1606,9 +1606,9 @@ QUnit.test('synchronizeMultiAxes option', function(assert) { // assert assert.equal(multiAxesSynchronizer.synchronize.callCount, 1); - assert.ok(series === chart.getAllSeries()[0], 'Series should be updated'); - assert.ok(valAxis === chart._valueAxes[0], 'Val axis should not be recreated'); - assert.ok(argAxis === chart._argumentAxes[0], 'Arg axis should not be recreated'); + assert.strictEqual(series, chart.getAllSeries()[0], 'Series should be updated'); + assert.strictEqual(valAxis, chart._valueAxes[0], 'Val axis should not be recreated'); + assert.strictEqual(argAxis, chart._argumentAxes[0], 'Arg axis should not be recreated'); }); QUnit.module('Change Strips of axes. Q499381', $.extend({}, commons.environment, { diff --git a/testing/tests/DevExpress.viz.charts/chart.part7.tests.js b/testing/tests/DevExpress.viz.charts/chart.part7.tests.js index 28681b316d35..e7f4d82112c7 100644 --- a/testing/tests/DevExpress.viz.charts/chart.part7.tests.js +++ b/testing/tests/DevExpress.viz.charts/chart.part7.tests.js @@ -1294,9 +1294,9 @@ $('
').appendTo('#qunit-fixture'); assert.strictEqual(this.labels[0].draw.callCount, 0); assert.deepEqual(this.labels[1].draw.lastCall.args, [false]); - assert.ok(series === chart.getAllSeries()[0], 'Series should not be recreated'); - assert.ok(valAxis === chart._valueAxes[0], 'Val axis should not be recreated'); - assert.ok(argAxis === chart._argumentAxes[0], 'Arg axis should not be recreated'); + assert.strictEqual(series, chart.getAllSeries()[0], 'Series should not be recreated'); + assert.strictEqual(valAxis, chart._valueAxes[0], 'Val axis should not be recreated'); + assert.strictEqual(argAxis, chart._argumentAxes[0], 'Arg axis should not be recreated'); }); QUnit.module('resolveLabelOverlapping. stack', $.extend({}, commons.environment, { diff --git a/testing/tests/DevExpress.viz.charts/chart.tests.js b/testing/tests/DevExpress.viz.charts/chart.tests.js index d666fa9458ce..82a03f4cf0f3 100644 --- a/testing/tests/DevExpress.viz.charts/chart.tests.js +++ b/testing/tests/DevExpress.viz.charts/chart.tests.js @@ -14,8 +14,8 @@ const Legend = vizMocks.Legend; const ChartTitle = vizMocks.Title; const Axis = vizMocks.stubClass(axisModule.Axis); const Range = vizMocks.stubClass(rangeModule.Range); -const dataSourceModule = require('data/data_source/data_source'); -const DataSource = vizMocks.stubClass(dataSourceModule.DataSource); +const DataSource = require('data/data_source/data_source').DataSource; +const DataSourceMock = vizMocks.stubClass(DataSource); require('viz/chart'); @@ -184,7 +184,7 @@ QUnit.test('Creation dataSource', function(assert) { this.options = { dataSource: [{}], series: [{}] }; const chart = this.createChart(); - assert.ok(chart.getDataSource() instanceof dataSourceModule.DataSource, 'dataSource created'); + assert.ok(chart.getDataSource() instanceof DataSource, 'dataSource created'); }); QUnit.test('Loading dataSource', function(assert) { @@ -197,7 +197,7 @@ QUnit.test('Loading dataSource', function(assert) { }); QUnit.test('dataSource instance', function(assert) { - const dataSource = new DataSource(); + const dataSource = new DataSourceMock(); this.options = { dataSource: dataSource, series: [{}] }; const chart = this.createChart(); @@ -255,7 +255,7 @@ QUnit.test('update with null dataSource', function(assert) { }); QUnit.test('changed event', function(assert) { - const dataSource = new DataSource(); + const dataSource = new DataSourceMock(); this.options = { dataSource: dataSource, series: [{}] }; this.createChart(); @@ -266,7 +266,7 @@ QUnit.test('changed event', function(assert) { }); QUnit.test('loadError event', function(assert) { - const dataSource = new DataSource(); + const dataSource = new DataSourceMock(); this.options = { dataSource: dataSource, series: [{}] }; this.createChart(); @@ -277,7 +277,7 @@ QUnit.test('loadError event', function(assert) { }); QUnit.test('disposing', function(assert) { - const dataSource = new DataSource(); + const dataSource = new DataSourceMock(); this.options = { dataSource: dataSource, series: [{}] }; const chart = this.createChart(); diff --git a/testing/tests/DevExpress.viz.charts/chartInteraction.tests.js b/testing/tests/DevExpress.viz.charts/chartInteraction.tests.js index c30f786e4b40..7bcf2c26326b 100644 --- a/testing/tests/DevExpress.viz.charts/chartInteraction.tests.js +++ b/testing/tests/DevExpress.viz.charts/chartInteraction.tests.js @@ -202,7 +202,7 @@ QUnit.test('useSpiderWeb option changing', function(assert) { polar.option('useSpiderWeb', true); assert.ok(polar.getAllSeries()[0].getOptions().spiderWidget); - assert.ok(initialSeries === polar.getAllSeries()[0]); + assert.strictEqual(initialSeries, polar.getAllSeries()[0]); }); // T738245 diff --git a/testing/tests/DevExpress.viz.charts/chartSync.tests.js b/testing/tests/DevExpress.viz.charts/chartSync.tests.js index 89d09446376d..04c83dacbaf0 100644 --- a/testing/tests/DevExpress.viz.charts/chartSync.tests.js +++ b/testing/tests/DevExpress.viz.charts/chartSync.tests.js @@ -847,9 +847,9 @@ const environment = { // assert assert.equal(chart.seriesFamiliesUpdatingOptions.equalBarWidth, true, 'series family should be updated'); - assert.ok(series === chart.getAllSeries()[0], 'Series should not be recreated'); - assert.ok(valAxis === chart._valueAxes[0], 'Val axis should not be recreated'); - assert.ok(argAxis === chart._argumentAxes[0], 'Arg axis should not be recreated'); + assert.strictEqual(series, chart.getAllSeries()[0], 'Series should not be recreated'); + assert.strictEqual(valAxis, chart._valueAxes[0], 'Val axis should not be recreated'); + assert.strictEqual(argAxis, chart._argumentAxes[0], 'Arg axis should not be recreated'); }); QUnit.test('T552944. Update series family and option that recreates series - series families are processed first', function(assert) { @@ -871,7 +871,7 @@ const environment = { equalBarWidth: true }); // assert - assert.ok(chart.getAllSeries() !== series, 'series recreated'); + assert.notStrictEqual(chart.getAllSeries(), series, 'series recreated'); }); QUnit.test('MinBubbleSize updating', function(assert) { @@ -900,9 +900,9 @@ const environment = { // assert assert.equal(chart.seriesFamiliesUpdatingOptions.minBubbleSize, 5, 'series family should be updated'); - assert.ok(series === chart.getAllSeries()[0], 'Series should not be recreated'); - assert.ok(valAxis === chart._valueAxes[0], 'Val axis should not be recreated'); - assert.ok(argAxis === chart._argumentAxes[0], 'Arg axis should not be recreated'); + assert.strictEqual(series, chart.getAllSeries()[0], 'Series should not be recreated'); + assert.strictEqual(valAxis, chart._valueAxes[0], 'Val axis should not be recreated'); + assert.strictEqual(argAxis, chart._argumentAxes[0], 'Arg axis should not be recreated'); }); QUnit.test('MaxBubbleSize updating', function(assert) { @@ -931,9 +931,9 @@ const environment = { // assert assert.equal(chart.seriesFamiliesUpdatingOptions.maxBubbleSize, 10, 'series family should be updated'); - assert.ok(series === chart.getAllSeries()[0], 'Series should not be recreated'); - assert.ok(valAxis === chart._valueAxes[0], 'Val axis should not be recreated'); - assert.ok(argAxis === chart._argumentAxes[0], 'Arg axis should not be recreated'); + assert.strictEqual(series, chart.getAllSeries()[0], 'Series should not be recreated'); + assert.strictEqual(valAxis, chart._valueAxes[0], 'Val axis should not be recreated'); + assert.strictEqual(argAxis, chart._argumentAxes[0], 'Arg axis should not be recreated'); }); QUnit.test('BarWidth updating', function(assert) { @@ -962,9 +962,9 @@ const environment = { // assert assert.equal(chart.seriesFamiliesUpdatingOptions.barWidth, 11, 'series family should be updated'); - assert.ok(series === chart.getAllSeries()[0], 'Series should not be recreated'); - assert.ok(valAxis === chart._valueAxes[0], 'Val axis should not be recreated'); - assert.ok(argAxis === chart._argumentAxes[0], 'Arg axis should not be recreated'); + assert.strictEqual(series, chart.getAllSeries()[0], 'Series should not be recreated'); + assert.strictEqual(valAxis, chart._valueAxes[0], 'Val axis should not be recreated'); + assert.strictEqual(argAxis, chart._argumentAxes[0], 'Arg axis should not be recreated'); }); QUnit.test('barGroupPadding updating', function(assert) { @@ -1040,9 +1040,9 @@ const environment = { // assert assert.equal(chart.seriesFamiliesUpdatingOptions.negativesAsZeroes, true, 'series family should be updated'); - assert.ok(series === chart.getAllSeries()[0], 'Series should not be recreated'); - assert.ok(valAxis === chart._valueAxes[0], 'Val axis should not be recreated'); - assert.ok(argAxis === chart._argumentAxes[0], 'Arg axis should not be recreated'); + assert.strictEqual(series, chart.getAllSeries()[0], 'Series should not be recreated'); + assert.strictEqual(valAxis, chart._valueAxes[0], 'Val axis should not be recreated'); + assert.strictEqual(argAxis, chart._argumentAxes[0], 'Arg axis should not be recreated'); }); const testEverythingWasDrawn = function(assert, chart, options) { diff --git a/testing/tests/DevExpress.viz.charts/pieChart.tests.js b/testing/tests/DevExpress.viz.charts/pieChart.tests.js index 7d5c66fe5299..06d1bf6179dd 100644 --- a/testing/tests/DevExpress.viz.charts/pieChart.tests.js +++ b/testing/tests/DevExpress.viz.charts/pieChart.tests.js @@ -488,7 +488,7 @@ const overlappingEnvironment = $.extend({}, environment, { }); // assert - assert.ok(oldSeries === commons.getTrackerStub(true).stub('updateSeries').lastCall.args[0]); + assert.strictEqual(oldSeries, commons.getTrackerStub(true).stub('updateSeries').lastCall.args[0]); }); QUnit.test('T400246. After series update tracker gets new series', function(assert) { @@ -510,7 +510,7 @@ const overlappingEnvironment = $.extend({}, environment, { }); // assert - assert.ok(oldSeries !== commons.getTrackerStub(true).stub('updateSeries').lastCall.args[0]); + assert.notStrictEqual(oldSeries, commons.getTrackerStub(true).stub('updateSeries').lastCall.args[0]); }); QUnit.test('create tracker, with series', function(assert) { diff --git a/testing/tests/DevExpress.viz.charts/themeManager.tests.js b/testing/tests/DevExpress.viz.charts/themeManager.tests.js index 66e6876073cb..eab25ebaa554 100644 --- a/testing/tests/DevExpress.viz.charts/themeManager.tests.js +++ b/testing/tests/DevExpress.viz.charts/themeManager.tests.js @@ -1777,7 +1777,7 @@ function createThemeManager(options, themeGroupName) { themeManager.resetOptions('firstLevelOption2'); - assert.ok(themeManager.getOptions('firstLevelOption2') !== result1); + assert.notStrictEqual(themeManager.getOptions('firstLevelOption2'), result1); assert.deepEqual(themeManager.getOptions('firstLevelObject'), result2); assert.strictEqual(themeManager.getOptions('firstLevelOption2'), 'new value'); diff --git a/testing/tests/DevExpress.viz.charts/tracker.tests.js b/testing/tests/DevExpress.viz.charts/tracker.tests.js index 08835dbacf47..2eeddad73c56 100644 --- a/testing/tests/DevExpress.viz.charts/tracker.tests.js +++ b/testing/tests/DevExpress.viz.charts/tracker.tests.js @@ -2208,23 +2208,15 @@ QUnit.test('mouseout from legend item', function(assert) { assert.strictEqual(this.series.notify.lastCall.args[0].target.getOptions().hoverMode, 'allargumentpoints'); }); -QUnit.test('mouseout from legend item', function(assert) { +QUnit.test('mousedown on legend item', function(assert) { this.legend.coordsIn.withArgs(97, 45).returns(true); this.legend.getItemByCoord.withArgs(97, 45).returns({ id: 0, argument: 'argument1', argumentIndex: 11 }); $(this.renderer.root.element).trigger(getEvent('dxpointermove', { pageX: 100, pageY: 50 })); - this.series.notify.reset(); + $(this.renderer.root.element).trigger(getEvent('dxpointerdown', { pageX: 100, pageY: 50 })); - $(this.renderer.root.element).trigger(getEvent('dxpointermove', { pageX: 80, pageY: 50 })); - - assert.strictEqual(this.series.notify.callCount, 1); - assert.strictEqual(this.series.notify.lastCall.args[0].action, 'clearPointHover'); - assert.strictEqual(this.series.notify.lastCall.args[0].notifyLegend, true); - assert.strictEqual(this.series.notify.lastCall.args[0].target.fullState, 0); - assert.strictEqual(this.series.notify.lastCall.args[0].target.argumentIndex, 11); - assert.strictEqual(this.series.notify.lastCall.args[0].target.argument, 'argument1'); - assert.strictEqual(this.series.notify.lastCall.args[0].target.getOptions().hoverMode, 'allargumentpoints'); + assert.strictEqual(this.series.notify.callCount, 0); }); QUnit.test('mouseout from chart after hover point on legend', function(assert) { diff --git a/testing/tests/DevExpress.viz.core.series/barPoint.tests.js b/testing/tests/DevExpress.viz.core.series/barPoint.tests.js index 94a71e891b24..354c1a396f65 100644 --- a/testing/tests/DevExpress.viz.core.series/barPoint.tests.js +++ b/testing/tests/DevExpress.viz.core.series/barPoint.tests.js @@ -1489,8 +1489,14 @@ QUnit.test('Get Graphic Settings', function(assert) { assert.equal(settings.width, 430); }); - -QUnit.module('Draw label', environment); +QUnit.module('Draw label', $.extend({}, environment, { + createPoint: function() { + const p = createPoint(this.series, this.data, this.options); + p._drawLabel(this.renderer, this.group); + p._label.draw.reset(); + return p; + } +})); QUnit.test('Value = null', function(assert) { this.data.value = null; @@ -1507,7 +1513,7 @@ QUnit.test('Value = null', function(assert) { }); QUnit.test('Get bbox for point', function(assert) { - const point = createPoint(this.series, this.data, this.options); + const point = this.createPoint(); point.x = 55; point.y = 40; @@ -1521,7 +1527,7 @@ QUnit.test('Get bbox for point', function(assert) { }); QUnit.test('Get bbox for point with border', function(assert) { - const point = createPoint(this.series, this.data, this.options); + const point = this.createPoint(); point.x = 50; point.y = 35; @@ -1534,7 +1540,7 @@ QUnit.test('Get bbox for point with border', function(assert) { }); QUnit.test('Default, not rotated', function(assert) { - const point = createPoint(this.series, this.data, this.options); + const point = this.createPoint(); const label = point._label; point.x = 33; @@ -1551,7 +1557,7 @@ QUnit.test('Default, not rotated', function(assert) { QUnit.test('Default, not rotated. Position is invalid', function(assert) { this.options.label.position = 'abc'; - const point = createPoint(this.series, this.data, this.options); + const point = this.createPoint(); const label = point._label; point.x = 33; @@ -1568,7 +1574,7 @@ QUnit.test('Default, not rotated. Position is invalid', function(assert) { QUnit.test('Default, not rotated with zero value', function(assert) { this.data.value = 0; - const point = createPoint(this.series, this.data, this.options); + const point = this.createPoint(); const label = point._label; point.x = 33; @@ -1584,7 +1590,7 @@ QUnit.test('Default, not rotated with zero value', function(assert) { QUnit.test('Default, not rotated with negative value', function(assert) { this.data.value = -15; - const point = createPoint(this.series, this.data, this.options); + const point = this.createPoint(); const label = point._label; point.x = 23; @@ -1601,7 +1607,7 @@ QUnit.test('Default, not rotated with negative value', function(assert) { QUnit.test('Default, not rotated fullstacked with negative value', function(assert) { this.data.value = -15; this.series.isFullStackedSeries = function() { return true; }; - const point = createPoint(this.series, this.data, this.options); + const point = this.createPoint(); const label = point._label; point.x = 23; @@ -1618,7 +1624,7 @@ QUnit.test('Default, not rotated fullstacked with negative value', function(asse QUnit.test('Default, not rotated fullstacked with zero value', function(assert) { this.data.value = 0; this.series.isFullStackedSeries = function() { return true; }; - const point = createPoint(this.series, this.data, this.options); + const point = this.createPoint(); const label = point._label; point.x = 33; @@ -1634,7 +1640,7 @@ QUnit.test('Default, not rotated fullstacked with zero value', function(assert) QUnit.test('Default, rotated', function(assert) { this.options.rotated = true; - const point = createPoint(this.series, this.data, this.options); + const point = this.createPoint(); const label = point._label; point.x = 53; @@ -1651,7 +1657,7 @@ QUnit.test('Default, rotated', function(assert) { QUnit.test('Default, rotated with zero value', function(assert) { this.options.rotated = true; this.data.value = 0; - const point = createPoint(this.series, this.data, this.options); + const point = this.createPoint(); const label = point._label; point.x = 55; @@ -1668,7 +1674,7 @@ QUnit.test('Default, rotated with zero value', function(assert) { QUnit.test('Default, rotated with negative value', function(assert) { this.options.rotated = true; this.data.value = -15; - const point = createPoint(this.series, this.data, this.options); + const point = this.createPoint(); const label = point._label; point.x = 43; @@ -1686,7 +1692,7 @@ QUnit.test('Default, rotated fullstacked with negative value', function(assert) this.options.rotated = true; this.data.value = -15; this.series.isFullStackedSeries = function() { return true; }; - const point = createPoint(this.series, this.data, this.options); + const point = this.createPoint(); const label = point._label; point.x = 43; @@ -1706,7 +1712,7 @@ QUnit.test('Default, rotated fullstacked with zero value', function(assert) { this.options.rotated = true; this.data.value = 0; this.series.isFullStackedSeries = function() { return true; }; - const point = createPoint(this.series, this.data, this.options); + const point = this.createPoint(); const label = point._label; point.x = 0; @@ -1723,7 +1729,7 @@ QUnit.test('Default, rotated fullstacked with zero value', function(assert) { QUnit.test('Default, label with zero value, showForZeroValues is true', function(assert) { this.data.value = 0; this.options.label.showForZeroValues = true; - const point = createPoint(this.series, this.data, this.options); + const point = this.createPoint(); point.x = 33; point.y = 22; @@ -1736,7 +1742,7 @@ QUnit.test('Default, label with zero value, showForZeroValues is true', function QUnit.test('Default, label with zero value, showForZeroValues is false', function(assert) { this.data.value = 0; this.options.label.showForZeroValues = false; - const point = createPoint(this.series, this.data, this.options); + const point = this.createPoint(); point._drawLabel(this.renderer, this.group); @@ -1748,7 +1754,7 @@ QUnit.test('Default, double draw, hidden to visible', function(assert) { this.options.resolveLabelsOverlapping = true; this.options.label.position = 'inside'; - const point = createPoint(this.series, this.data, this.options); + const point = this.createPoint(); const label = point._label; point.x = 33; @@ -1766,7 +1772,7 @@ QUnit.test('Default, double draw, hidden to visible', function(assert) { QUnit.test('Default, inside, not rotated', function(assert) { this.options.label.position = 'inside'; - const point = createPoint(this.series, this.data, this.options); + const point = this.createPoint(); const label = point._label; point.x = 33; @@ -1783,7 +1789,7 @@ QUnit.test('Default, inside, not rotated', function(assert) { QUnit.test('Default, inside, not rotated, label height > point height', function(assert) { this.options.label.position = 'inside'; this.label.getBoundingRect.returns({ width: 20, height: 12 }); - const point = createPoint(this.series, this.data, this.options); + const point = this.createPoint(); const label = point._label; point.x = 33; @@ -1804,7 +1810,7 @@ QUnit.test('Inside, label height > point height with resolveLabelsOverlapping - this.options.resolveLabelsOverlapping = true; this.options.label.position = 'inside'; - const point = createPoint(this.series, this.data, this.options); + const point = this.createPoint(); const label = point._label; point.x = 33; @@ -1823,7 +1829,7 @@ QUnit.test('Inside, label width > point width with resolveLabelsOverlapping - la this.options.resolveLabelsOverlapping = true; this.options.label.position = 'inside'; - const point = createPoint(this.series, this.data, this.options); + const point = this.createPoint(); const label = point._label; point.x = 33; @@ -1842,7 +1848,7 @@ QUnit.test('Outside, label width > point width with resolveLabelsOverlapping - l this.options.label.position = 'outside'; this.options.resolveLabelsOverlapping = true; - const point = createPoint(this.series, this.data, this.options); + const point = this.createPoint(); const label = point._label; point.x = 33; @@ -1864,7 +1870,7 @@ QUnit.test('Outside, label under the point, label width > point width with resol this.data.value = -20; this.options.resolveLabelsOverlapping = true; - const point = createPoint(this.series, this.data, this.options); + const point = this.createPoint(); const label = point._label; point.x = 33; @@ -1886,7 +1892,7 @@ QUnit.test('Outside, rotated, label height > point height with resolveLabelsOver this.options.rotated = true; this.options.label.position = 'outside'; - const point = createPoint(this.series, this.data, this.options); + const point = this.createPoint(); const label = point._label; point.x = 33; @@ -1909,7 +1915,7 @@ QUnit.test('Outside, rotated, label under the point, label height > point height this.data.value = -20; this.options.label.position = 'outside'; - const point = createPoint(this.series, this.data, this.options); + const point = this.createPoint(); const label = point._label; point.x = 33; @@ -1932,7 +1938,7 @@ QUnit.test('Label\'s border is equal of point\'s border', function(assert) { this.data.value = 20; this.options.label.position = 'inside'; - const point = createPoint(this.series, this.data, this.options); + const point = this.createPoint(); const label = point._label; point.x = 33; @@ -1953,7 +1959,7 @@ QUnit.test('Label\'s border is equal of point\'s border. Rotated chart', functio this.data.value = 20; this.options.label.position = 'inside'; - const point = createPoint(this.series, this.data, this.options); + const point = this.createPoint(); const label = point._label; point.x = 33; @@ -1971,7 +1977,7 @@ QUnit.test('Default, inside, not rotated with negative value', function(assert) this.label.getBoundingRect.returns({ width: 9, height: 6 }); this.options.label.position = 'inside'; this.data.value = -15; - const point = createPoint(this.series, this.data, this.options); + const point = this.createPoint(); const label = point._label; point.x = 23; @@ -1992,7 +1998,7 @@ QUnit.test('Default, inside, not rotated fullstacked with negative value', funct this.options.type = 'fullstackedbar'; this.data.value = -15; this.series.isFullStackedSeries = function() { return true; }; - const point = createPoint(this.series, this.data, this.options); + const point = this.createPoint(); const label = point._label; point.x = 23; @@ -2011,7 +2017,7 @@ QUnit.test('Default, inside, not rotated fullstacked with negative value', funct QUnit.test('Default, inside, rotated', function(assert) { this.options.label.position = 'inside'; this.options.rotated = true; - const point = createPoint(this.series, this.data, this.options); + const point = this.createPoint(); const label = point._label; point.x = 53; @@ -2029,7 +2035,7 @@ QUnit.test('Default, inside, not rotated, label width > point width', function(a this.label.getBoundingRect.returns({ width: 22, height: 10 }); this.options.label.position = 'inside'; this.options.rotated = true; - const point = createPoint(this.series, this.data, this.options); + const point = this.createPoint(); const label = point._label; point.x = 33; @@ -2049,7 +2055,7 @@ QUnit.test('Default, inside, rotated with negative value', function(assert) { this.options.label.position = 'inside'; this.data.value = -15; this.options.rotated = true; - const point = createPoint(this.series, this.data, this.options); + const point = this.createPoint(); const label = point._label; point.x = 43; @@ -2069,7 +2075,7 @@ QUnit.test('Default, inside, rotated fullstacked with negative value', function( this.data.value = -15; this.options.rotated = true; this.series.isFullStackedSeries = function() { return true; }; - const point = createPoint(this.series, this.data, this.options); + const point = this.createPoint(); const label = point._label; point.x = 43; @@ -2087,7 +2093,7 @@ QUnit.test('Default, inside, rotated fullstacked with negative value', function( QUnit.test('Inverted value axis, not rotated', function(assert) { this.translators.val.getBusinessRange = function() { return { invert: true }; }; - const point = createPoint(this.series, this.data, this.options); + const point = this.createPoint(); const label = point._label; point.x = 33; @@ -2104,7 +2110,7 @@ QUnit.test('Inverted value axis, not rotated', function(assert) { QUnit.test('Inverted value axis, rotated', function(assert) { this.options.rotated = true; this.translators.val.getBusinessRange = function() { return { invert: true }; }; - const point = createPoint(this.series, this.data, this.options); + const point = this.createPoint(); const label = point._label; point.x = 33; @@ -2121,7 +2127,7 @@ QUnit.test('Inverted value axis, rotated', function(assert) { QUnit.test('Inverted value axis, not rotated, negative value', function(assert) { this.data.value = -15; this.translators.val.getBusinessRange = function() { return { invert: true }; }; - const point = createPoint(this.series, this.data, this.options); + const point = this.createPoint(); const label = point._label; point.x = 33; @@ -2139,7 +2145,7 @@ QUnit.test('Inverted value axis, rotated, negative value', function(assert) { this.data.value = -15; this.options.rotated = true; this.translators.val.getBusinessRange = function() { return { invert: true }; }; - const point = createPoint(this.series, this.data, this.options); + const point = this.createPoint(); const label = point._label; point.x = 33; @@ -2155,7 +2161,7 @@ QUnit.test('Inverted value axis, rotated, negative value', function(assert) { QUnit.test('Value axis contains categories, not inverted, not rotated', function(assert) { this.series._options.valueAxisType = 'discrete'; - const point = createPoint(this.series, this.data, this.options); + const point = this.createPoint(); const label = point._label; point.x = 54; @@ -2172,7 +2178,7 @@ QUnit.test('Value axis contains categories, not inverted, not rotated', function QUnit.test('Value axis contains categories, inverted, not rotated', function(assert) { this.series._options.valueAxisType = 'discrete'; this.translators.val.getBusinessRange = function() { return { invert: true }; }; - const point = createPoint(this.series, this.data, this.options); + const point = this.createPoint(); const label = point._label; point.x = 54; @@ -2189,7 +2195,7 @@ QUnit.test('Value axis contains categories, inverted, not rotated', function(ass QUnit.test('Value axis contains categories, not inverted, rotated', function(assert) { this.series._options.valueAxisType = 'discrete'; this.options.rotated = true; - const point = createPoint(this.series, this.data, this.options); + const point = this.createPoint(); const label = point._label; point.x = 54; @@ -2207,7 +2213,7 @@ QUnit.test('Value axis contains categories, inverted, rotated', function(assert) this.series._options.valueAxisType = 'discrete'; this.options.rotated = true; this.translators.val.getBusinessRange = function() { return { invert: true }; }; - const point = createPoint(this.series, this.data, this.options); + const point = this.createPoint(); const label = point._label; point.x = 54; @@ -2273,34 +2279,34 @@ QUnit.test('Draw label, not rotated (area of label > maxX area of series)', func }); QUnit.test('Draw label, not rotated (area of label < minY area of series)', function(assert) { - const label = createLabel.call(this, { x: 60, y: 10, width: 20, height: 10 }); + const label = createLabel.call(this, { x: 60, y: 25, width: 20, height: 50 }); assert.equal(label.shift.firstCall.args[0], 60); - assert.equal(label.shift.firstCall.args[1], 20); + assert.equal(label.shift.firstCall.args[1], 35); }); QUnit.test('Draw label, not rotated (area of label > maxY area of series)', function(assert) { this.data.value = -10; - const label = createLabel.call(this, { x: 50, y: 205, width: 20, height: 10 }); + const label = createLabel.call(this, { x: 50, y: 120, width: 20, height: 85 }); assert.equal(label.shift.firstCall.args[0], 50); - assert.equal(label.shift.firstCall.args[1], 200); + assert.equal(label.shift.firstCall.args[1], 185); }); QUnit.test('Draw label, rotated (area of label < minX area of series)', function(assert) { this.data.value = -10; this.options.rotated = true; - const label = createLabel.call(this, { x: 30, y: 40, width: 20, height: 10 }); + const label = createLabel.call(this, { x: 35, y: 40, width: 50, height: 10 }); - assert.equal(label.shift.firstCall.args[0], 30); + assert.equal(label.shift.firstCall.args[0], 45); assert.equal(label.shift.firstCall.args[1], 40); }); QUnit.test('Draw label, rotated (area of label > maxX area of series)', function(assert) { this.options.rotated = true; - const label = createLabel.call(this, { x: 95, y: 40, width: 20, height: 10 }); + const label = createLabel.call(this, { x: 40, y: 40, width: 55, height: 10 }); - assert.equal(label.shift.firstCall.args[0], 80); + assert.equal(label.shift.firstCall.args[0], 65); assert.equal(label.shift.firstCall.args[1], 40); }); @@ -2341,13 +2347,13 @@ QUnit.test('Draw label, point is abroad on the top', function(assert) { assert.equal(label.shift.firstCall.args[1], 12); }); - QUnit.test('Draw label, point is abroad on the bottom', function(assert) { const label = createLabel.call(this, { x: 30, y: 220, width: 40, height: 10 }); assert.equal(label.shift.firstCall.args[0], 40); assert.equal(label.shift.firstCall.args[1], 200); }); + QUnit.module('API', { beforeEach: function() { this.opt = { @@ -2463,6 +2469,7 @@ function createLabel(pointBBox) { $.extend(point, pointBBox); + point._drawLabel(this.renderer, this.group); point.correctLabelPosition(label); return label; diff --git a/testing/tests/DevExpress.viz.core.series/barSeries.tests.js b/testing/tests/DevExpress.viz.core.series/barSeries.tests.js index 3d042762c7a8..8beee0a84025 100644 --- a/testing/tests/DevExpress.viz.core.series/barSeries.tests.js +++ b/testing/tests/DevExpress.viz.core.series/barSeries.tests.js @@ -948,7 +948,7 @@ QUnit.test('Hide visible series', function(assert) { const points = series.getPoints(); // see T243839 $.each(points, function(_, point) { - assert.ok(point._options.visible === false); + assert.strictEqual(point._options.visible, false); }); }); @@ -966,7 +966,7 @@ QUnit.test('Show invisible series', function(assert) { const points = series.getPoints(); // see T243839 $.each(points, function(_, point) { - assert.ok(point._options.visible === true); + assert.strictEqual(point._options.visible, true); }); }); diff --git a/testing/tests/DevExpress.viz.core.series/baseSeries.tests.js b/testing/tests/DevExpress.viz.core.series/baseSeries.tests.js index 6a0dc0c46a64..e84b2f16350d 100644 --- a/testing/tests/DevExpress.viz.core.series/baseSeries.tests.js +++ b/testing/tests/DevExpress.viz.core.series/baseSeries.tests.js @@ -3968,7 +3968,7 @@ QUnit.test('Hide visible series', function(assert) { // see T243839 $.each(series.getAllPoints(), function(_, point) { - assert.ok(point._options.visible !== false); + assert.notStrictEqual(point._options.visible, false); }); }); @@ -4046,7 +4046,7 @@ QUnit.test('Show invisible series', function(assert) { // see T243839 $.each(series.getAllPoints(), function(_, point) { - assert.ok(point._options.visible !== true); + assert.notStrictEqual(point._options.visible, true); }); }); diff --git a/testing/tests/DevExpress.viz.core.series/bubbleSeries.tests.js b/testing/tests/DevExpress.viz.core.series/bubbleSeries.tests.js index 5d6a81676099..42c8fd20e09d 100644 --- a/testing/tests/DevExpress.viz.core.series/bubbleSeries.tests.js +++ b/testing/tests/DevExpress.viz.core.series/bubbleSeries.tests.js @@ -767,7 +767,7 @@ QUnit.test('Hide visible series', function(assert) { const points = series.getPoints(); // see T243839 $.each(points, function(_, point) { - assert.ok(point._options.visible === false); + assert.strictEqual(point._options.visible, false); }); }); @@ -786,6 +786,6 @@ QUnit.test('Show invisible series', function(assert) { const points = series.getPoints(); // see T243839 $.each(points, function(_, point) { - assert.ok(point._options.visible === true); + assert.strictEqual(point._options.visible, true); }); }); diff --git a/testing/tests/DevExpress.viz.core.series/financialPoint.tests.js b/testing/tests/DevExpress.viz.core.series/financialPoint.tests.js index aaa056aff08c..0138920b4258 100644 --- a/testing/tests/DevExpress.viz.core.series/financialPoint.tests.js +++ b/testing/tests/DevExpress.viz.core.series/financialPoint.tests.js @@ -1858,7 +1858,10 @@ QUnit.module('Draw label', { }) }; this.sinonFactory = sinon.stub(labelModule, 'Label', function() { - return sinon.createStubInstance(originalLabel); + const label = sinon.createStubInstance(originalLabel); + label.getLayoutOptions.returns(that.options.label); + label.getBoundingRect.returns({ height: 10, width: 20 }); + return label; }); this.renderer = new vizMocks.Renderer(); this.renderer.bBoxTemplate = { x: 55, y: 40, height: 10, width: 20 }; @@ -1894,7 +1897,8 @@ QUnit.module('Draw label', { areLabelsVisible: function() { return true; }, getLabelVisibility: function() { return true; }, getValueAxis: function() { return { getTranslator: function() { return that.translators.val; } }; }, - getArgumentAxis: function() { return { getTranslator: function() { return that.translators.arg; } }; } + getArgumentAxis: function() { return { getTranslator: function() { return that.translators.arg; } }; }, + getVisibleArea: function() { return { minX: 0, maxX: 200, minY: 0, maxY: 210 }; }, }; }, afterEach: function() { @@ -2103,6 +2107,37 @@ QUnit.test('Draw label. Candlestick', function(assert) { assert.deepEqual(point._label.draw.lastCall.args, [true]); }); +QUnit.test('Draw label, not rotated (area of label < minY area of series)', function(assert) { + const point = createPoint(this.series, this.data, this.options); + point.x = 50; + point.highY = 15; + point.lowY = 60; + point.width = 20; + const label = point._label; + + point._drawLabel(this.renderer, this.group); + point.correctLabelPosition(label); + + assert.equal(label.shift.firstCall.args[0], 40); + assert.equal(label.shift.firstCall.args[1], 25); +}); + +QUnit.test('Draw label, rotated (area of label > maxX area of series)', function(assert) { + this.options.rotated = true; + const point = createPoint(this.series, this.data, this.options); + point.x = 50; + point.highY = 200; + point.lowY = 60; + point.width = 20; + const label = point._label; + + point._drawLabel(this.renderer, this.group); + point.correctLabelPosition(label); + + assert.equal(label.shift.firstCall.args[0], 170); + assert.equal(label.shift.firstCall.args[1], 45); +}); + QUnit.module('get point radius', { beforeEach: function() { this.renderer = new vizMocks.Renderer(); diff --git a/testing/tests/DevExpress.viz.core.series/financialSeries.tests.js b/testing/tests/DevExpress.viz.core.series/financialSeries.tests.js index 52dd0980e508..128ccd5741d9 100644 --- a/testing/tests/DevExpress.viz.core.series/financialSeries.tests.js +++ b/testing/tests/DevExpress.viz.core.series/financialSeries.tests.js @@ -1493,7 +1493,7 @@ const checkGroups = function(assert, series) { const points = series.getPoints(); // see T243839 $.each(points, function(_, point) { - assert.ok(point._options.visible === false); + assert.strictEqual(point._options.visible, false); }); }); @@ -1513,7 +1513,7 @@ const checkGroups = function(assert, series) { const points = series.getPoints(); // see T243839 $.each(points, function(_, point) { - assert.ok(point._options.visible === true); + assert.strictEqual(point._options.visible, true); }); }); })(); diff --git a/testing/tests/DevExpress.viz.core/export.integration.tests.js b/testing/tests/DevExpress.viz.core/export.integration.tests.js index 66a19e861baf..f52249693205 100644 --- a/testing/tests/DevExpress.viz.core/export.integration.tests.js +++ b/testing/tests/DevExpress.viz.core/export.integration.tests.js @@ -412,10 +412,10 @@ QUnit.test('Export menu creation', function(assert) { // assert assert.equal(exportModule.ExportMenu.lastCall.args[0].renderer, this.renderer); - assert.ok(typeof exportModule.ExportMenu.lastCall.args[0].incidentOccurred === 'function'); + assert.strictEqual(typeof exportModule.ExportMenu.lastCall.args[0].incidentOccurred, 'function'); assert.strictEqual(this.exportMenu.setOptions.getCall(0).args[0].rtl, 'rtl option'); - assert.ok(typeof exportModule.ExportMenu.lastCall.args[0].exportTo === 'function'); - assert.ok(typeof exportModule.ExportMenu.lastCall.args[0].print === 'function'); + assert.strictEqual(typeof exportModule.ExportMenu.lastCall.args[0].exportTo, 'function'); + assert.strictEqual(typeof exportModule.ExportMenu.lastCall.args[0].print, 'function'); exportModule.ExportMenu.lastCall.args[0].exportTo('FORMAT'); assert.deepEqual(widget.exportTo.getCall(0).args, [undefined, 'FORMAT']); diff --git a/testing/tests/DevExpress.viz.core/legend.tests.js b/testing/tests/DevExpress.viz.core/legend.tests.js index cdaa5886858c..f02df703a992 100644 --- a/testing/tests/DevExpress.viz.core/legend.tests.js +++ b/testing/tests/DevExpress.viz.core/legend.tests.js @@ -2494,6 +2494,20 @@ QUnit.test('Shift simple title; itemTextPosition = \'bottom\'', function(assert) assert.deepEqual(this.title.shift.lastCall.args, [2, 2], 'title must have moved'); }); +// T854736 +QUnit.test('Shift legend with title after erase. Title position - bottom', function(assert) { + this.options.title = { text: 'Simple title', verticalAlignment: 'bottom' }; + + this.titleLayout.width = 16; + + const legend = this.createSimpleLegend(); + legend.draw(200, 200); + legend.erase(); + legend.shift(0, 0); + assert.deepEqual(this.title.shift.lastCall.args, [0, 2], 'title must have moved'); +}); + + QUnit.test('Shift simple title; horizontalAlignment = \'right\' verticalAlignment = \'top\' title.horizontalAlignment = \'center\'; margins not zero', function(assert) { this.options.title = { text: 'Simple title', diff --git a/testing/tests/DevExpress.viz.core/loadingIndicator.integration.tests.js b/testing/tests/DevExpress.viz.core/loadingIndicator.integration.tests.js index 2fb77d4b1cab..f7475593d21a 100644 --- a/testing/tests/DevExpress.viz.core/loadingIndicator.integration.tests.js +++ b/testing/tests/DevExpress.viz.core/loadingIndicator.integration.tests.js @@ -28,8 +28,8 @@ QUnit.test('Show', function(assert) { const params = loadingIndicatorModule.LoadingIndicator.lastCall.args[0]; assert.ok(params.renderer, 'param - renderer'); - assert.ok(typeof params.eventTrigger === 'function', 'param - event trigger'); - assert.ok(typeof params.notify === 'function', 'param - notify'); + assert.strictEqual(typeof params.eventTrigger, 'function', 'param - event trigger'); + assert.strictEqual(typeof params.notify, 'function', 'param - notify'); assert.deepEqual(this.loadingIndicator.setSize.lastCall.args, [{ width: 600, height: 400, left: 0, top: 0, right: 0, bottom: 0 }], 'canvas'); assert.deepEqual(this.loadingIndicator.setOptions.lastCall.args[0].text, 'Some text', 'options'); assert.deepEqual(this.loadingIndicator.show.lastCall.args, [], 'show'); diff --git a/testing/tests/DevExpress.viz.core/title.integration.tests.js b/testing/tests/DevExpress.viz.core/title.integration.tests.js index 2245e9ab3025..09ad95c4a549 100644 --- a/testing/tests/DevExpress.viz.core/title.integration.tests.js +++ b/testing/tests/DevExpress.viz.core/title.integration.tests.js @@ -23,7 +23,7 @@ QUnit.test('Creation', function(assert) { const params = titleModule.Title.lastCall.args[0]; assert.ok(params.renderer, 'param - renderer'); - assert.ok(typeof params.incidentOccurred === 'function', 'param - incident occurred'); + assert.strictEqual(typeof params.incidentOccurred, 'function', 'param - incident occurred'); assert.strictEqual(params.cssClass, 'dxtm-title', 'param - css class'); }); diff --git a/testing/tests/DevExpress.viz.core/tooltip.integration.tests.js b/testing/tests/DevExpress.viz.core/tooltip.integration.tests.js index edd08750bf34..154fe538a3dc 100644 --- a/testing/tests/DevExpress.viz.core/tooltip.integration.tests.js +++ b/testing/tests/DevExpress.viz.core/tooltip.integration.tests.js @@ -27,7 +27,7 @@ QUnit.test('Creation', function(assert) { const params = tooltipModule.Tooltip.lastCall.args[0]; assert.strictEqual(params.cssClass, 'dxtm-tooltip', 'param - css class'); assert.strictEqual(params.pathModified, 'pathModified-option', 'param - path modified'); - assert.ok(typeof params.eventTrigger === 'function', 'param - event trigger'); + assert.strictEqual(typeof params.eventTrigger, 'function', 'param - event trigger'); assert.equal(params.widgetRoot, this.widget.element()); }); diff --git a/testing/tests/DevExpress.viz.core/xyAxes.tests.js b/testing/tests/DevExpress.viz.core/xyAxes.tests.js index af7fb0956a7c..4e9b00d0afea 100644 --- a/testing/tests/DevExpress.viz.core/xyAxes.tests.js +++ b/testing/tests/DevExpress.viz.core/xyAxes.tests.js @@ -690,7 +690,7 @@ QUnit.test('IncidentOccured on measure labels', function(assert) { axis.setMarginOptions({ checkInterval: true }); axis.measureLabels(this.canvas); - assert.ok(this.tickGenerator.lastCall.args[0].incidentOccurred !== this.incidentOccurred); + assert.notStrictEqual(this.tickGenerator.lastCall.args[0].incidentOccurred, this.incidentOccurred); }); QUnit.test('call measure labels after axis draw - use ticks generated on draw', function(assert) { diff --git a/testing/tests/DevExpress.viz.gauges/baseGauge.tests.js b/testing/tests/DevExpress.viz.gauges/baseGauge.tests.js index 755982243192..755fbf37df0f 100644 --- a/testing/tests/DevExpress.viz.gauges/baseGauge.tests.js +++ b/testing/tests/DevExpress.viz.gauges/baseGauge.tests.js @@ -154,8 +154,8 @@ QUnit.test('Components creation', function(assert) { // assert.deepEqual(factory.createLayoutManager.lastCall.args, [], "layout manager"); const arg = this.tracker.setCallbacks.lastCall.args[0]; - assert.ok(typeof arg['tooltip-show'] === 'function', 'show callback'); - assert.ok(typeof arg['tooltip-hide'] === 'function', 'hide callback'); + assert.strictEqual(typeof arg['tooltip-show'], 'function', 'show callback'); + assert.strictEqual(typeof arg['tooltip-hide'], 'function', 'hide callback'); }); QUnit.test('Components disposing', function(assert) { diff --git a/testing/tests/DevExpress.viz.gauges/common.tests.js b/testing/tests/DevExpress.viz.gauges/common.tests.js index dc9f0b23cb7f..2b1f55b71e98 100644 --- a/testing/tests/DevExpress.viz.gauges/common.tests.js +++ b/testing/tests/DevExpress.viz.gauges/common.tests.js @@ -592,7 +592,7 @@ QUnit.test('Value indicators are rendered in hard mode', function(assert) { }), 'value indicator 3 options'); assert.strictEqual(gauge._valueIndicators[2].previousValue, -50, 'value is set - 3'); assert.strictEqual(gauge._valueIndicators[2].value(), 30, 'value is set - 3'); - assert.ok(typeof gauge.indicatorValue === 'function', 'indicatorValue method is available'); + assert.strictEqual(typeof gauge.indicatorValue, 'function', 'indicatorValue method is available'); }); QUnit.test('Value indicators are rendered - not valid types', function(assert) { @@ -1401,7 +1401,7 @@ QUnit.test('indicatorValue - set, not valid', function(assert) { QUnit.test('indicatorValue - not in hard mode', function(assert) { const gauge = this.createTestGauge(); - assert.ok(gauge.valueIndicator === undefined, 'method is not available'); + assert.strictEqual(gauge.valueIndicator, undefined, 'method is not available'); }); QUnit.module('Gauge - options changing support', environment); diff --git a/testing/tests/DevExpress.viz.rangeSelector/common.part1.tests.js b/testing/tests/DevExpress.viz.rangeSelector/common.part1.tests.js index d03e5fdcc44c..8f67f9e2a78a 100644 --- a/testing/tests/DevExpress.viz.rangeSelector/common.part1.tests.js +++ b/testing/tests/DevExpress.viz.rangeSelector/common.part1.tests.js @@ -1,6 +1,6 @@ const $ = require('jquery'); const trackerModule = require('viz/range_selector/tracker'); -const dataSourceModule = require('data/data_source/data_source'); +const DataSource = require('data/data_source/data_source').DataSource; const seriesDataSourceModule = require('viz/range_selector/series_data_source'); const commons = require('./rangeSelectorParts/commons.js'); @@ -223,7 +223,7 @@ QUnit.test('Creation', function(assert) { const widget = this.createWidget({ dataSource: [1, 2, 3] }); const ds = widget.getDataSource(); - assert.ok(ds instanceof dataSourceModule.DataSource); + assert.ok(ds instanceof DataSource); assert.deepEqual(ds.items(), [1, 2, 3]); }); @@ -239,7 +239,7 @@ QUnit.module('isReady', $.extend({}, commons.environment, { })); QUnit.test('dataSource is not loaded', function(assert) { - const ds = new dataSourceModule.DataSource(); + const ds = new DataSource(); ds.isLoaded = sinon.stub().returns(false); const rangeSelector = this.createWidget({ dataSource: ds }); @@ -248,7 +248,7 @@ QUnit.test('dataSource is not loaded', function(assert) { }); QUnit.test('dataSource is loaded', function(assert) { - const ds = new dataSourceModule.DataSource(); + const ds = new DataSource(); ds.isLoaded = sinon.stub().returns(true); const rangeSelector = this.createWidget({ dataSource: ds }); diff --git a/testing/tests/DevExpress.viz.rangeSelector/common.part3.tests.js b/testing/tests/DevExpress.viz.rangeSelector/common.part3.tests.js index 9fe11c729f59..6753d4b50870 100644 --- a/testing/tests/DevExpress.viz.rangeSelector/common.part3.tests.js +++ b/testing/tests/DevExpress.viz.rangeSelector/common.part3.tests.js @@ -3,7 +3,7 @@ import baseWidgetModule from 'viz/core/base_widget'; import commons from './rangeSelectorParts/commons.js'; import slidersControllerModule from 'viz/range_selector/sliders_controller'; import seriesDataSourceModule from 'viz/range_selector/series_data_source'; -import dataSourceModule from 'data/data_source/data_source'; +import { DataSource } from 'data/data_source/data_source'; import dateLocalization from 'localization/date'; import axisModule from 'viz/axes/base_axis'; @@ -1660,7 +1660,7 @@ QUnit.test('dataSource creation', function(assert) { }); const ds = widget.getDataSource(); - assert.ok(ds instanceof dataSourceModule.DataSource); + assert.ok(ds instanceof DataSource); assert.ok(ds.isLoaded()); assert.deepEqual(ds.items(), [{}]); }); diff --git a/testing/tests/DevExpress.viz.renderers/Animation.tests.js b/testing/tests/DevExpress.viz.renderers/Animation.tests.js index 41b3f1cc14b0..74a081f3a13e 100644 --- a/testing/tests/DevExpress.viz.renderers/Animation.tests.js +++ b/testing/tests/DevExpress.viz.renderers/Animation.tests.js @@ -529,7 +529,7 @@ const vizMocks = require('../../helpers/vizMocks.js'); // Assert assert.ok(new Date() - animation._startTime < 1000); assert.strictEqual(result, true); - assert.ok(firstTick !== secondTick); + assert.notStrictEqual(firstTick, secondTick); }); diff --git a/testing/tests/DevExpress.viz.renderers/SvgElement.tests.js b/testing/tests/DevExpress.viz.renderers/SvgElement.tests.js index b5ffde41315f..c33baa012a44 100644 --- a/testing/tests/DevExpress.viz.renderers/SvgElement.tests.js +++ b/testing/tests/DevExpress.viz.renderers/SvgElement.tests.js @@ -523,7 +523,7 @@ function checkDashStyle(assert, elem, result, style, value) { markupString = svg.markup(); // assert - assert.ok(markupString.indexOf('&<>  ©Ø') !== -1); + assert.notStrictEqual(markupString.indexOf('&<>  ©Ø'), -1); }); QUnit.test('Change multiple entries of entity to numeric code', function(assert) { @@ -537,7 +537,7 @@ function checkDashStyle(assert, elem, result, style, value) { markupString = svg.markup(); // assert - assert.ok(markupString.indexOf('1 2 3') !== -1); + assert.notStrictEqual(markupString.indexOf('1 2 3'), -1); }); QUnit.module('SvgElement jQuery API', { @@ -5925,7 +5925,7 @@ function checkDashStyle(assert, elem, result, style, value) { assert.deepEqual(result, { rowCount: 3, textChanged: true, textIsEmpty: false }); - assert.ok(text.element.childNodes[1].textContent.indexOf('...') !== -1); + assert.notStrictEqual(text.element.childNodes[1].textContent.indexOf('...'), -1); assert.ok(text.getBBox().width <= 110); }); @@ -6122,7 +6122,7 @@ function checkDashStyle(assert, elem, result, style, value) { wordWrap: 'normal', textOverflow: 'ellipsis' }); - assert.ok(text.getBBox().height !== 0); + assert.notStrictEqual(text.getBBox().height, 0); }); QUnit.test('Set max height. TextOverflow = \'none\'. Show all texts ', function(assert) { @@ -6137,7 +6137,7 @@ function checkDashStyle(assert, elem, result, style, value) { textOverflow: 'none' }); - assert.ok(text.getBBox().height !== 0); + assert.notStrictEqual(text.getBBox().height, 0); }); QUnit.test('Set max height. textOverflow ellipsis. multi line text, Last text width less than maxWidth - add ... at the end', function(assert) { diff --git a/testing/tests/DevExpress.viz.sankey/sankey.base.tests.js b/testing/tests/DevExpress.viz.sankey/sankey.base.tests.js index 1efee554bd06..e80cd6fc712f 100644 --- a/testing/tests/DevExpress.viz.sankey/sankey.base.tests.js +++ b/testing/tests/DevExpress.viz.sankey/sankey.base.tests.js @@ -454,7 +454,7 @@ QUnit.test('Returning correct links[].connection data in getAllLinks', function( const output = find(links, function(i) { return i.connection.source === linkData.source && i.connection.target === linkData.target && i.connection.weight === linkData.weight; }); - assert.ok(typeof output !== 'undefined'); + assert.notStrictEqual(typeof output, 'undefined'); }); }); diff --git a/testing/tests/DevExpress.viz.sparklines/baseSparklineTooltipEvents.tests.js b/testing/tests/DevExpress.viz.sparklines/baseSparklineTooltipEvents.tests.js index a66a7eeca11a..0e48f7516c4b 100644 --- a/testing/tests/DevExpress.viz.sparklines/baseSparklineTooltipEvents.tests.js +++ b/testing/tests/DevExpress.viz.sparklines/baseSparklineTooltipEvents.tests.js @@ -3,10 +3,7 @@ const $ = require('jquery'); const vizMocks = require('../../helpers/vizMocks.js'); const rendererModule = require('viz/core/renderers/renderer'); -const baseSparkline = require('viz/sparklines/base_sparkline'); -const eventsEngine = require('events/core/events_engine'); -const devices = require('core/devices'); -const DEFAULT_EVENTS_DELAY = 100; +const pointerEvents = require('events/pointer'); require('viz/sparkline'); @@ -29,15 +26,12 @@ QUnit.begin(function() { const environment = { beforeEach: function() { - baseSparkline._DEBUG_reset(); - // this._originalRendererType = dxSparkline.prototype._rendererType; this.$container = $(createTestContainer('#container')); this.createSparkline = function(options) { return this.$container.dxSparkline(options).dxSparkline('instance'); }; - // dxSparkline.prototype._rendererType = vizMocks.Renderer; - this.triggerDocument = function(name) { - const event = $.Event(name); + this.triggerDocument = function(name, target, x, y) { + const event = $.Event(name, { pageX: x, pageY: y }); // Because of ui.events.js event.changedTouches = [{}]; @@ -53,420 +47,85 @@ const environment = { target.trigger(event); this.triggerDocument.apply(this, arguments); // Bubbling emulation }; - - this.clock = sinon.useFakeTimers(); }, afterEach: function() { - this.clock.restore(); - // dxSparkline.prototype._rendererType = this._originalRendererType; this.$container.remove(); } }; - -QUnit.module('Tooltip events on non-touch device', environment); - -QUnit.test('Mouseover after delay', function(assert) { - assert.expect(1); - const sparkline = this.createSparkline({ - dataSource: [4, 8, 6, 9, 5], - tooltip: { - enabled: true - } - }); - - sparkline._DEBUG_showCallback = function() { - assert.ok(true, 'Show timeout set 1 time'); - }; - - this.trigger('mouseover', sparkline._tooltipTracker); -}); - -QUnit.test('Mousemove with big distance', function(assert) { - assert.expect(1); - const tooltipShown = sinon.spy(); - const sparkline = this.createSparkline({ - dataSource: [4, 8, 6, 9, 5], - tooltip: { - enabled: true - }, - onTooltipShown: tooltipShown - }); - const tracker = sparkline._tooltipTracker; - - this.trigger('mouseover', tracker, 5, 5); - - this.trigger('mousemove', tracker, 10, 5); - this.trigger('mousemove', tracker, 10, 20); - this.trigger('mousemove', tracker, 30, 10); - this.trigger('mousemove', tracker, 40, 5); - assert.equal(tooltipShown.callCount, 1); -}); - -QUnit.test('Mousemove with small distance', function(assert) { - assert.expect(1); - const tooltipShown = sinon.spy(); - const sparkline = this.createSparkline({ - dataSource: [4, 8, 6, 9, 5], - tooltip: { - enabled: true - }, - onTooltipShown: tooltipShown - }); - const tracker = sparkline._tooltipTracker; - - this.trigger('mouseover', tracker, 5, 5); - - this.trigger('mousemove', tracker, 7, 5); - this.trigger('mousemove', tracker, 7, 3); - this.trigger('mousemove', tracker, 4, 3); - this.trigger('mousemove', tracker, 4, 6); - assert.equal(tooltipShown.callCount, 1); -}); - -QUnit.test('Quick mouseout after mouseover', function(assert) { - assert.expect(1); - const sparkline = this.createSparkline({ - dataSource: [4, 8, 6, 9, 5], - tooltip: { - enabled: true - } - }); - const tracker = sparkline._tooltipTracker; - - sparkline._DEBUG_clearShowTooltipTimeout = 0; - - this.trigger('mouseover', tracker); - this.trigger('mouseout', tracker); - this.clock.tick(DEFAULT_EVENTS_DELAY); - - assert.equal(sparkline._DEBUG_clearShowTooltipTimeout, 1, 'Clear show tooltip timeout 1 time'); -}); - -QUnit.test('Mouseout after mouseover', function(assert) { - assert.expect(1); - const sparkline = this.createSparkline({ - dataSource: [4, 8, 6, 9, 5], - tooltip: { - enabled: true - } - }); - const tracker = sparkline._tooltipTracker; - const that = this; - - sparkline._DEBUG_hideTooltipTimeoutSet = 0; - sparkline._DEBUG_showCallback = function() { - that.trigger('mouseout', tracker); - that.clock.tick(DEFAULT_EVENTS_DELAY); - }; - sparkline._DEBUG_hideCallback = function() { - assert.equal(sparkline._DEBUG_hideTooltipTimeoutSet, 1, 'Hide timeout set 1 time'); - }; - that.trigger('mouseover', tracker); -}); - -QUnit.test('Hide tooltip on scroll without delay', function(assert) { - const originalPlatform = devices.real().platform; - - try { - devices.real({ platform: 'generic' }); - assert.expect(2); - const sparkline = this.createSparkline({ - dataSource: [4, 8, 6, 9, 5], - tooltip: { - enabled: true - }, - onTooltipHidden: function() { - assert.ok(true); - } +QUnit.module('Tooltip events', environment); + +function createTest(name, actions, asserts) { + ['down', 'move'].forEach(act => { + QUnit.test(`${name}. pointer${act}`, function(assert) { + const tooltipShown = sinon.spy(); + const tooltipHidden = sinon.spy(); + const sparkline = this.createSparkline({ + dataSource: [4, 8, 5], + tooltip: { + enabled: true + }, + onTooltipShown: tooltipShown, + onTooltipHidden: tooltipHidden + }); + + actions.arrange.call(this, pointerEvents[act], sparkline._tooltipTracker); + + // act + actions.act.call(this, pointerEvents[act], sparkline._tooltipTracker); + + // assert + assert.strictEqual(tooltipShown.callCount, asserts.tooltipShownCallCount); + assert.strictEqual(tooltipHidden.callCount, asserts.tooltipHiddenCallCount); }); - const tracker = sparkline._tooltipTracker; - const that = this; + }); +} - sparkline._DEBUG_hideTooltipTimeoutSet = 0; - sparkline._DEBUG_hideCallback = function() { - assert.equal(sparkline._DEBUG_hideTooltipTimeoutSet, 0, 'Hide timeout set 1 time'); - }; - that.trigger('mouseover', tracker); - eventsEngine.trigger(sparkline.$element(), 'scroll'); - } finally { - devices.real({ platform: originalPlatform }); +createTest('Tooltip showing', { + arrange() { }, + act(act, tracker) { + this.trigger(act, tracker, 10, 15); } +}, { + tooltipShownCallCount: 1, + tooltipHiddenCallCount: 0 }); -QUnit.test('Should not crash on parent scroll if tooltip was not shown', function(assert) { - const originalPlatform = devices.real().platform; - - try { - devices.real({ platform: 'generic' }); - assert.expect(0); - const sparkline = this.createSparkline({ - dataSource: [4, 8, 6, 9, 5], - tooltip: { - enabled: true - } - }); - - eventsEngine.trigger(sparkline.$element(), 'scroll'); - } finally { - devices.real({ platform: originalPlatform }); +createTest('Tooltip hiding after move pointer outside canvas', { + arrange(act, tracker) { + this.trigger(act, tracker, 10, 15); + }, + act(act, tracker) { + this.trigger(act, tracker, 1000, 1000); } +}, { + tooltipShownCallCount: 1, + tooltipHiddenCallCount: 1 }); -QUnit.test('B252494 - Tooltip exception', function(assert) { - assert.expect(2); - const sparkline = this.createSparkline({ - dataSource: [4, 8, 6, 9, 5], - tooltip: { - enabled: true - } - }); - const tracker = sparkline._tooltipTracker; - const that = this; - - sparkline._DEBUG_hideTooltipTimeoutSet = 0; - sparkline._DEBUG_showCallback = function() { - sparkline.option('type', null); - that.trigger('mouseout', tracker); - that.clock.tick(DEFAULT_EVENTS_DELAY); - }; - sparkline._DEBUG_hideCallback = function(tooltipWasShowed) { - assert.equal(sparkline._DEBUG_hideTooltipTimeoutSet, 1, 'Hide timeout set 1 time'); - assert.ok(!tooltipWasShowed, 'Tooltip is not showed'); - }; - that.trigger('mouseover', tracker); - -}); - -QUnit.test('Dispose after show - B252555', function(assert) { - assert.expect(1); - const sparkline = this.createSparkline({ - dataSource: [4, 8, 6, 9, 5] - }); - const tracker = sparkline._tooltipTracker; - const that = this; - - sparkline._DEBUG_hideTooltipTimeoutSet = 0; - - sparkline._DEBUG_showCallback = function() { - that.trigger('mouseout', tracker); - $(that.$container).remove(); - that.clock.tick(DEFAULT_EVENTS_DELAY); - assert.equal(sparkline._DEBUG_hideTooltipTimeoutSet, 1, 'Hide timeout set 1 time'); - }; - - sparkline._DEBUG_hideCallback = function() { - assert.ok(false); - }; - - that.trigger('mouseover', tracker); -}); - -QUnit.test('Dispose after hide - B252555', function(assert) { - assert.expect(1); - const sparkline = this.createSparkline({ - dataSource: [4, 8, 6, 9, 5] - }); - const tracker = sparkline._tooltipTracker; - const that = this; - - sparkline._DEBUG_hideTooltipTimeoutSet = 0; - - sparkline._DEBUG_showCallback = function() { - that.trigger('mouseout', tracker); - that.clock.tick(DEFAULT_EVENTS_DELAY); - }; - - sparkline._DEBUG_hideCallback = function() { - sparkline._DEBUG_showCallback = function() { - assert.ok(false); - }; - - $(that.$container).remove(); - that.trigger('mouseover', tracker); - assert.equal(sparkline._DEBUG_hideTooltipTimeoutSet, 1, 'Hide timeout set 1 time'); - }; - - that.trigger('mouseover', tracker); -}); - -QUnit.module('Tooltip events on touch device', environment); - -QUnit.test('Touchstart', function(assert) { - assert.expect(1); +QUnit.test('No events hendling after dispose', function(assert) { const tooltipShown = sinon.spy(); + const tooltipHidden = sinon.spy(); const sparkline = this.createSparkline({ - dataSource: [4, 8, 6, 9, 5], + dataSource: [4, 8, 5], tooltip: { enabled: true }, - onTooltipShown: tooltipShown + onTooltipShown: tooltipShown, + onTooltipHidden: tooltipHidden }); - const tracker = sparkline._tooltipTracker; - - this.trigger('touchstart', tracker); - assert.equal(tooltipShown.callCount, 1); -}); - -QUnit.test('Pointerdown', function(assert) { - assert.expect(1); - const tooltipShown = sinon.spy(); - const sparkline = this.createSparkline({ - dataSource: [4, 8, 6, 9, 5], - tooltip: { - enabled: true - }, - onTooltipShown: tooltipShown - }); const tracker = sparkline._tooltipTracker; + this.trigger(pointerEvents.move, tracker, 10, 15); + tooltipShown.reset(); - this.trigger('pointerdown', tracker); - assert.equal(tooltipShown.callCount, 1); -}); + // act + this.$container.remove(); -QUnit.test('Quick touchend', function(assert) { - assert.expect(1); - const sparkline = this.createSparkline({ - dataSource: [4, 8, 6, 9, 5], - tooltip: { - enabled: true - } - }); - const tracker = sparkline._tooltipTracker; - - sparkline._DEBUG_hideTooltipTimeoutSet = 0; - - sparkline._DEBUG_hideCallback = function() { - assert.equal(sparkline._DEBUG_hideTooltipTimeoutSet, 1, 'hide timeout set 1 time'); - }; - - this.trigger('touchstart', tracker); - this.triggerDocument('touchend'); - this.clock.tick(DEFAULT_EVENTS_DELAY); -}); - -QUnit.test('Quick pointerup', function(assert) { - assert.expect(1); - const sparkline = this.createSparkline({ - dataSource: [4, 8, 6, 9, 5], - tooltip: { - enabled: true - } - }); - const tracker = sparkline._tooltipTracker; - - sparkline._DEBUG_hideTooltipTimeoutSet = 0; - - sparkline._DEBUG_hideCallback = function() { - assert.equal(sparkline._DEBUG_hideTooltipTimeoutSet, 1, 'hide timeout set 1 time'); - }; - - this.trigger('pointerdown', tracker); - this.triggerDocument('pointerup'); - this.clock.tick(DEFAULT_EVENTS_DELAY); -}); - -QUnit.test('Touchstart in another place', function(assert) { - assert.expect(1); - const sparkline = this.createSparkline({ - dataSource: [4, 8, 6, 9, 5], - tooltip: { - enabled: true - } - }); - const tracker = sparkline._tooltipTracker; - const that = this; - - sparkline._DEBUG_hideTooltipTimeoutSet = 0; - - sparkline._DEBUG_showCallback = function() { - that.triggerDocument('touchstart'); - that.clock.tick(DEFAULT_EVENTS_DELAY); - }; - - sparkline._DEBUG_hideCallback = function() { - assert.equal(sparkline._DEBUG_hideTooltipTimeoutSet, 1, 'hide timeout set 1 time'); - }; - - this.trigger('touchstart', tracker); - this.clock.tick(DEFAULT_EVENTS_DELAY); -}); - -QUnit.test('Pointerdown in another place', function(assert) { - assert.expect(1); - const sparkline = this.createSparkline({ - dataSource: [4, 8, 6, 9, 5], - tooltip: { - enabled: true - } - }); - const tracker = sparkline._tooltipTracker; - const that = this; - - sparkline._DEBUG_hideTooltipTimeoutSet = 0; - - sparkline._DEBUG_showCallback = function() { - that.triggerDocument('pointerdown'); - that.clock.tick(DEFAULT_EVENTS_DELAY); - }; - - sparkline._DEBUG_hideCallback = function() { - assert.equal(sparkline._DEBUG_hideTooltipTimeoutSet, 1, 'hide timeout set 1 time'); - }; - - this.trigger('pointerdown', tracker); - this.clock.tick(DEFAULT_EVENTS_DELAY); -}); - -QUnit.test('Touchstart on document after tooltip showing', function(assert) { - assert.expect(1); - const sparkline = this.createSparkline({ - dataSource: [4, 8, 6, 9, 5], - tooltip: { - enabled: true - } - }); - const tracker = sparkline._tooltipTracker; - const that = this; - - sparkline._DEBUG_hideTooltipTimeoutSet = 0; - - sparkline._DEBUG_showCallback = function() { - that.triggerDocument('touchstart'); - that.clock.tick(DEFAULT_EVENTS_DELAY); - }; - - sparkline._DEBUG_hideCallback = function() { - assert.equal(sparkline._DEBUG_hideTooltipTimeoutSet, 1, 'hide timeout set 1 time'); - }; - - this.trigger('touchstart', tracker); - this.clock.tick(DEFAULT_EVENTS_DELAY); -}); - -QUnit.test('Pointerdown on document after tooltip showing', function(assert) { - assert.expect(1); - const sparkline = this.createSparkline({ - dataSource: [4, 8, 6, 9, 5], - tooltip: { - enabled: true - } - }); - const tracker = sparkline._tooltipTracker; - const that = this; - - sparkline._DEBUG_hideTooltipTimeoutSet = 0; - - sparkline._DEBUG_showCallback = function() { - that.triggerDocument('pointerdown'); - that.clock.tick(DEFAULT_EVENTS_DELAY); - }; - - sparkline._DEBUG_hideCallback = function() { - assert.equal(sparkline._DEBUG_hideTooltipTimeoutSet, 1, 'hide timeout set 1 time'); - }; + this.triggerDocument(pointerEvents.move); + this.triggerDocument(pointerEvents.down); - this.trigger('pointerdown', tracker); - this.clock.tick(DEFAULT_EVENTS_DELAY); + // assert + assert.strictEqual(tooltipShown.callCount, 0); + assert.strictEqual(tooltipHidden.callCount, 0); }); diff --git a/testing/tests/DevExpress.viz.sparklines/bullet.tests.js b/testing/tests/DevExpress.viz.sparklines/bullet.tests.js index 8a277a664c3c..5c5eb238663a 100644 --- a/testing/tests/DevExpress.viz.sparklines/bullet.tests.js +++ b/testing/tests/DevExpress.viz.sparklines/bullet.tests.js @@ -958,7 +958,7 @@ QUnit.test('B239673 - Tooltip does not update location after resize', function(a target: 8 }); - bullet._showTooltipCallback(); + bullet._showTooltip(); bullet._tooltip.hide = sinon.spy(); this.resetTranslators(); diff --git a/testing/tests/DevExpress.viz.sparklines/bulletTooltip.tests.js b/testing/tests/DevExpress.viz.sparklines/bulletTooltip.tests.js index de66f705a358..230c8f59f378 100644 --- a/testing/tests/DevExpress.viz.sparklines/bulletTooltip.tests.js +++ b/testing/tests/DevExpress.viz.sparklines/bulletTooltip.tests.js @@ -73,7 +73,7 @@ QUnit.test('Enabled tooltip', function(assert) { enabled: true } }); - bullet._showTooltipCallback(); + bullet._showTooltip(); const arg = bullet._tooltip.ctorArgs; assert.strictEqual(arg.length, 1); @@ -101,7 +101,7 @@ QUnit.test('Enabled tooltip. Empty data', function(assert) { enabled: true } }); - bullet._showTooltipCallback(); + bullet._showTooltip(); const arg = bullet._tooltip.ctorArgs; assert.strictEqual(arg.length, 1); @@ -129,7 +129,7 @@ QUnit.test('Disabled tooltip', function(assert) { } }); - bullet._showTooltipCallback(); + bullet._showTooltip(); assert.equal(bullet._tooltip.update.callCount, 1, 'update is called'); assert.equal(bullet._tooltip.update.lastCall.args[0].enabled, false); @@ -143,7 +143,7 @@ QUnit.test('dxBullet get TooltipFormatObject', function(assert) { enabled: true } }); - bullet._showTooltipCallback(); + bullet._showTooltip(); assert.deepEqual(bullet._tooltip.show.lastCall.args, [{ originalTarget: 20, @@ -168,7 +168,7 @@ QUnit.test('Default Tooltip text', function(assert) { } }); - bullet._showTooltipCallback(); + bullet._showTooltip(); bullet._tooltip.formatValue = function(value, format) { return value; }; const ctResult = bullet._tooltip.update.lastCall.args[0].customizeTooltip(bullet._getTooltipData()); @@ -189,7 +189,7 @@ QUnit.test('Default Tooltip text. Rtl', function(assert) { rtlEnabled: true }); - bullet._showTooltipCallback(); + bullet._showTooltip(); bullet._tooltip.formatValue = function(value, format) { return value; }; const ctResult = bullet._tooltip.update.lastCall.args[0].customizeTooltip(bullet._getTooltipData()); diff --git a/testing/tests/DevExpress.viz.sparklines/sparkline.tests.js b/testing/tests/DevExpress.viz.sparklines/sparkline.tests.js index af56cf628ff3..a87ce6850a50 100644 --- a/testing/tests/DevExpress.viz.sparklines/sparkline.tests.js +++ b/testing/tests/DevExpress.viz.sparklines/sparkline.tests.js @@ -8,7 +8,7 @@ const rendererModule = require('viz/core/renderers/renderer'); const dataValidatorModule = require('viz/components/data_validator'); const translator2DModule = require('viz/translators/translator2d'); const seriesModule = require('viz/series/base_series'); -const dataSourceModule = require('data/data_source/data_source'); +const DataSource = require('data/data_source/data_source').DataSource; require('viz/sparkline'); @@ -1927,7 +1927,7 @@ QUnit.begin(function() { const sparkline = this.createSparkline({ dataSource: [4] }); - sparkline._showTooltipCallback(); + sparkline._showTooltip(); sparkline.option('size', { width: 300, height: 100 }); assert.ok(sparkline._tooltip.hide.calledOnce, 'Tooltip should be hidden'); @@ -2082,7 +2082,7 @@ QUnit.begin(function() { beforeEach: function() { environment.beforeEach.call(this); sinon.stub(BaseWidget.prototype, '_drawn', sinon.spy()); - this.data = new dataSourceModule.DataSource(); + this.data = new DataSource(); this.isLoadedStub = sinon.stub(this.data, 'isLoaded'); }, afterEach: function() { @@ -2127,7 +2127,7 @@ QUnit.begin(function() { }); QUnit.test('isReady with not loaded dataSource', function(assert) { - const data = new dataSourceModule.DataSource(); + const data = new DataSource(); sinon.stub(data, 'isLoaded', function() { return false; }); const sparkline = this.createSparkline({ dataSource: data }); @@ -2158,7 +2158,7 @@ QUnit.begin(function() { const widget = this.createSparkline({ dataSource: [1, 2, 3] }); const ds = widget.getDataSource(); - assert.ok(ds instanceof dataSourceModule.DataSource); + assert.ok(ds instanceof DataSource); assert.ok(ds.isLoaded()); assert.deepEqual(ds.items(), [1, 2, 3]); }); diff --git a/testing/tests/DevExpress.viz.sparklines/sparklineTooltip.tests.js b/testing/tests/DevExpress.viz.sparklines/sparklineTooltip.tests.js index 046bb564e9ff..5ef856836298 100644 --- a/testing/tests/DevExpress.viz.sparklines/sparklineTooltip.tests.js +++ b/testing/tests/DevExpress.viz.sparklines/sparklineTooltip.tests.js @@ -74,7 +74,7 @@ QUnit.test('Enabled tooltip', function(assert) { enabled: true } }); - sparkline._showTooltipCallback(); + sparkline._showTooltip(); const arg = sparkline._tooltip.ctorArgs; assert.strictEqual(arg.length, 1); @@ -102,7 +102,7 @@ QUnit.test('Enabled tooltip. Empty data', function(assert) { enabled: true } }); - sparkline._showTooltipCallback(); + sparkline._showTooltip(); const arg = sparkline._tooltip.ctorArgs; assert.strictEqual(arg.length, 1); @@ -129,7 +129,7 @@ QUnit.test('Disabled tooltip', function(assert) { } }); - sparkline._showTooltipCallback(); + sparkline._showTooltip(); assert.equal(sparkline._tooltip.update.callCount, 1, 'update is called'); assert.equal(sparkline._tooltip.update.lastCall.args[0].enabled, false); @@ -143,7 +143,7 @@ QUnit.test('Tooltip when datasource is empty', function(assert) { } }); - sparkline._showTooltipCallback(); + sparkline._showTooltip(); assert.equal(sparkline._tooltip.update.callCount, 1, 'update is called'); assert.equal(sparkline._tooltip.update.lastCall.args[0].enabled, false); @@ -164,7 +164,7 @@ QUnit.test('customizeTooltip does not return html or text', function(assert) { } }); - sparkline._showTooltipCallback(); + sparkline._showTooltip(); const ct = sparkline._tooltip.update.lastCall.args[0].customizeTooltip; @@ -189,7 +189,7 @@ QUnit.test('customizeTooltip return html', function(assert) { } }); - sparkline._showTooltipCallback(); + sparkline._showTooltip(); const ct = sparkline._tooltip.update.lastCall.args[0].customizeTooltip; @@ -214,7 +214,7 @@ QUnit.test('customizeTooltip return text', function(assert) { } }); - sparkline._showTooltipCallback(); + sparkline._showTooltip(); const ct = sparkline._tooltip.update.lastCall.args[0].customizeTooltip; @@ -239,7 +239,7 @@ QUnit.test('customizeTooltip is not function', function(assert) { } }); - sparkline._showTooltipCallback(); + sparkline._showTooltip(); const ct = sparkline._tooltip.update.lastCall.args[0].customizeTooltip; @@ -258,7 +258,7 @@ QUnit.test('Default customizeTooltip callback. Custom linespacing', function(ass } }); - sparkline._showTooltipCallback(); + sparkline._showTooltip(); const ct = sparkline._tooltip.update.lastCall.args[0].customizeTooltip; @@ -276,7 +276,7 @@ QUnit.test('dxSparkline get TooltipFormatObject', function(assert) { enabled: true } }); - sparkline._showTooltipCallback(); + sparkline._showTooltip(); assert.deepEqual(sparkline._tooltip.show.lastCall.args, [{ firstValue: '4:undefined', @@ -303,7 +303,7 @@ QUnit.test('sparkline tooltip format object. min/max values when all values are } }); - sparkline._showTooltipCallback(); + sparkline._showTooltip(); assert.strictEqual(sparkline._tooltip.show.lastCall.args[0].originalMinValue, 0); assert.strictEqual(sparkline._tooltip.show.lastCall.args[0].originalMaxValue, 0); @@ -319,7 +319,7 @@ QUnit.test('Default Tooltip text', function(assert) { enabled: true } }); - sparkline._showTooltipCallback(); + sparkline._showTooltip(); sparkline._tooltip.formatValue = function(value, format) { return value; }; const ctResult = sparkline._tooltip.update.lastCall.args[0].customizeTooltip(sparkline._getTooltipData()); @@ -344,7 +344,7 @@ QUnit.test('Default Tooltip text. Rtl', function(assert) { }, rtlEnabled: true }); - sparkline._showTooltipCallback(); + sparkline._showTooltip(); sparkline._tooltip.formatValue = function(value, format) { return value; }; const ctResult = sparkline._tooltip.update.lastCall.args[0].customizeTooltip(sparkline._getTooltipData()); @@ -368,7 +368,7 @@ QUnit.test('Winloss sparkline get TooltipFormatObject', function(assert) { enabled: true } }); - sparkline._showTooltipCallback(); + sparkline._showTooltip(); assert.deepEqual(sparkline._tooltip.show.lastCall.args, [{ diff --git a/testing/tests/DevExpress.viz.vectorMap/mapLayer.tests.js b/testing/tests/DevExpress.viz.vectorMap/mapLayer.tests.js index bb709a013b05..8853ab1e5209 100644 --- a/testing/tests/DevExpress.viz.vectorMap/mapLayer.tests.js +++ b/testing/tests/DevExpress.viz.vectorMap/mapLayer.tests.js @@ -11,7 +11,7 @@ let stubSelectStrategy; let StubMapLayerElement; let StubProxy; const projectionModule = require('viz/vector_map/projection.main'); -const dataSourceModule = require('data/data_source/data_source'); +const DataSource = require('data/data_source/data_source').DataSource; const baseThemeManagerModule = require('viz/core/base_theme_manager'); const vizMocks = require('../../helpers/vizMocks.js'); @@ -140,7 +140,7 @@ QUnit.test('dataSource creation', function(assert) { this.layer.setOptions({ dataSource: [{}] }); assert.ok(this.layer.getDataSource(), 'getDataSource method is work'); - assert.ok(this.layer.getDataSource() instanceof dataSourceModule.DataSource); + assert.ok(this.layer.getDataSource() instanceof DataSource); assert.deepEqual(this.layer.getDataSource().items(), [{}], 'data source items'); }); @@ -225,8 +225,8 @@ QUnit.test('Set options with data, load error', function(assert) { const labelRoot = this.context.labelRoot = new vizMocks.Element(); this.context.grouping = { g1: 1, g2: 2 }; - const DataSource = vizMocks.stubClass(dataSourceModule.DataSource); - const ds = new DataSource(); + const DataSourceMock = vizMocks.stubClass(DataSource); + const ds = new DataSourceMock(); this.layer.setOptions({ dataSource: ds diff --git a/testing/tests/DevExpress.viz.vectorMap/mapLayer_new.tests.js b/testing/tests/DevExpress.viz.vectorMap/mapLayer_new.tests.js index c6d0c5976bef..801205c14b8b 100644 --- a/testing/tests/DevExpress.viz.vectorMap/mapLayer_new.tests.js +++ b/testing/tests/DevExpress.viz.vectorMap/mapLayer_new.tests.js @@ -7,7 +7,7 @@ const controlBarModule = require('viz/vector_map/control_bar'); const legendModule = require('viz/vector_map/legend'); const tooltipModule = require('viz/core/tooltip'); const tooltipViewerModule = require('viz/vector_map/tooltip_viewer'); -const dataSourceModule = require('data/data_source/data_source'); +const DataSource = require('data/data_source/data_source').DataSource; const exportMenuModule = require('viz/core/export'); // TODO maybe if you test layer - you should create exact layer? const rendererModule = require('viz/core/renderers/renderer'); @@ -481,7 +481,7 @@ QUnit.test('Change name of one layer', function(assert) { const updatedLayers = map.getLayers(); updatedLayers.forEach(function(l, i) { - assert.ok(l !== oldLayers[i]); + assert.notStrictEqual(l, oldLayers[i]); }); }); @@ -493,7 +493,7 @@ QUnit.test('Layers shouldn\'t be created on updating when name not set', functio const oldLayer = map.getLayers()[0]; map.option('layers', [{ color: 'some_color_1' }]); - assert.ok(map.getLayers()[0] === oldLayer); + assert.strictEqual(map.getLayers()[0], oldLayer); }); QUnit.test('No crush on updating when on of layer in null', function(assert) { @@ -567,7 +567,7 @@ QUnit.test('getDataSource method', function(assert) { ]) }); - assert.ok(map.getLayers()[0].getDataSource() instanceof dataSourceModule.DataSource); + assert.ok(map.getLayers()[0].getDataSource() instanceof DataSource); }); QUnit.test('Bounds calculation', function(assert) { diff --git a/testing/tests/DevExpress.viz.vectorMap/projection.tests.js b/testing/tests/DevExpress.viz.vectorMap/projection.tests.js index 5a6c2c7c617b..8b0a00248f56 100644 --- a/testing/tests/DevExpress.viz.vectorMap/projection.tests.js +++ b/testing/tests/DevExpress.viz.vectorMap/projection.tests.js @@ -1273,7 +1273,7 @@ QUnit.test('bounds', function(assert) { const newProj = proj.bounds([10, 20, 30, 40]); assert.ok(newProj instanceof projectionModule._TESTS_Engine, 'instance type'); - assert.ok(newProj !== proj, 'not same instance'); + assert.notStrictEqual(newProj, proj, 'not same instance'); assert.strictEqual(newProj.original(), proj, 'original'); assert.strictEqual(newProj.ar(), 3, 'ar'); }); @@ -1292,7 +1292,7 @@ QUnit.test('aspectRatio', function(assert) { const newProj = proj.aspectRatio(4); assert.ok(newProj instanceof projectionModule._TESTS_Engine, 'instance type'); - assert.ok(newProj !== proj, 'not same instance'); + assert.notStrictEqual(newProj, proj, 'not same instance'); assert.strictEqual(newProj.original(), proj, 'original'); assert.strictEqual(newProj.ar(), 4, 'ar'); assert.deepEqual(newProj.project([10, 20]), proj.project([10, 20]), 'project'); diff --git a/testing/tests/DevExpress.viz.vectorMap/tracker.tests.js b/testing/tests/DevExpress.viz.vectorMap/tracker.tests.js index 28422fc28fd3..3ef846d1f42e 100644 --- a/testing/tests/DevExpress.viz.vectorMap/tracker.tests.js +++ b/testing/tests/DevExpress.viz.vectorMap/tracker.tests.js @@ -156,7 +156,7 @@ QUnit.test('Subscription to projection', function(assert) { const arg = this.projection.on.lastCall.args[0]; assert.strictEqual(typeof arg.center, 'function', 'center handler'); assert.strictEqual(typeof arg.zoom, 'function', 'zoom handler'); - assert.ok(arg.center === arg.zoom, 'same handler for both events'); + assert.strictEqual(arg.center, arg.zoom, 'same handler for both events'); }); QUnit.test('Event emitter methods are injected', function(assert) { diff --git a/testing/tests/DevExpress/misc.tests.js b/testing/tests/DevExpress/misc.tests.js index cf65095b96cc..a3e0d72fb2b2 100644 --- a/testing/tests/DevExpress/misc.tests.js +++ b/testing/tests/DevExpress/misc.tests.js @@ -83,9 +83,13 @@ QUnit.module('uncleared timers detection', { const log = this.log.get(); assert.strictEqual(Object.keys(log.timeouts).length, 1); - assert.strictEqual(log.timeouts[0].callback, callback.toString()); - assert.strictEqual(log.timeouts[0].timeout, 123); - assert.ok(log.timeouts[0].stack.indexOf('codeThatSchedulesTimer') > -1); + + const timerInfo = log.timeouts[0]; + assert.strictEqual(timerInfo.timerType, 'timeouts'); + assert.strictEqual(timerInfo.timerId, 0); + assert.strictEqual(timerInfo.callback, callback.toString()); + assert.strictEqual(timerInfo.timeout, 123); + assert.ok(timerInfo.stack.indexOf('codeThatSchedulesTimer') > -1); }); QUnit.test('expired setTimeout', function(assert) { @@ -116,9 +120,13 @@ QUnit.module('uncleared timers detection', { const log = this.log.get(); assert.strictEqual(Object.keys(log.intervals).length, 1); - assert.strictEqual(log.intervals[0].callback, callback.toString()); - assert.strictEqual(log.intervals[0].timeout, 321); - assert.ok(log.intervals[0].stack.indexOf('codeThatSchedulesTimer') > -1); + + const timerInfo = log.intervals[0]; + assert.strictEqual(timerInfo.timerType, 'intervals'); + assert.strictEqual(timerInfo.timerId, 0); + assert.strictEqual(timerInfo.callback, callback.toString()); + assert.strictEqual(timerInfo.timeout, 321); + assert.ok(timerInfo.stack.indexOf('codeThatSchedulesTimer') > -1); }); QUnit.test('uncleared requestAnimationFrame', function(assert) { @@ -130,8 +138,12 @@ QUnit.module('uncleared timers detection', { const log = this.log.get(); assert.strictEqual(Object.keys(log.animationFrames).length, 1); - assert.strictEqual(log.animationFrames[0].callback, callback.toString()); - assert.ok(log.animationFrames[0].stack.indexOf('codeThatSchedulesTimer') > -1); + + const timerInfo = log.animationFrames[0]; + assert.strictEqual(timerInfo.timerType, 'animationFrames'); + assert.strictEqual(timerInfo.timerId, 0); + assert.strictEqual(timerInfo.callback, callback.toString()); + assert.ok(timerInfo.stack.indexOf('codeThatSchedulesTimer') > -1); }); QUnit.test('cleared setTimeout', function(assert) { diff --git a/themebuilder/modules/less-template-loader.js b/themebuilder/modules/less-template-loader.js index 3ee3417fa105..9413fcb78bbd 100644 --- a/themebuilder/modules/less-template-loader.js +++ b/themebuilder/modules/less-template-loader.js @@ -50,10 +50,11 @@ class LessMetadataPreCompiler { } class LessMetadataPostCompiler { - constructor(compiledMetadata, swatchSelector, colorScheme) { + constructor(compiledMetadata, swatchSelector, colorScheme, noClean) { this._metadata = compiledMetadata; this.swatchSelector = swatchSelector; this.colorScheme = colorScheme; + this.useCleanCss = !noClean; } process(css) { @@ -81,7 +82,9 @@ class LessMetadataPostCompiler { .replace(themeMarkerRegex, '$1' + this.colorScheme + '$3'); } - css = new CleanCss(cleanCssOptions).minify(css).styles; + if(this.useCleanCss) { + css = new CleanCss(cleanCssOptions).minify(css).styles; + } return css.replace(metadataRegex, ''); } @@ -110,6 +113,7 @@ class LessTemplateLoader { this.swatchSelector = config.makeSwatch ? SWATCH_SELECTOR_PREFIX + config.outColorScheme : ''; this.outColorScheme = config.outColorScheme; this.version = version; + this.noClean = config.noClean; } load(theme, colorScheme, metadata, modifiedItems, widgets) { @@ -157,7 +161,7 @@ class LessTemplateLoader { }; const preCompiler = new LessMetadataPreCompiler(metadata, this.swatchSelector, modifyVars); - const postCompiler = new LessMetadataPostCompiler(compiledMetadata, this.swatchSelector, this.outColorScheme); + const postCompiler = new LessMetadataPostCompiler(compiledMetadata, this.swatchSelector, this.outColorScheme, this.noClean); less = preCompiler.process(less); diff --git a/themebuilder/tests/builder-spec.js b/themebuilder/tests/builder-spec.js index b790c8bf0995..38eee93b37cc 100644 --- a/themebuilder/tests/builder-spec.js +++ b/themebuilder/tests/builder-spec.js @@ -116,8 +116,9 @@ describe('Builder - testing exported function', () => { assert.ok(themeBuilderCss === distributionCss); }); }).timeout(buildTimeout); +}); - +describe('Check if all widgets can be compiled separately', () => { ['generic.light', 'material.blue.light'].forEach(theme => { const ModulesHandler = require('../modules/modules-handler'); const themesFileContent = fs.readFileSync(path.join(__dirname, '../../styles/theme.less'), 'utf8'); @@ -131,7 +132,8 @@ describe('Builder - testing exported function', () => { lessCompiler: lessCompiler, items: [], baseTheme: theme, - widgets: [widgetName] + widgets: [widgetName], + noClean: true }; it(`We can build bundle for every widget (${theme}, ${widgetName})`, () => { @@ -139,10 +141,9 @@ describe('Builder - testing exported function', () => { assert.isString(result.css, `${widgetName} bundle builded`); assert.deepEqual(result.widgets, [ widgetName ]); }); - }); + }).timeout(buildTimeout); }); }); - }); diff --git a/themebuilder/tests/less-template-loader-spec.js b/themebuilder/tests/less-template-loader-spec.js index c466af0858d3..8f8e074079f8 100644 --- a/themebuilder/tests/less-template-loader-spec.js +++ b/themebuilder/tests/less-template-loader-spec.js @@ -588,4 +588,42 @@ describe('LessTemplateLoader', () => { assert.equal(data.version, version); }); }); + + it('clean-css works with noClean = false', () => { + const config = { + isBootstrap: false, + lessCompiler: lessCompiler, + reader: path => { + assert.equal(path, 'devextreme-themebuilder/data/less/bundles/dx.light.less'); + return new Promise(resolve => { + resolve('@base-bg: #fff;@base-font-family:\'default\';@base-text-color:#0f0;div { font: 14px/1 DXIcons; font-size: 20px; line-height: 20px; }'); + }); + } + }; + + const lessTemplateLoader = new LessTemplateLoader(config); + + config.noClean = true; + const lessTemplateLoaderNoClean = new LessTemplateLoader(config); + + lessTemplateLoaderNoClean._makeInfoHeader = emptyHeader; + lessTemplateLoader._makeInfoHeader = emptyHeader; + + const testCases = [{ + loader: lessTemplateLoader, + expected: 'div {\n font: 20px/20px DXIcons;\n}' + }, { + loader: lessTemplateLoaderNoClean, + expected: 'div {\n font: 14px/1 DXIcons;\n font-size: 20px;\n line-height: 20px;\n}\n' + }]; + + const promises = testCases.map(testCase => testCase.loader.load( + themeName, + colorScheme, + metadata, + [] + ).then(data => assert.equal(data.css, testCase.expected))); + + return Promise.all(promises); + }); }); diff --git a/ts/dx.all.d.ts b/ts/dx.all.d.ts index ba2d0c4be7f7..0d60d9a8f585 100644 --- a/ts/dx.all.d.ts +++ b/ts/dx.all.d.ts @@ -1574,7 +1574,21 @@ declare module DevExpress.events { /** @name events.triggerHandler(element, event, extraParameters) */ export function triggerHandler(element: Element | Array, event: string | event, extraParameters: any): void; } -declare module DevExpress.exporter { +declare module DevExpress.excelExporter { + /** @name CellAddress */ + export interface CellAddress { + /** @name CellAddress.column */ + column?: number; + /** @name CellAddress.row */ + row?: number; + } + /** @name CellRange */ + export interface CellRange { + /** @name CellRange.from */ + from?: CellAddress; + /** @name CellRange.to */ + to?: CellAddress; + } /** @name ExcelDataGridCell */ export interface ExcelDataGridCell { /** @name ExcelDataGridCell.column */ @@ -1592,6 +1606,50 @@ declare module DevExpress.exporter { /** @name ExcelDataGridCell.value */ value?: any; } + /** @name ExportDataGridProps */ + export interface ExportDataGridProps { + /** @name ExportDataGridProps.autoFilterEnabled */ + autoFilterEnabled?: boolean; + /** @name ExportDataGridProps.component */ + component?: DevExpress.ui.dxDataGrid; + /** @name ExportDataGridProps.customizeCell */ + customizeCell?: ((options: { gridCell?: ExcelDataGridCell, excelCell?: any }) => any); + /** @name ExportDataGridProps.keepColumnWidths */ + keepColumnWidths?: boolean; + /** @name ExportDataGridProps.loadPanel */ + loadPanel?: ExportLoadPanel; + /** @name ExportDataGridProps.selectedRowsOnly */ + selectedRowsOnly?: boolean; + /** @name ExportDataGridProps.topLeftCell */ + topLeftCell?: CellAddress; + /** @name ExportDataGridProps.worksheet */ + worksheet?: any; + } + /** @name ExportLoadPanel */ + export interface ExportLoadPanel { + /** @name ExportLoadPanel.enabled */ + enabled?: boolean; + /** @name ExportLoadPanel.height */ + height?: number; + /** @name ExportLoadPanel.indicatorSrc */ + indicatorSrc?: string; + /** @name ExportLoadPanel.shading */ + shading?: boolean; + /** @name ExportLoadPanel.shadingColor */ + shadingColor?: string; + /** @name ExportLoadPanel.showIndicator */ + showIndicator?: boolean; + /** @name ExportLoadPanel.showPane */ + showPane?: boolean; + /** @name ExportLoadPanel.text */ + text?: string; + /** @name ExportLoadPanel.width */ + width?: number; + } + /** @name excelExporter.exportDataGrid(options) */ + export function exportDataGrid(options: ExportDataGridProps): Promise & JQueryPromise; +} +declare module DevExpress.exporter { /** @name ExcelFont */ export interface ExcelFont { /** @name ExcelFont.bold */ @@ -1608,93 +1666,132 @@ declare module DevExpress.exporter { underline?: 'double' | 'doubleAccounting' | 'none' | 'single' | 'singleAccounting'; } } -declare module DevExpress.fileProvider { - /** @name AjaxFileProvider.Options */ - export interface AjaxFileProviderOptions extends FileProviderOptions { - /** @name AjaxFileProvider.Options.itemsExpr */ - itemsExpr?: string | Function; - /** @name AjaxFileProvider.Options.url */ - url?: string; - } - /** @name AjaxFileProvider */ - export class AjaxFileProvider extends FileProvider { - constructor(options?: AjaxFileProviderOptions) - } - /** @name ArrayFileProvider.Options */ - export interface ArrayFileProviderOptions extends FileProviderOptions { - /** @name ArrayFileProvider.Options.contentExpr */ - contentExpr?: string | Function; - /** @name ArrayFileProvider.Options.data */ - data?: Array; - /** @name ArrayFileProvider.Options.itemsExpr */ - itemsExpr?: string | Function; - } - /** @name ArrayFileProvider */ - export class ArrayFileProvider extends FileProvider { - constructor(options?: ArrayFileProviderOptions) - } - /** @name CustomFileProvider.Options */ - export interface CustomFileProviderOptions extends FileProviderOptions { - /** @name CustomFileProvider.Options.abortFileUpload */ - abortFileUpload?: Function; - /** @name CustomFileProvider.Options.copyItem */ - copyItem?: Function; - /** @name CustomFileProvider.Options.createDirectory */ - createDirectory?: Function; - /** @name CustomFileProvider.Options.deleteItem */ - deleteItem?: Function; - /** @name CustomFileProvider.Options.downloadItems */ - downloadItems?: Function; - /** @name CustomFileProvider.Options.getItems */ - getItems?: Function; - /** @name CustomFileProvider.Options.getItemsContent */ - getItemsContent?: Function; - /** @name CustomFileProvider.Options.hasSubDirectoriesExpr */ +declare module DevExpress.fileManagement { + /** @name CustomFileSystemProvider.Options */ + export interface CustomFileSystemProviderOptions extends FileSystemProviderBaseOptions { + /** @name CustomFileSystemProvider.Options.abortFileUpload */ + abortFileUpload?: ((file: File, uploadInfo?: UploadInfo) => Promise | JQueryPromise | any); + /** @name CustomFileSystemProvider.Options.copyItem */ + copyItem?: ((item: FileSystemItem, destinationDirectory: FileSystemItem) => Promise | JQueryPromise | any); + /** @name CustomFileSystemProvider.Options.createDirectory */ + createDirectory?: ((parentDirectory: FileSystemItem, name: string) => Promise | JQueryPromise | any); + /** @name CustomFileSystemProvider.Options.deleteItem */ + deleteItem?: ((item: FileSystemItem) => Promise | JQueryPromise | any); + /** @name CustomFileSystemProvider.Options.downloadItems */ + downloadItems?: ((items: Array) => any); + /** @name CustomFileSystemProvider.Options.getItems */ + getItems?: ((parentDirectory: FileSystemItem) => Promise> | JQueryPromise> | Array); + /** @name CustomFileSystemProvider.Options.getItemsContent */ + getItemsContent?: ((items: Array) => Promise | JQueryPromise | any); + /** @name CustomFileSystemProvider.Options.hasSubDirectoriesExpr */ hasSubDirectoriesExpr?: string | Function; - /** @name CustomFileProvider.Options.moveItem */ - moveItem?: Function; - /** @name CustomFileProvider.Options.renameItem */ - renameItem?: Function; - /** @name CustomFileProvider.Options.uploadChunkSize */ - uploadChunkSize?: number; - /** @name CustomFileProvider.Options.uploadFileChunk */ - uploadFileChunk?: Function; - } - /** @name CustomFileProvider */ - export class CustomFileProvider extends FileProvider { - constructor(options?: CustomFileProviderOptions) - } - /** @name FileProvider.Options */ - export interface FileProviderOptions { - /** @name FileProvider.Options.dateModifiedExpr */ + /** @name CustomFileSystemProvider.Options.moveItem */ + moveItem?: ((item: FileSystemItem, destinationDirectory: FileSystemItem) => Promise | JQueryPromise | any); + /** @name CustomFileSystemProvider.Options.renameItem */ + renameItem?: ((item: FileSystemItem, newName: string) => Promise | JQueryPromise | any); + /** @name CustomFileSystemProvider.Options.uploadFileChunk */ + uploadFileChunk?: ((file: File, uploadInfo: UploadInfo) => Promise | JQueryPromise | any); + } + /** @name CustomFileSystemProvider */ + export class CustomFileSystemProvider extends FileSystemProviderBase { + constructor(options?: CustomFileSystemProviderOptions) + } + /** @name FileSystemItem */ + export class FileSystemItem { + /** @name FileSystemItem.dataItem */ + dataItem: any; + /** @name FileSystemItem.dateModified */ + dateModified: Date; + /** @name FileSystemItem.isDirectory */ + isDirectory: boolean; + /** @name FileSystemItem.key */ + key: string; + /** @name FileSystemItem.name */ + name: string; + /** @name FileSystemItem.path */ + path: string; + /** @name FileSystemItem.pathKeys */ + pathKeys: Array; + /** @name FileSystemItem.size */ + size: number; + /** @name FileSystemItem.thumbnail */ + thumbnail: string; + } + /** @name FileSystemProviderBase.Options */ + export interface FileSystemProviderBaseOptions { + /** @name FileSystemProviderBase.Options.dateModifiedExpr */ dateModifiedExpr?: string | Function; - /** @name FileProvider.Options.isDirectoryExpr */ + /** @name FileSystemProviderBase.Options.isDirectoryExpr */ isDirectoryExpr?: string | Function; - /** @name FileProvider.Options.keyExpr */ + /** @name FileSystemProviderBase.Options.keyExpr */ keyExpr?: string | Function; - /** @name FileProvider.Options.nameExpr */ + /** @name FileSystemProviderBase.Options.nameExpr */ nameExpr?: string | Function; - /** @name FileProvider.Options.sizeExpr */ + /** @name FileSystemProviderBase.Options.sizeExpr */ sizeExpr?: string | Function; - /** @name FileProvider.Options.thumbnailExpr */ + /** @name FileSystemProviderBase.Options.thumbnailExpr */ thumbnailExpr?: string | Function; } - /** @name FileProvider */ - export class FileProvider { - constructor(options?: FileProviderOptions) - /** @name FileProvider.getItemContent() */ - getItemContent(items: Array): Promise & JQueryPromise; + /** @name FileSystemProviderBase */ + export class FileSystemProviderBase { + constructor(options?: FileSystemProviderBaseOptions) + /** @name FileSystemProviderBase.abortFileUpload() */ + abortFileUpload(fileData: File, uploadInfo: any, destinationDirectory: FileSystemItem): Promise & JQueryPromise; + /** @name FileSystemProviderBase.copyItems() */ + copyItems(items: Array, destinationDirectory: FileSystemItem): Array | JQueryPromise>; + /** @name FileSystemProviderBase.createDirectory() */ + createDirectory(parentDirectory: FileSystemItem, name: string): Promise & JQueryPromise; + /** @name FileSystemProviderBase.deleteItems() */ + deleteItems(items: Array): Array | JQueryPromise>; + /** @name FileSystemProviderBase.downloadItems() */ + downloadItems(items: Array): any; + /** @name FileSystemProviderBase.getItems() */ + getItems(parentDirectory: FileSystemItem): Promise> & JQueryPromise>; + /** @name FileSystemProviderBase.getItemsContent() */ + getItemsContent(items: Array): Promise & JQueryPromise; + /** @name FileSystemProviderBase.moveItems() */ + moveItems(items: Array, destinationDirectory: FileSystemItem): Array | JQueryPromise>; + /** @name FileSystemProviderBase.renameItem() */ + renameItem(item: FileSystemItem, newName: string): Promise & JQueryPromise; + /** @name FileSystemProviderBase.uploadFileChunk() */ + uploadFileChunk(fileData: File, uploadInfo: any, destinationDirectory: FileSystemItem): Promise & JQueryPromise; + } + /** @name ObjectFileSystemProvider.Options */ + export interface ObjectFileSystemProviderOptions extends FileSystemProviderBaseOptions { + /** @name ObjectFileSystemProvider.Options.contentExpr */ + contentExpr?: string | Function; + /** @name ObjectFileSystemProvider.Options.data */ + data?: Array; + /** @name ObjectFileSystemProvider.Options.itemsExpr */ + itemsExpr?: string | Function; + } + /** @name ObjectFileSystemProvider */ + export class ObjectFileSystemProvider extends FileSystemProviderBase { + constructor(options?: ObjectFileSystemProviderOptions) } - /** @name RemoteFileProvider.Options */ - export interface RemoteFileProviderOptions extends FileProviderOptions { - /** @name RemoteFileProvider.Options.endpointUrl */ + /** @name RemoteFileSystemProvider.Options */ + export interface RemoteFileSystemProviderOptions extends FileSystemProviderBaseOptions { + /** @name RemoteFileSystemProvider.Options.endpointUrl */ endpointUrl?: string; - /** @name RemoteFileProvider.Options.hasSubDirectoriesExpr */ + /** @name RemoteFileSystemProvider.Options.hasSubDirectoriesExpr */ hasSubDirectoriesExpr?: string | Function; } - /** @name RemoteFileProvider */ - export class RemoteFileProvider extends FileProvider { - constructor(options?: RemoteFileProviderOptions) + /** @name RemoteFileSystemProvider */ + export class RemoteFileSystemProvider extends FileSystemProviderBase { + constructor(options?: RemoteFileSystemProviderOptions) + } + /** @name UploadInfo */ + export interface UploadInfo { + /** @name UploadInfo.bytesUploaded */ + bytesUploaded?: number; + /** @name UploadInfo.chunkBlob */ + chunkBlob?: Blob; + /** @name UploadInfo.chunkCount */ + chunkCount?: number; + /** @name UploadInfo.chunkIndex */ + chunkIndex?: number; + /** @name UploadInfo.customData */ + customData?: any; } } declare module DevExpress.fx { @@ -2846,7 +2943,7 @@ declare module DevExpress.ui { /** @name dxDataGrid.Options.editing */ editing?: dxDataGridEditing; /** @name dxDataGrid.Options.export */ - export?: { allowExportSelectedData?: boolean, customizeExcelCell?: ((options: { component?: dxDataGrid, horizontalAlignment?: 'center' | 'centerContinuous' | 'distributed' | 'fill' | 'general' | 'justify' | 'left' | 'right', verticalAlignment?: 'bottom' | 'center' | 'distributed' | 'justify' | 'top', wrapTextEnabled?: boolean, backgroundColor?: string, fillPatternType?: 'darkDown' | 'darkGray' | 'darkGrid' | 'darkHorizontal' | 'darkTrellis' | 'darkUp' | 'darkVertical' | 'gray0625' | 'gray125' | 'lightDown' | 'lightGray' | 'lightGrid' | 'lightHorizontal' | 'lightTrellis' | 'lightUp' | 'lightVertical' | 'mediumGray' | 'none' | 'solid', fillPatternColor?: string, font?: DevExpress.exporter.ExcelFont, value?: string | number | Date, numberFormat?: string, gridCell?: DevExpress.exporter.ExcelDataGridCell }) => any), enabled?: boolean, excelFilterEnabled?: boolean, excelWrapTextEnabled?: boolean, fileName?: string, ignoreExcelErrors?: boolean, proxyUrl?: string, texts?: { exportAll?: string, exportSelectedRows?: string, exportTo?: string } }; + export?: { allowExportSelectedData?: boolean, customizeExcelCell?: ((options: { component?: dxDataGrid, horizontalAlignment?: 'center' | 'centerContinuous' | 'distributed' | 'fill' | 'general' | 'justify' | 'left' | 'right', verticalAlignment?: 'bottom' | 'center' | 'distributed' | 'justify' | 'top', wrapTextEnabled?: boolean, backgroundColor?: string, fillPatternType?: 'darkDown' | 'darkGray' | 'darkGrid' | 'darkHorizontal' | 'darkTrellis' | 'darkUp' | 'darkVertical' | 'gray0625' | 'gray125' | 'lightDown' | 'lightGray' | 'lightGrid' | 'lightHorizontal' | 'lightTrellis' | 'lightUp' | 'lightVertical' | 'mediumGray' | 'none' | 'solid', fillPatternColor?: string, font?: DevExpress.exporter.ExcelFont, value?: string | number | Date, numberFormat?: string, gridCell?: DevExpress.excelExporter.ExcelDataGridCell }) => any), enabled?: boolean, excelFilterEnabled?: boolean, excelWrapTextEnabled?: boolean, fileName?: string, ignoreExcelErrors?: boolean, proxyUrl?: string, texts?: { exportAll?: string, exportSelectedRows?: string, exportTo?: string } }; /** @name dxDataGrid.Options.groupPanel */ groupPanel?: { allowColumnDragging?: boolean, emptyPanelText?: string, visible?: boolean | 'auto' }; /** @name dxDataGrid.Options.grouping */ @@ -3137,6 +3234,8 @@ declare module DevExpress.ui { gridSize?: number | { items?: Array, value?: number }; /** @name dxDiagram.Options.hasChanges */ hasChanges?: boolean; + /** @name dxDiagram.Options.historyToolbar */ + historyToolbar?: { commands?: Array<'separator' | 'export' | 'undo' | 'redo' | 'cut' | 'copy' | 'paste' | 'selectAll' | 'delete' | 'fontName' | 'fontSize' | 'bold' | 'italic' | 'underline' | 'fontColor' | 'lineColor' | 'fillColor' | 'textAlignLeft' | 'textAlignCenter' | 'textAlignRight' | 'lock' | 'unlock' | 'sendToBack' | 'bringToFront' | 'insertShapeImage' | 'editShapeImage' | 'deleteShapeImage' | 'connectorLineType' | 'connectorLineStart' | 'connectorLineEnd' | 'autoLayout' | 'fullScreen' | 'zoomLevel' | 'autoZoom' | 'showGrid' | 'snapToGrid' | 'gridSize' | 'units'>, visible?: boolean }; /** @name dxDiagram.Options.nodes */ nodes?: { autoLayout?: 'auto' | 'off' | 'tree' | 'layered' | { orientation?: 'auto' | 'vertical' | 'horizontal', type?: 'auto' | 'off' | 'tree' | 'layered' }, childrenExpr?: string | ((data: any) => any), containerKeyExpr?: string | ((data: any) => any), dataSource?: Array | DevExpress.data.DataSource | DevExpress.data.DataSourceOptions, heightExpr?: string | ((data: any) => any), imageUrlExpr?: string | ((data: any) => any), itemsExpr?: string | ((data: any) => any), keyExpr?: string | ((data: any) => any), leftExpr?: string | ((data: any) => any), lockedExpr?: string | ((data: any) => any), parentKeyExpr?: string | ((data: any) => any), styleExpr?: string | ((data: any) => any), textExpr?: string | ((data: any) => any), textStyleExpr?: string | ((data: any) => any), topExpr?: string | ((data: any) => any), typeExpr?: string | ((data: any) => any), widthExpr?: string | ((data: any) => any), zIndexExpr?: string | ((data: any) => any) }; /** @name dxDiagram.Options.onItemClick */ @@ -3162,11 +3261,13 @@ declare module DevExpress.ui { /** @name dxDiagram.Options.snapToGrid */ snapToGrid?: boolean; /** @name dxDiagram.Options.toolbar */ - toolbar?: { commands?: Array<'separator' | 'export' | 'undo' | 'redo' | 'cut' | 'copy' | 'paste' | 'selectAll' | 'delete' | 'fontName' | 'fontSize' | 'bold' | 'italic' | 'underline' | 'fontColor' | 'lineColor' | 'fillColor' | 'textAlignLeft' | 'textAlignCenter' | 'textAlignRight' | 'lock' | 'unlock' | 'sendToBack' | 'bringToFront' | 'insertShapeImage' | 'editShapeImage' | 'deleteShapeImage' | 'connectorLineType' | 'connectorLineStart' | 'connectorLineEnd' | 'autoLayout' | 'fullScreen'>, visible?: boolean }; + toolbar?: { commands?: Array<'separator' | 'export' | 'undo' | 'redo' | 'cut' | 'copy' | 'paste' | 'selectAll' | 'delete' | 'fontName' | 'fontSize' | 'bold' | 'italic' | 'underline' | 'fontColor' | 'lineColor' | 'fillColor' | 'textAlignLeft' | 'textAlignCenter' | 'textAlignRight' | 'lock' | 'unlock' | 'sendToBack' | 'bringToFront' | 'insertShapeImage' | 'editShapeImage' | 'deleteShapeImage' | 'connectorLineType' | 'connectorLineStart' | 'connectorLineEnd' | 'autoLayout' | 'fullScreen' | 'zoomLevel' | 'autoZoom' | 'showGrid' | 'snapToGrid' | 'gridSize' | 'units'>, visible?: boolean }; /** @name dxDiagram.Options.toolbox */ toolbox?: { groups?: Array<{ category?: 'general' | 'flowchart' | 'orgChart' | 'containers' | 'custom' | string, displayMode?: 'icons' | 'texts', expanded?: boolean, shapes?: Array<'text' | 'rectangle' | 'ellipse' | 'cross' | 'triangle' | 'diamond' | 'heart' | 'pentagon' | 'octagon' | 'star' | 'arrowLeft' | 'arrowTop' | 'arrowRight' | 'arrowBottom' | 'arrowNorthSouth' | 'arrowEastWest' | 'process' | 'decision' | 'terminator' | 'predefinedProcess' | 'document' | 'multipleDocuments' | 'manualInput' | 'preparation' | 'data' | 'database' | 'hardDisk' | 'internalStorage' | 'paperTape' | 'manualOperation' | 'delay' | 'storedData' | 'display' | 'merge' | 'connector' | 'or' | 'summingJunction' | 'verticalContainer' | 'horizontalContainer' | 'cardWithImageOnLeft' | 'cardWithImageOnTop' | 'cardWithImageOnRight'> | Array, title?: string }> | Array<'general' | 'flowchart' | 'orgChart' | 'containers' | 'custom'>, visible?: boolean }; /** @name dxDiagram.Options.units */ units?: 'in' | 'cm' | 'px'; + /** @name dxDiagram.Options.viewToolbar */ + viewToolbar?: { commands?: Array<'separator' | 'export' | 'undo' | 'redo' | 'cut' | 'copy' | 'paste' | 'selectAll' | 'delete' | 'fontName' | 'fontSize' | 'bold' | 'italic' | 'underline' | 'fontColor' | 'lineColor' | 'fillColor' | 'textAlignLeft' | 'textAlignCenter' | 'textAlignRight' | 'lock' | 'unlock' | 'sendToBack' | 'bringToFront' | 'insertShapeImage' | 'editShapeImage' | 'deleteShapeImage' | 'connectorLineType' | 'connectorLineStart' | 'connectorLineEnd' | 'autoLayout' | 'fullScreen' | 'zoomLevel' | 'autoZoom' | 'showGrid' | 'snapToGrid' | 'gridSize' | 'units'>, visible?: boolean }; /** @name dxDiagram.Options.viewUnits */ viewUnits?: 'in' | 'cm' | 'px'; /** @name dxDiagram.Options.zoomLevel */ @@ -3492,17 +3593,17 @@ declare module DevExpress.ui { /** @name dxFileManager.Options.customizeDetailColumns */ customizeDetailColumns?: ((columns: Array) => Array); /** @name dxFileManager.Options.customizeThumbnail */ - customizeThumbnail?: ((fileItem: any) => string); - /** @name dxFileManager.Options.fileProvider */ - fileProvider?: any; + customizeThumbnail?: ((fileSystemItem: DevExpress.fileManagement.FileSystemItem) => string); + /** @name dxFileManager.Options.fileSystemProvider */ + fileSystemProvider?: any; /** @name dxFileManager.Options.itemView */ itemView?: { mode?: 'details' | 'thumbnails', showFolders?: boolean, showParentFolder?: boolean }; /** @name dxFileManager.Options.onCurrentDirectoryChanged */ - onCurrentDirectoryChanged?: ((e: { component?: dxFileManager, element?: DevExpress.core.dxElement, model?: any }) => any); + onCurrentDirectoryChanged?: ((e: { component?: dxFileManager, element?: DevExpress.core.dxElement, model?: any, directory?: DevExpress.fileManagement.FileSystemItem }) => any); /** @name dxFileManager.Options.onSelectedFileOpened */ - onSelectedFileOpened?: ((e: { component?: dxFileManager, element?: DevExpress.core.dxElement, model?: any, fileItem?: any }) => any); + onSelectedFileOpened?: ((e: { component?: dxFileManager, element?: DevExpress.core.dxElement, model?: any, file?: DevExpress.fileManagement.FileSystemItem }) => any); /** @name dxFileManager.Options.permissions */ - permissions?: { copy?: boolean, create?: boolean, download?: boolean, move?: boolean, remove?: boolean, rename?: boolean, upload?: boolean }; + permissions?: { copy?: boolean, create?: boolean, delete?: boolean, download?: boolean, move?: boolean, rename?: boolean, upload?: boolean }; /** @name dxFileManager.Options.rootFolderName */ rootFolderName?: string; /** @name dxFileManager.Options.selectionMode */ @@ -3510,7 +3611,7 @@ declare module DevExpress.ui { /** @name dxFileManager.Options.toolbar */ toolbar?: dxFileManagerToolbar; /** @name dxFileManager.Options.upload */ - upload?: { maxFileSize?: number }; + upload?: { chunkSize?: number, maxFileSize?: number }; } /** @name dxFileManager */ export class dxFileManager extends Widget { @@ -3540,23 +3641,23 @@ declare module DevExpress.ui { /** @name dxFileManagerToolbar */ export interface dxFileManagerToolbar { /** @name dxFileManagerToolbar.fileSelectionItems */ - fileSelectionItems?: Array; + fileSelectionItems?: Array; /** @name dxFileManagerToolbar.items */ - items?: Array; + items?: Array; } /** @name dxFileManagerToolbarItem */ export interface dxFileManagerToolbarItem extends dxToolbarItem { /** @name dxFileManagerToolbarItem.location */ location?: 'after' | 'before' | 'center'; /** @name dxFileManagerToolbarItem.name */ - name?: 'showNavPane' | 'create' | 'upload' | 'refresh' | 'viewSwitcher' | 'download' | 'move' | 'copy' | 'rename' | 'delete' | 'clear' | 'separator' | string; + name?: 'showNavPane' | 'create' | 'upload' | 'refresh' | 'switchView' | 'download' | 'move' | 'copy' | 'rename' | 'delete' | 'clear' | 'separator' | string; /** @name dxFileManagerToolbarItem.visible */ visible?: boolean; } /** @name dxFileUploader.Options */ export interface dxFileUploaderOptions extends EditorOptions { /** @name dxFileUploader.Options.abortUpload */ - abortUpload?: ((file: File, uploadInfo: { bytesUploaded?: number, chunkCount?: number, customData?: any, chunkBlob?: Blob, chunkIndex?: number }) => Promise | JQueryPromise | any); + abortUpload?: ((file: File, uploadInfo?: DevExpress.fileManagement.UploadInfo) => Promise | JQueryPromise | any); /** @name dxFileUploader.Options.accept */ accept?: string; /** @name dxFileUploader.Options.allowCanceling */ @@ -3606,7 +3707,7 @@ declare module DevExpress.ui { /** @name dxFileUploader.Options.uploadButtonText */ uploadButtonText?: string; /** @name dxFileUploader.Options.uploadChunk */ - uploadChunk?: ((file: File, uploadInfo: { bytesUploaded?: number, chunkCount?: number, customData?: any, chunkBlob?: Blob, chunkIndex?: number }) => Promise | JQueryPromise | any); + uploadChunk?: ((file: File, uploadInfo: DevExpress.fileManagement.UploadInfo) => Promise | JQueryPromise | any); /** @name dxFileUploader.Options.uploadFailedMessage */ uploadFailedMessage?: string; /** @name dxFileUploader.Options.uploadFile */ @@ -3992,8 +4093,10 @@ declare module DevExpress.ui { export interface dxGanttTimeMarker { /** @name dxGanttTimeMarker.cssClass */ cssClass?: string; - /** @name dxGanttTimeMarker.dateTime */ - dateTime?: Date | number | string | (() => Date | number | string); + /** @name dxGanttTimeMarker.end */ + end?: Date | number | string | (() => Date | number | string); + /** @name dxGanttTimeMarker.start */ + start?: Date | number | string | (() => Date | number | string); /** @name dxGanttTimeMarker.title */ title?: string; }