diff --git a/app/extensions/brave/content/scripts/inputHandler.js b/app/extensions/brave/content/scripts/inputHandler.js index 86a9ed03497..82c80acf069 100644 --- a/app/extensions/brave/content/scripts/inputHandler.js +++ b/app/extensions/brave/content/scripts/inputHandler.js @@ -151,3 +151,34 @@ document.addEventListener('keydown', (e /*: Event*/) => { break } }) + +function hasBraveDragData (dataTransfer) { + if (!dataTransfer || !dataTransfer.types) { + return false + } + for (let i = 0; i < dataTransfer.types.length; i++) { + let type = dataTransfer.types[i] + if (type && type.startsWith('application/x-brave-')) { + return true + } + } + return false +} + +function blockDndData (e) { + if (hasBraveDragData(e.dataTransfer)) { + // Block drag data from the Brave UI + try { + e.dataTransfer.dropEffect = 'none' + } catch (e) {} + e.preventDefault() + e.stopPropagation() + return false + } + return true +} + +window.addEventListener('dragover', blockDndData, true) +window.addEventListener('dragenter', blockDndData, true) +window.addEventListener('dragleave', blockDndData, true) +window.addEventListener('drop', blockDndData, true) diff --git a/app/renderer/components/main/main.js b/app/renderer/components/main/main.js index 14294044d7d..35a126cb247 100644 --- a/app/renderer/components/main/main.js +++ b/app/renderer/components/main/main.js @@ -68,6 +68,7 @@ const {isSourceAboutUrl} = require('../../../../js/lib/appUrlUtil') const {getCurrentWindowId, isMaximized, isFocused, isFullScreen} = require('../../currentWindow') const platformUtil = require('../../../common/lib/platformUtil') const urlUtil = require('../../../../js/lib/urlutil') +const {hasBraveDragData} = require('../../../../js/dndData') const isDarwin = platformUtil.isDarwin() const isWindows = platformUtil.isWindows() const isLinux = platformUtil.isLinux() @@ -445,8 +446,10 @@ class Main extends React.Component { // disable dnd by default window.addEventListener('dragover', function (event) { - // allow webviews to handle dnd - if (event.target.tagName === 'WEBVIEW') { + // allow webviews to handle dnd as long as the dragged object isn't from + // Brave itself + if (event.target.tagName === 'WEBVIEW' && + !hasBraveDragData(event.dataTransfer)) { return true } event.dataTransfer.dropEffect = 'none' @@ -455,8 +458,10 @@ class Main extends React.Component { }, true) window.addEventListener('drop', function (event) { - // allow webviews to handle dnd - if (event.target.tagName === 'WEBVIEW') { + // allow webviews to handle dnd as long as the dragged object isn't from + // Brave itself + if (event.target.tagName === 'WEBVIEW' && + !hasBraveDragData(event.dataTransfer)) { return true } event.preventDefault() diff --git a/js/dndData.js b/js/dndData.js index 6f3587f33ef..6e2e7e212b5 100644 --- a/js/dndData.js +++ b/js/dndData.js @@ -4,18 +4,33 @@ const Immutable = require('immutable') +const braveDragTypePrefix = 'application/x-brave-' + module.exports.hasDragData = (dataTransfer, dragType) => { - return dataTransfer.types.includes(`application/x-brave-${dragType}`) + return dataTransfer.types.includes(`${braveDragTypePrefix}${dragType}`) } module.exports.getDragData = (dataTransfer, dragType) => { - const data = dataTransfer.getData(`application/x-brave-${dragType}`) + const data = dataTransfer.getData(`${braveDragTypePrefix}${dragType}`) if (!data) { return undefined } return Immutable.fromJS(JSON.parse(data)) } +module.exports.hasBraveDragData = (dataTransfer) => { + if (!dataTransfer || !dataTransfer.types) { + return false + } + for (let i = 0; i < dataTransfer.types.length; i++) { + let type = dataTransfer.types[i] + if (type && type.startsWith(braveDragTypePrefix)) { + return true + } + } + return false +} + module.exports.setupDataTransferURL = (dataTransfer, location, title) => { dataTransfer.setData('text/plain', location) dataTransfer.setData('text/uri-list', location) diff --git a/test/unit/dndDataTest.js b/test/unit/dndDataTest.js new file mode 100644 index 00000000000..aab0e8a3aec --- /dev/null +++ b/test/unit/dndDataTest.js @@ -0,0 +1,25 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ +/* global describe, it */ + +const dndData = require('../../js/dndData') +const assert = require('assert') + +describe('dndData', function () { + describe('hasBraveDragData', function () { + it('returns false for empty transfer', () => { + assert.equal(dndData.hasBraveDragData(), false) + assert.equal(dndData.hasBraveDragData({types: []}), false) + assert.equal(dndData.hasBraveDragData({}), false) + }) + it('returns false for regular transfer', () => { + assert.equal(dndData.hasBraveDragData({types: ['text/plain']}), false) + assert.equal(dndData.hasBraveDragData({types: ['text/plain', 'text/html']}), false) + }) + it('returns true for brave transfer', () => { + assert.equal(dndData.hasBraveDragData({types: ['application/x-brave-tab']}), true) + assert.equal(dndData.hasBraveDragData({types: ['text/plain', 'text/uri-list', 'application/x-brave-bookmark']}), true) + }) + }) +})