Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

File manager - Fix toolbar separators calculation #12698

Merged
Merged
103 changes: 75 additions & 28 deletions js/ui/file_manager/ui.file_manager.toolbar.js
Original file line number Diff line number Diff line change
Expand Up @@ -167,36 +167,74 @@ class FileManagerToolbar extends Widget {

return preparedItem;
});
return this._updateSeparatorsVisibility(items);
this._updateSeparatorsVisibility(items);
return items;
}

_updateSeparatorsVisibility(items, toolbar) {
for(let i = 0; i < items.length; i++) {
if(items[i].name === 'separator') {
const isSeparatorVisible = this._groupHasItems(items, i, true) && this._groupHasItems(items, i, false);
if(toolbar) {
const optionName = `items[${i}].visible`;
toolbar.option(optionName, isSeparatorVisible);
} else {
items[i].visible = isSeparatorVisible;
let hasModifications = false;
const menuItems = this._getMenuItems(toolbar);
const hasItemsBefore = {
before: false,
center: false,
after: false
};
const itemGroups = {
before: this._getItemsInGroup(items, menuItems, 'before'),
center: this._getItemsInGroup(items, menuItems, 'center'),
after: this._getItemsInGroup(items, menuItems, 'after')
};
items.forEach((item, i) => {
const itemLocation = this._getItemLocation(item);
if(item.name === 'separator') {
const isSeparatorVisible = hasItemsBefore[itemLocation] && this._groupHasItemsAfter(itemGroups[itemLocation]);
if(item.visible !== isSeparatorVisible) {
hasModifications = true;
item.visible = isSeparatorVisible;
}
hasItemsBefore[itemLocation] = false;
} else {
if(!this._isItemInMenu(menuItems, item)) {
hasItemsBefore[itemLocation] = hasItemsBefore[itemLocation] || item.visible;
}
itemGroups[itemLocation].shift();
}
});

if(toolbar && hasModifications) {
toolbar.repaint();
}
return items;
return hasModifications;
}

_getMenuItems(toolbar) {
const result = toolbar ? toolbar._getMenuItems() : [];
return result.map(menuItem => menuItem.originalItemData);
}

_isItemInMenu(menuItems, item) {
return !!menuItems.length
&& ensureDefined(item.locateInMenu, 'never') !== 'never'
&& menuItems.indexOf(item.originalItemData) !== -1;
}

_getItemsInGroup(items, menuItems, groupName) {
return items.filter(item => this._getItemLocation(item) === groupName && !this._isItemInMenu(menuItems, item));
}

_groupHasItems(items, separatorIndex, isBeforeGroup) {
const delta = isBeforeGroup ? -1 : 1;
let i = separatorIndex + delta;
while(items[i] && items[i].name !== 'separator') {
if(items[i].visible) {
_groupHasItemsAfter(items) {
for(let i = 0; i < items.length; i++) {
if(items[i].name !== 'separator' && items[i].visible) {
return true;
}
i += delta;
}
return false;
}

_getItemLocation(toolbarItem) {
return ensureDefined(toolbarItem.location, 'before');
}

_configureItemByCommandName(commandName, item) {
let result = {};

Expand Down Expand Up @@ -321,10 +359,10 @@ class FileManagerToolbar extends Widget {
}

_toggleCompactMode(toolbar, useCompactMode) {
toolbar.beginUpdate();

let hasModifications = false;
const items = toolbar.option('items');
items.forEach((item, index) => {

items.forEach(item => {
if(item.compactMode) {
let optionsSource = null;

Expand All @@ -336,11 +374,17 @@ class FileManagerToolbar extends Widget {
}

const options = this._getCompactModeOptions(optionsSource, item.available);
toolbar.option(`items[${index}]`, options);
extend(true, item, options);
hasModifications = true;
}
});

toolbar.endUpdate();
hasModifications = this._updateSeparatorsVisibility(items) || hasModifications;
if(hasModifications) {
toolbar.repaint();
}

this._updateSeparatorsVisibility(items, toolbar);
}

_getCompactModeOptions({ showText, locateInMenu }, available) {
Expand All @@ -352,23 +396,26 @@ class FileManagerToolbar extends Widget {
}

_ensureAvailableCommandsVisible(toolbar, fileItems) {
toolbar.beginUpdate();

let hasModifications = false;
const items = toolbar.option('items');

items.forEach((item, index) => {
items.forEach(item => {
if(item.name !== 'separator') {
const itemVisible = item.available;
item.available = this._isToolbarItemAvailable(item, fileItems);
if(item.available !== itemVisible) {
const optionName = `items[${index}].visible`;
toolbar.option(optionName, item.available);
item.visible = item.available;
hasModifications = true;
}
}
});

this._updateSeparatorsVisibility(toolbar.option('items'), toolbar);
toolbar.endUpdate();
hasModifications = this._updateSeparatorsVisibility(items) || hasModifications;
if(hasModifications) {
toolbar.repaint();
}

this._updateSeparatorsVisibility(items, toolbar);
}

_fileToolbarHasEffectiveItems(fileItems) {
Expand Down
182 changes: 182 additions & 0 deletions testing/tests/DevExpress.ui.widgets/fileManagerParts/toolbar.tests.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import $ from 'jquery';
import 'ui/file_manager';
import fx from 'animation/fx';
import renderer from 'core/renderer';
import { Consts, FileManagerWrapper, createTestFileSystem } from '../../../helpers/fileManagerHelpers.js';

const { test } = QUnit;
Expand Down Expand Up @@ -637,4 +638,185 @@ QUnit.module('Toolbar', moduleConfig, () => {
assert.ok(!$toolbar.hasClass(Consts.FILE_TOOLBAR_CLASS), 'file toolbar hidden');
});

test('toolbar separators must take location into account', function(assert) {
createFileManager(false);
this.clock.tick(400);

const fileManager = this.wrapper.getInstance();
fileManager.option({
permissions: {
download: true
},
toolbar: {
fileSelectionItems: ['download', 'separator', 'clearSelection']
}
});
this.clock.tick(400);

const $item = this.wrapper.findDetailsItem('File 1.txt');
$item.trigger('dxclick');
this.clock.tick(400);

const $separators = this.wrapper.getToolbarSeparators();
assert.equal($separators.length, 0, 'file toolbar has no separators');
});

test('toolbar separators must render one time for empty group', function(assert) {
createFileManager(false);
this.clock.tick(400);

const fileManager = this.wrapper.getInstance();
fileManager.option({
toolbar: {
items: [
{
options: {
text: 'item0'
},
visible: true,
location: 'before'
},
'separator',
{
options: {
text: 'item1'
},
visible: false,
location: 'before'
},
'separator',
{
options: {
text: 'item2'
},
visible: true,
location: 'before'
}
]
}
});
this.clock.tick(400);

const $separators = this.wrapper.getToolbarSeparators();
assert.equal($separators.length, 1, 'toolbar has one separator');
});

test('toolbar separators must support default items in menu', function(assert) {
createFileManager(false);
this.clock.tick(400);

const fileManager = this.wrapper.getInstance();
fileManager.option({
toolbar: {
fileSelectionItems: [
'download', 'move', 'copy', 'rename', 'separator', 'delete', 'refresh', 'clearSelection',
{
widget: 'dxButton',
options: {
text: 'some button with very-very long text to make it easier to hide some items in toolbar menu'
}
},
{
widget: 'dxButton',
options: {
text: 'some item 2 with text'
}
}
]
}
});
this.clock.tick(400);

const originalWidth = renderer.fn.width;
renderer.fn.width = () => 700;
$('#fileManager').css('width', '100%');
fileManager.repaint();
this.clock.tick(800);

const $item = this.wrapper.findDetailsItem('File 1.txt');
$item.trigger('dxclick');
this.clock.tick(400);

const $separators = this.wrapper.getToolbarSeparators();
assert.equal($separators.length, 0, 'file toolbar has no separators');

renderer.fn.width = originalWidth;
});

test('toolbar separators must support custom items in menu', function(assert) {
createFileManager(false);
this.clock.tick(400);

const fileManager = this.wrapper.getInstance();
fileManager.option({
toolbar: {
fileSelectionItems: [
'download', 'move', 'copy', 'rename', 'separator', 'refresh', 'clearSelection',
{
widget: 'dxButton',
options: {
text: 'some item 1 with text'
},
locateInMenu: 'auto'
}
]
}
});
this.clock.tick(400);

const originalWidth = renderer.fn.width;
renderer.fn.width = () => 400;
$('#fileManager').css('width', '100%');
fileManager.repaint();
this.clock.tick(800);

const $item = this.wrapper.findDetailsItem('File 1.txt');
$item.trigger('dxclick');
this.clock.tick(400);
const $separators = this.wrapper.getToolbarSeparators();
assert.equal($separators.length, 0, 'file toolbar has no separators');

renderer.fn.width = originalWidth;
});

test('items can render in menu after first load', function(assert) {
createFileManager(false);
this.clock.tick(400);

const fileManager = this.wrapper.getInstance();
fileManager.option({
toolbar: {
fileSelectionItems: [
'download', 'move', 'copy', 'rename', 'separator', 'refresh', 'clearSelection',
{
widget: 'dxButton',
options: {
text: 'some item 1 with text'
},
locateInMenu: 'auto'
}
]
}
});
this.clock.tick(400);

const originalWidth = renderer.fn.width;
renderer.fn.width = () => 400;
$('#fileManager').css('width', '100%');
fileManager.repaint();
this.clock.tick(800);

const $item = this.wrapper.findDetailsItem('File 1.txt');
$item.trigger('dxclick');
this.clock.tick(400);

const $toolbarDropDownMenuButton = this.wrapper.getToolbarDropDownMenuButton();
$toolbarDropDownMenuButton.trigger('dxclick');
this.clock.tick(400);

const toolbarDropDownMenuItem = this.wrapper.getToolbarDropDownMenuItem(0);
assert.notStrictEqual($(toolbarDropDownMenuItem).find('.dx-button-text').text().indexOf('some item 1 with text'), -1, 'custom button is rendered in the dropDown menu');
renderer.fn.width = originalWidth;
});

});