Merge pull request #6333 from electron/drag-item
Add `webContents.startDrag(item)` API
This commit is contained in:
commit
83ae14f2ed
8 changed files with 206 additions and 0 deletions
|
@ -17,6 +17,7 @@
|
|||
#include "atom/browser/lib/bluetooth_chooser.h"
|
||||
#include "atom/browser/native_window.h"
|
||||
#include "atom/browser/net/atom_network_delegate.h"
|
||||
#include "atom/browser/ui/drag_util.h"
|
||||
#include "atom/browser/web_contents_permission_helper.h"
|
||||
#include "atom/browser/web_contents_preferences.h"
|
||||
#include "atom/browser/web_view_guest_delegate.h"
|
||||
|
@ -1205,6 +1206,35 @@ void WebContents::EndFrameSubscription() {
|
|||
view->EndFrameSubscription();
|
||||
}
|
||||
|
||||
void WebContents::StartDrag(const mate::Dictionary& item,
|
||||
mate::Arguments* args) {
|
||||
base::FilePath file;
|
||||
std::vector<base::FilePath> files;
|
||||
if (!item.Get("files", &files) && item.Get("file", &file)) {
|
||||
files.push_back(file);
|
||||
}
|
||||
|
||||
mate::Handle<NativeImage> icon;
|
||||
if (!item.Get("icon", &icon) && !file.empty()) {
|
||||
// TODO(zcbenz): Set default icon from file.
|
||||
}
|
||||
|
||||
// Error checking.
|
||||
if (icon.IsEmpty()) {
|
||||
args->ThrowError("icon must be set");
|
||||
return;
|
||||
}
|
||||
|
||||
// Start dragging.
|
||||
if (!files.empty()) {
|
||||
base::MessageLoop::ScopedNestableTaskAllower allow(
|
||||
base::MessageLoop::current());
|
||||
DragFileItems(files, icon->image(), web_contents()->GetNativeView());
|
||||
} else {
|
||||
args->ThrowError("There is nothing to drag");
|
||||
}
|
||||
}
|
||||
|
||||
void WebContents::OnCursorChange(const content::WebCursor& cursor) {
|
||||
content::WebCursor::CursorInfo info;
|
||||
cursor.GetCursorInfo(&info);
|
||||
|
@ -1324,6 +1354,7 @@ void WebContents::BuildPrototype(v8::Isolate* isolate,
|
|||
.SetMethod("beginFrameSubscription",
|
||||
&WebContents::BeginFrameSubscription)
|
||||
.SetMethod("endFrameSubscription", &WebContents::EndFrameSubscription)
|
||||
.SetMethod("startDrag", &WebContents::StartDrag)
|
||||
.SetMethod("setSize", &WebContents::SetSize)
|
||||
.SetMethod("isGuest", &WebContents::IsGuest)
|
||||
.SetMethod("getType", &WebContents::GetType)
|
||||
|
|
|
@ -142,6 +142,9 @@ class WebContents : public mate::TrackableObject<WebContents>,
|
|||
void BeginFrameSubscription(mate::Arguments* args);
|
||||
void EndFrameSubscription();
|
||||
|
||||
// Dragging native items.
|
||||
void StartDrag(const mate::Dictionary& item, mate::Arguments* args);
|
||||
|
||||
// Methods for creating <webview>.
|
||||
void SetSize(const SetSizeParams& params);
|
||||
bool IsGuest() const;
|
||||
|
|
24
atom/browser/ui/drag_util.h
Normal file
24
atom/browser/ui/drag_util.h
Normal file
|
@ -0,0 +1,24 @@
|
|||
// Copyright (c) 2016 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef ATOM_BROWSER_UI_DRAG_UTIL_H_
|
||||
#define ATOM_BROWSER_UI_DRAG_UTIL_H_
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "ui/gfx/image/image.h"
|
||||
|
||||
namespace base {
|
||||
class FilePath;
|
||||
}
|
||||
|
||||
namespace atom {
|
||||
|
||||
void DragFileItems(const std::vector<base::FilePath>& files,
|
||||
const gfx::Image& icon,
|
||||
gfx::NativeView view);
|
||||
|
||||
} // namespace atom
|
||||
|
||||
#endif // ATOM_BROWSER_UI_DRAG_UTIL_H_
|
58
atom/browser/ui/drag_util_mac.mm
Normal file
58
atom/browser/ui/drag_util_mac.mm
Normal file
|
@ -0,0 +1,58 @@
|
|||
// Copyright (c) 2016 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
#include "atom/browser/ui/drag_util.h"
|
||||
#include "base/files/file_path.h"
|
||||
#include "base/strings/sys_string_conversions.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
namespace {
|
||||
|
||||
// Write information about the file being dragged to the pasteboard.
|
||||
void AddFilesToPasteboard(NSPasteboard* pasteboard,
|
||||
const std::vector<base::FilePath>& files) {
|
||||
NSMutableArray* fileList = [NSMutableArray array];
|
||||
for (const base::FilePath& file : files)
|
||||
[fileList addObject:base::SysUTF8ToNSString(file.value())];
|
||||
[pasteboard declareTypes:[NSArray arrayWithObject:NSFilenamesPboardType]
|
||||
owner:nil];
|
||||
[pasteboard setPropertyList:fileList forType:NSFilenamesPboardType];
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void DragFileItems(const std::vector<base::FilePath>& files,
|
||||
const gfx::Image& icon,
|
||||
gfx::NativeView view) {
|
||||
NSPasteboard* pasteboard = [NSPasteboard pasteboardWithName:NSDragPboard];
|
||||
AddFilesToPasteboard(pasteboard, files);
|
||||
|
||||
// Synthesize a drag event, since we don't have access to the actual event
|
||||
// that initiated a drag (possibly consumed by the Web UI, for example).
|
||||
NSPoint position = [[view window] mouseLocationOutsideOfEventStream];
|
||||
NSTimeInterval eventTime = [[NSApp currentEvent] timestamp];
|
||||
NSEvent* dragEvent = [NSEvent mouseEventWithType:NSLeftMouseDragged
|
||||
location:position
|
||||
modifierFlags:NSLeftMouseDraggedMask
|
||||
timestamp:eventTime
|
||||
windowNumber:[[view window] windowNumber]
|
||||
context:nil
|
||||
eventNumber:0
|
||||
clickCount:1
|
||||
pressure:1.0];
|
||||
|
||||
// Run the drag operation.
|
||||
[[view window] dragImage:icon.ToNSImage()
|
||||
at:position
|
||||
offset:NSZeroSize
|
||||
event:dragEvent
|
||||
pasteboard:pasteboard
|
||||
source:view
|
||||
slideBack:YES];
|
||||
}
|
||||
|
||||
} // namespace atom
|
48
atom/browser/ui/drag_util_views.cc
Normal file
48
atom/browser/ui/drag_util_views.cc
Normal file
|
@ -0,0 +1,48 @@
|
|||
// Copyright (c) 2016 GitHub, Inc.
|
||||
// Use of this source code is governed by the MIT license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "atom/browser/ui/drag_util.h"
|
||||
|
||||
#include "ui/aura/window.h"
|
||||
#include "ui/base/dragdrop/drag_drop_types.h"
|
||||
#include "ui/base/dragdrop/drag_utils.h"
|
||||
#include "ui/base/dragdrop/file_info.h"
|
||||
#include "ui/base/dragdrop/os_exchange_data.h"
|
||||
#include "ui/gfx/geometry/point.h"
|
||||
#include "ui/gfx/screen.h"
|
||||
#include "ui/views/widget/widget.h"
|
||||
#include "ui/wm/public/drag_drop_client.h"
|
||||
|
||||
namespace atom {
|
||||
|
||||
void DragFileItems(const std::vector<base::FilePath>& files,
|
||||
const gfx::Image& icon,
|
||||
gfx::NativeView view) {
|
||||
// Set up our OLE machinery
|
||||
ui::OSExchangeData data;
|
||||
|
||||
drag_utils::CreateDragImageForFile(files[0], icon.AsImageSkia(), &data);
|
||||
|
||||
std::vector<ui::FileInfo> file_infos;
|
||||
for (const base::FilePath& file : files) {
|
||||
file_infos.push_back(ui::FileInfo(file, base::FilePath()));
|
||||
}
|
||||
data.SetFilenames(file_infos);
|
||||
|
||||
aura::Window* root_window = view->GetRootWindow();
|
||||
if (!root_window || !aura::client::GetDragDropClient(root_window))
|
||||
return;
|
||||
|
||||
gfx::Point location = gfx::Screen::GetScreen()->GetCursorScreenPoint();
|
||||
// TODO(varunjain): Properly determine and send DRAG_EVENT_SOURCE below.
|
||||
aura::client::GetDragDropClient(root_window)->StartDragAndDrop(
|
||||
data,
|
||||
root_window,
|
||||
view,
|
||||
location,
|
||||
ui::DragDropTypes::DRAG_COPY | ui::DragDropTypes::DRAG_LINK,
|
||||
ui::DragDropTypes::DRAG_EVENT_SOURCE_MOUSE);
|
||||
}
|
||||
|
||||
} // namespace atom
|
|
@ -943,6 +943,16 @@ defaults to `false`.
|
|||
|
||||
End subscribing for frame presentation events.
|
||||
|
||||
### `webContents.startDrag(item)`
|
||||
|
||||
* `item` object
|
||||
* `file` String
|
||||
* `icon` [NativeImage](native-image.md)
|
||||
|
||||
Sets the `item` as dragging item for current drag-drop operation, `file` is the
|
||||
absolute path of the file to be dragged, and `icon` is the image showing under
|
||||
the cursor when dragging.
|
||||
|
||||
### `webContents.savePage(fullPath, saveType, callback)`
|
||||
|
||||
* `fullPath` String - The full file path.
|
||||
|
|
|
@ -321,6 +321,35 @@ win.setRepresentedFilename('/etc/passwd');
|
|||
win.setDocumentEdited(true);
|
||||
```
|
||||
|
||||
## Dragging files out of the window
|
||||
|
||||
For certain kinds of apps that manipulate on files, it is important to be able
|
||||
to drag files from Electron to other apps. To implement this feature in your
|
||||
app, you need to call `webContents.startDrag(item)` API on `ondragstart` event.
|
||||
|
||||
In web page:
|
||||
|
||||
```html
|
||||
<a href="#" id="drag">item</a>
|
||||
<script type="text/javascript" charset="utf-8">
|
||||
document.getElementById('drag').ondragstart = (event) => {
|
||||
event.preventDefault()
|
||||
ipcRenderer.send('ondragstart', '/path/to/item')
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
In the main process:
|
||||
|
||||
```javascript
|
||||
ipcMain.on('ondragstart', (event, filePath) => {
|
||||
event.sender.startDrag({
|
||||
file: filePath,
|
||||
icon: '/path/to/icon.png'
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
[addrecentdocument]: ../api/app.md#appaddrecentdocumentpath-os-x-windows
|
||||
[clearrecentdocuments]: ../api/app.md#appclearrecentdocuments-os-x-windows
|
||||
[setusertaskstasks]: ../api/app.md#appsetusertaskstasks-windows
|
||||
|
|
|
@ -245,6 +245,9 @@
|
|||
'atom/browser/ui/atom_menu_model.h',
|
||||
'atom/browser/ui/cocoa/atom_menu_controller.h',
|
||||
'atom/browser/ui/cocoa/atom_menu_controller.mm',
|
||||
'atom/browser/ui/drag_util_mac.mm',
|
||||
'atom/browser/ui/drag_util_views.cc',
|
||||
'atom/browser/ui/drag_util.h',
|
||||
'atom/browser/ui/file_dialog.h',
|
||||
'atom/browser/ui/file_dialog_gtk.cc',
|
||||
'atom/browser/ui/file_dialog_mac.mm',
|
||||
|
|
Loading…
Reference in a new issue