Index: chrome/test/data/webui/md_bookmarks/dnd_manager_test.js |
diff --git a/chrome/test/data/webui/md_bookmarks/dnd_manager_test.js b/chrome/test/data/webui/md_bookmarks/dnd_manager_test.js |
new file mode 100644 |
index 0000000000000000000000000000000000000000..faefc8260b67903a0105cccdd66f53d4f6d5c6a5 |
--- /dev/null |
+++ b/chrome/test/data/webui/md_bookmarks/dnd_manager_test.js |
@@ -0,0 +1,342 @@ |
+// Copyright 2017 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+suite('drag and drop', function() { |
+ var app; |
+ var list; |
+ var sidebar; |
+ var store; |
+ var dndManager; |
+ var draggedIds; |
+ |
+ var DRAG_STYLE = { |
+ NONE: 0, |
+ ON: 1, |
+ ABOVE: 2, |
+ BELOW: 3, |
+ }; |
+ |
+ function getFolderNode(id) { |
+ var nodes = [sidebar]; |
+ var node; |
+ while (nodes.length) { |
+ node = nodes.pop(); |
+ if (node.itemId == id) |
+ return node; |
+ |
+ node.root.querySelectorAll('bookmarks-folder-node') |
+ .forEach((x) => {nodes.unshift(x)}); |
+ } |
+ } |
+ |
+ function getListItem(id) { |
+ var items = list.root.querySelectorAll('bookmarks-item'); |
+ for (var i = 0; i < items.length; i++) { |
+ if (items[i].itemId == id) |
+ return items[i]; |
+ } |
+ } |
+ |
+ function dispatchDragEvent(type, node, xy) { |
+ xy = xy || MockInteractions.middleOfNode(node); |
+ var props = { |
+ bubbles: true, |
+ cancelable: true, |
+ clientX: xy.x, |
+ clientY: xy.y, |
+ // Make this a primary input. |
+ buttons: 1, |
+ }; |
+ var e = new DragEvent(type, props); |
+ node.dispatchEvent(e); |
+ } |
+ |
+ function assertDragStyle(bookmarkElement, style) { |
+ var dragStyles = {}; |
+ dragStyles[DRAG_STYLE.ON] = 'drag-on'; |
+ dragStyles[DRAG_STYLE.ABOVE] = 'drag-above'; |
+ dragStyles[DRAG_STYLE.BELOW] = 'drag-below'; |
+ |
+ var classList = bookmarkElement.getDropTarget().classList; |
+ Object.keys(dragStyles).forEach(dragStyle => { |
+ assertEquals( |
+ dragStyle == style, classList.contains(dragStyles[dragStyle]), |
+ dragStyles[dragStyle] + (dragStyle == style ? ' missing' : ' found') + |
+ ' in classList ' + classList); |
+ }); |
+ } |
+ |
+ function createDragData(ids, sameProfile) { |
+ return { |
+ elements: ids.map(id => store.data.nodes[id]), |
+ sameProfile: sameProfile == undefined ? true : sameProfile, |
+ }; |
+ } |
+ |
+ setup(function() { |
+ store = new bookmarks.TestStore({ |
+ nodes: testTree( |
+ createFolder( |
+ '1', |
+ [ |
+ createFolder( |
+ '11', |
+ [ |
+ createFolder( |
+ '111', |
+ [ |
+ createItem('1111'), |
+ ]), |
+ createFolder('112', []), |
+ ]), |
+ createItem('12'), |
+ createItem('13'), |
+ createFolder('14', []), |
+ createFolder('15', []), |
+ ]), |
+ createFolder('2', [])), |
+ selectedFolder: '1', |
+ }); |
+ bookmarks.Store.instance_ = store; |
+ |
+ chrome.bookmarkManagerPrivate.startDrag = function(nodes, isTouch) { |
+ draggedIds = nodes; |
+ }; |
+ |
+ app = document.createElement('bookmarks-app'); |
+ replaceBody(app); |
+ list = app.$$('bookmarks-list'); |
+ sidebar = app.$$('bookmarks-sidebar'); |
+ dndManager = app.dndManager_; |
+ dndManager.dropIndicator_.disableTimeoutForTesting(); |
+ Polymer.dom.flush(); |
+ }); |
+ |
+ test('dragInfo isDraggingFolderToDescendant', function() { |
+ var dragInfo = new bookmarks.DragInfo(); |
+ var nodes = store.data.nodes; |
+ dragInfo.handleChromeDragEnter(createDragData(['11'])); |
+ assertTrue(dragInfo.isDraggingFolderToDescendant('111', nodes)); |
+ assertFalse(dragInfo.isDraggingFolderToDescendant('1', nodes)); |
+ assertFalse(dragInfo.isDraggingFolderToDescendant('2', nodes)); |
+ |
+ dragInfo.handleChromeDragEnter(createDragData(['1'])); |
+ assertTrue(dragInfo.isDraggingFolderToDescendant('14', nodes)); |
+ assertTrue(dragInfo.isDraggingFolderToDescendant('111', nodes)); |
+ assertFalse(dragInfo.isDraggingFolderToDescendant('2', nodes)); |
+ }); |
+ |
+ test('drag in list', function() { |
+ var dragElement = getListItem('13'); |
+ var dragTarget = getListItem('12'); |
+ |
+ dispatchDragEvent('dragstart', dragElement); |
+ assertDeepEquals(['13'], draggedIds); |
+ dndManager.dragInfo_.handleChromeDragEnter(createDragData(draggedIds)); |
+ |
+ // Bookmark items cannot be dragged onto other items. |
+ dispatchDragEvent( |
+ 'dragover', dragTarget, MockInteractions.topLeftOfNode(dragTarget)); |
+ assertEquals( |
+ DropPosition.ABOVE, |
+ dndManager.calculateValidDropPositions_(dragTarget)); |
+ assertDragStyle(dragTarget, DRAG_STYLE.ABOVE); |
+ |
+ dispatchDragEvent('dragleave', dragTarget); |
+ assertDragStyle(dragTarget, DRAG_STYLE.NONE); |
+ |
+ // Bookmark items can be dragged onto folders. |
+ dragTarget = getListItem('11'); |
+ dispatchDragEvent('dragover', dragTarget); |
+ assertEquals( |
+ DropPosition.ON | DropPosition.ABOVE | DropPosition.BELOW, |
+ dndManager.calculateValidDropPositions_(dragTarget)); |
+ assertDragStyle(dragTarget, DRAG_STYLE.ON); |
+ |
+ // There are no valid drop locations for dragging an item onto itself. |
+ assertEquals( |
+ DropPosition.NONE, |
+ dndManager.calculateValidDropPositions_(dragElement)); |
+ dispatchDragEvent('dragleave', dragTarget); |
+ dispatchDragEvent('dragover', dragElement); |
+ |
+ assertDragStyle(dragTarget, DRAG_STYLE.NONE); |
+ assertDragStyle(dragElement, DRAG_STYLE.NONE); |
+ }); |
+ |
+ test('reorder folder nodes', function() { |
+ var dragElement = getFolderNode('112'); |
+ var dragTarget = getFolderNode('111'); |
+ dispatchDragEvent('dragstart', dragElement); |
+ dndManager.dragInfo_.handleChromeDragEnter(createDragData(draggedIds)); |
+ |
+ assertEquals( |
+ DropPosition.ON | DropPosition.ABOVE, |
+ dndManager.calculateValidDropPositions_(dragTarget)); |
+ |
+ dispatchDragEvent( |
+ 'dragover', dragTarget, MockInteractions.topLeftOfNode(dragTarget)); |
+ assertDragStyle(dragTarget, DRAG_STYLE.ABOVE); |
+ }); |
+ |
+ test('drag an item into a sidebar folder', function() { |
+ var dragElement = getListItem('13'); |
+ var dragTarget = getFolderNode('2'); |
+ dispatchDragEvent('dragstart', dragElement); |
+ dndManager.dragInfo_.handleChromeDragEnter(createDragData(draggedIds)); |
+ |
+ // Items can only be dragged onto sidebar folders, not above or below. |
+ assertEquals( |
+ DropPosition.ON, dndManager.calculateValidDropPositions_(dragTarget)); |
+ |
+ dispatchDragEvent('dragover', dragTarget); |
+ assertDragStyle(dragTarget, DRAG_STYLE.ON); |
+ |
+ // Items cannot be dragged onto their parent folders. |
+ dragTarget = getFolderNode('1'); |
+ dispatchDragEvent('dragover', dragTarget); |
+ assertDragStyle(dragTarget, DRAG_STYLE.NONE); |
+ }); |
+ |
+ test('drag a folder into a descendant', function() { |
+ var dragElement = getFolderNode('11'); |
+ var dragTarget = getFolderNode('112'); |
+ |
+ // Folders cannot be dragged into their descendants. |
+ dispatchDragEvent('dragstart', dragElement); |
+ dndManager.dragInfo_.handleChromeDragEnter(createDragData(draggedIds)); |
+ assertEquals( |
+ DropPosition.NONE, |
+ dndManager.calculateValidDropPositions_(dragTarget)); |
+ |
+ dispatchDragEvent('dragover', dragTarget); |
+ |
+ assertDragStyle(dragTarget, DRAG_STYLE.NONE); |
+ }); |
+ |
+ test('drag item into sidebar folder with descendants', function() { |
+ var dragElement = getFolderNode('15'); |
+ var dragTarget = getFolderNode('11'); |
+ dispatchDragEvent('dragstart', dragElement); |
+ dndManager.dragInfo_.handleChromeDragEnter(createDragData(draggedIds)); |
+ |
+ // Drags below an open folder are not allowed. |
+ assertEquals( |
+ DropPosition.ON | DropPosition.ABOVE, |
+ dndManager.calculateValidDropPositions_(dragTarget)); |
+ |
+ dispatchDragEvent('dragover', dragTarget); |
+ |
+ assertDragStyle(dragTarget, DRAG_STYLE.ON); |
+ |
+ dispatchDragEvent('dragend', dragElement); |
+ assertDragStyle(dragTarget, DRAG_STYLE.NONE); |
+ |
+ store.data.closedFolders['11'] = true; |
+ |
+ dispatchDragEvent('dragstart', dragElement); |
+ dndManager.dragInfo_.handleChromeDragEnter(createDragData(draggedIds)); |
+ |
+ // Drags below a closed folder are allowed. |
+ assertEquals( |
+ DropPosition.ON | DropPosition.ABOVE | DropPosition.BELOW, |
+ dndManager.calculateValidDropPositions_(dragTarget)); |
+ }); |
+ |
+ test('drag multiple list items', function() { |
+ // Dragging multiple items. |
+ store.data.selection.items = {'13': true, '15': true}; |
+ dispatchDragEvent('dragstart', getListItem('13')); |
+ assertDeepEquals(['13', '15'], draggedIds); |
+ dndManager.dragInfo_.handleChromeDragEnter(createDragData(draggedIds)); |
+ |
+ // The dragged items should not be allowed to be dragged around any selected |
+ // item. |
+ assertEquals( |
+ DropPosition.NONE, |
+ dndManager.calculateValidDropPositions_(getListItem('13'))); |
+ assertEquals( |
+ DropPosition.ON, |
+ dndManager.calculateValidDropPositions_(getListItem('14'))); |
+ assertEquals( |
+ DropPosition.NONE, |
+ dndManager.calculateValidDropPositions_(getListItem('15'))); |
+ |
+ // Dragging an unselected item should only drag the unselected item. |
+ dispatchDragEvent('dragstart', getListItem('14')); |
+ assertDeepEquals(['14'], draggedIds); |
+ |
+ // Dragging a folder node should only drag the node. |
+ dispatchDragEvent('dragstart', getListItem('11')); |
+ assertDeepEquals(['11'], draggedIds); |
+ }); |
+ |
+ test('bookmarks from different profiles', function() { |
+ dndManager.dragInfo_.handleChromeDragEnter(createDragData(['11'], false)); |
+ |
+ // All positions should be allowed even with the same bookmark id if the |
+ // drag element is from a different profile. |
+ assertEquals( |
+ DropPosition.ON | DropPosition.ABOVE | DropPosition.BELOW, |
+ dndManager.calculateValidDropPositions_(getListItem('11'))); |
+ |
+ // Folders from other profiles should be able to be dragged into |
+ // descendants in this profile. |
+ assertEquals( |
+ DropPosition.ON | DropPosition.ABOVE | DropPosition.BELOW, |
+ dndManager.calculateValidDropPositions_(getFolderNode('112'))); |
+ }); |
+ |
+ test('drag from sidebar to list', function() { |
+ var dragElement = getFolderNode('112'); |
+ var dragTarget = getListItem('13'); |
+ |
+ // Drag a folder onto the list. |
+ dispatchDragEvent('dragstart', dragElement); |
+ assertDeepEquals(['112'], draggedIds); |
+ dndManager.dragInfo_.handleChromeDragEnter(createDragData(draggedIds)); |
+ |
+ dispatchDragEvent( |
+ 'dragover', dragTarget, MockInteractions.topLeftOfNode(dragTarget)); |
+ assertDragStyle(dragTarget, DRAG_STYLE.ABOVE); |
+ |
+ dispatchDragEvent('dragend', dragTarget); |
+ |
+ // Folders should not be able to dragged onto themselves in the list. |
+ dndManager.dragInfo_.handleChromeDragEnter(createDragData(['11'])); |
+ assertEquals( |
+ DropPosition.NONE, |
+ dndManager.calculateValidDropPositions_(getListItem('11'))); |
+ |
+ // Ancestors should not be able to be dragged onto descendant |
+ // displayed lists. |
+ store.data.selectedFolder = '111'; |
+ store.notifyObservers(); |
+ Polymer.dom.flush(); |
+ |
+ dndManager.dragInfo_.handleChromeDragEnter(createDragData(['11'])); |
+ assertEquals( |
+ DropPosition.NONE, |
+ dndManager.calculateValidDropPositions_(getListItem('1111'))); |
+ }); |
+ |
+ test('drags with search', function() { |
+ store.data.search.term = 'Asgore'; |
+ store.data.search.results = ['11', '13', '2']; |
+ store.data.selectedFolder = null; |
+ store.notifyObservers(); |
+ |
+ // Search results should not be able to be dragged onto, but can be dragged |
+ // from. |
+ dndManager.dragInfo_.handleChromeDragEnter(createDragData(['2'])); |
+ assertEquals( |
+ DropPosition.NONE, |
+ dndManager.calculateValidDropPositions_(getListItem('13'))); |
+ |
+ // Drags onto folders should work as per usual. |
+ assertEquals( |
+ DropPosition.ON | DropPosition.ABOVE | DropPosition.BELOW, |
+ dndManager.calculateValidDropPositions_(getFolderNode('112'))); |
+ }); |
+}); |