Giter Club home page Giter Club logo

dropzone's People

Contributors

derrick56007 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

dropzone's Issues

Multiple DropZone issue

I have a form with multiple video and image fields (in this case two video and one image). All have the DropZone is a Stack.

I get several errors:

1> The image does not display, just the videos. If I remove one of the video widget, the image is rendered.

2> When I push a camera widget and pop back I get errors like this:
══╡ EXCEPTION CAUGHT BY SCHEDULER LIBRARY ╞═════════════════════════════════════════════════════════
The following IndexError was thrown during a scheduler callback:
RangeError (index): Index out of range: index must not be negative: -1

Can you help identify the issue?

The getter 'uri' was called on null

Hi Derrick,
I really interested with your package. But I can not use or something went wrong
onDrop: (List<html.File> files) {
always return error message "The getter 'uri' was called on null" and can not upload
Can you give advise?
Thank you

DropZone does not work After Hot Restart

When using a DropZone widget in a Flutter web app and using hot restart, the drop zone will stop working.

I investigated this and found out that the old listener is called instead of the new one after hot restart, i.e. the listener attached to the JS drop events survives the hot restart and no new listener is attached.

@derrick56007 do you have an idea how to fix this?

Enhancement: createObjectUrlFromBlob

The last method is not available, and has to be added explicitly.

final name = file.name;
final mime = file.type;
final length = file.size;

final url = Url.createObjectUrlFromBlob(file);

I believe that a file.url will be a useful addition.

DropZone not triggered over iFrame

I have an iFrame component and I wish to use DropZone - the onDrag and onDrop are not triggered.

Don't know if this is an enhancement, bug or an issue on how I created the iFrame:

html.IFrameElement _iframeElement;
_iframeElement = html.IFrameElement();
_iframeElement.id = iFrameId;
_iframeElement.allow = 'accelerometer; gyroscope;';
_iframeElement.allowFullscreen = true;
_iframeElement.src = initialVideo;
_iframeElement.style.border = 'none';
_iframeElement.style.cursor = 'auto';
_iframeElement.style.width = '100%';
_iframeElement.style.height = '100%';

// ignore: undefined_prefixed_name
ui.platformViewRegistry.registerViewFactory(iFrameId, (int viewId) => _iframeElement);

videoWidget = HtmlElementView(
  key: key,
  viewType: iFrameId,
);

Potential improvements to the library

Hi @derrick56007 thanks for putting this library together. I tried a few for Flutter web and this one seems to work the best for us on various browsers. We ran into a few issues with bugs around multiple drop targets (need a single instance of the drag target), the mouse leaving the window, etc. So I copied your code and refactored it some.

Happy to issue a PR at some point but a bit swamped at the moment.

There are some pieces that are coupled to our codebase in here but thought it'd be better to share the code here to start a discussion.

A few high level points

  • We have a single instance that handles the drag/drop events, stops the propagation, and relays them to widgets that need it. This is because if you do run e.stopPropagation() for every widget it won't work for multiple widgets (event gets swallowed).
  • We handle dragEnter/dragLeave because dragOver can't detect if your mouse leaves the window
  • Centralized the logic to handle _dragInBounds updates to better deal with edge cases
  • Reduced the number of null operators necessary with early returns

Let me know what you think

//@dart=2.12

// adapted from https://github.com/Derrick56007/dropzone
import 'dart:html';

import 'package:flutter/widgets.dart';
import 'package:turtle_app/file_manager/file_picker/html.dart';

import '../file_drop_target.dart';
import '../local_file.dart';
import 'package:turtle_app/util/event_handler.dart';

FileDropTarget createFileDropTarget({
  Key? key,
  required Widget child,
  Function()? onEnter,
  Function()? onExit,
  Function(Iterable<LocalFile>)? onDrop,
}) =>
    HtmlFileDropTarget(
      key: key,
      child: child,
      onEnter: onEnter,
      onExit: onExit,
      onDrop: onDrop,
    );

class HtmlFileDropTarget extends StatefulWidget implements FileDropTarget {
  const HtmlFileDropTarget({
    Key? key,
    required this.child,
    this.onEnter,
    this.onExit,
    this.onDrop,
  }) : super(key: key);

  final Widget child;

  final Function()? onEnter;
  final Function()? onExit;
  final Function(Iterable<LocalFile>)? onDrop;

  @override
  State<StatefulWidget> createState() => _HtmlFileDropTargetState();
}

class _HtmlFileDropTargetState extends State<HtmlFileDropTarget> {
  bool _dragInBounds = false;

  final _dispose = <void Function()>[];

  @override
  void dispose() {
    super.dispose();
    for (final cb in _dispose) cb();
  }

  @override
  void initState() {
    super.initState();

    _dispose.add(_controller.onDragEnter.addListener(_onDragEnter));
    _dispose.add(_controller.onDragOver.addListener(_onDragOver));
    _dispose.add(_controller.onDragLeave.addListener(_onDragLeave));
    _dispose.add(_controller.onDragDrop.addListener(_onDragDrop));
  }

  @override
  Widget build(BuildContext c) => widget.child;

  void _onDragEnter(MouseEvent e) {
    // can treat this like drag-over
    _onDragOver(e);
  }

  void _onDragLeave(MouseEvent e) {
    // mouse has left the window or drag region so consider this as onExit
    _setDragInBounds(false);
  }

  void _onDragOver(MouseEvent e) {
    final renderObject = context.findRenderObject();
    if (renderObject == null) {
      _setDragInBounds(false);
      return;
    }

    final bounds = _getGlobalPaintBounds(renderObject);
    _setDragInBounds(_isCursorWithinBounds(e, bounds));
  }

  void _onDragDrop(MouseEvent e) {
    _setDragInBounds(false);

    final htmlFiles = e.dataTransfer.files ?? [];
    final localFiles = htmlFiles.map(castToFile);
    widget.onDrop?.call(localFiles);
  }

  void _setDragInBounds(bool value) {
    if (_dragInBounds == value) return;
    _dragInBounds = value;

    if (_dragInBounds) {
      widget.onEnter?.call();
    } else {
      widget.onExit?.call();
    }
  }
}

Rect _getGlobalPaintBounds(RenderObject renderObject) {
  final translation = renderObject.getTransformTo(null).getTranslation();
  return renderObject.paintBounds.shift(Offset(translation.x, translation.y));
}

bool _isCursorWithinBounds(MouseEvent e, Rect bounds) {
  return e.layer.x >= bounds.left &&
      e.layer.x <= bounds.right &&
      e.layer.y >= bounds.top &&
      e.layer.y <= bounds.bottom;
}

class _HtmlFileDropTargetController {
  _HtmlFileDropTargetController() {
    final body = document.body!;

    body.onDragEnter.listen(_onDragEnter);
    body.onDragOver.listen(_onDragOver);
    body.onDragLeave.listen(_onDragLeave);
    body.onDrop.listen(_onDrop);
  }

  final onDragEnter = Event<MouseEvent>();
  final onDragOver = Event<MouseEvent>();
  final onDragLeave = Event<MouseEvent>();
  final onDragDrop = Event<MouseEvent>();

  void _onDragEnter(MouseEvent e) {
    _stopEvent(e);
    onDragEnter.notifyListeners(e);
  }

  void _onDragOver(MouseEvent e) {
    _stopEvent(e);
    onDragOver.notifyListeners(e);
  }

  void _onDragLeave(MouseEvent e) {
    _stopEvent(e);
    onDragLeave.notifyListeners(e);
  }

  void _onDrop(MouseEvent e) {
    _stopEvent(e);
    onDragDrop.notifyListeners(e);
  }
}

final _controller = _HtmlFileDropTargetController();

void _stopEvent(MouseEvent e) {
  e.stopPropagation();
  e.stopImmediatePropagation();
  e.preventDefault();
}

typedef EventHandler<T> = void Function(T event);

class Event<T> {
  final _listeners = <EventHandler<T>>{};

  void Function() addListener(EventHandler<T> listener) {
    _listeners.add(listener);
    return () => removeListener(listener);
  }

  void removeListener(EventHandler<T> listener) => _listeners.remove(listener);

  void notifyListeners(T event) {
    for (final listener in _listeners) listener(event);
  }

  void dispose() {
    _listeners.clear();
  }
}

Let me know if you have any questions on the changes in the code. Cheers!

onDrop() not called after files were selected using the pickFiles() method.

Hi,
I would like to display a list with all files that will be uploaded. If I drop them on the drop zone this can be easily done using the onDrop method. I add the filenames to a list and call setState -> my view with a listview is updated.
It is handy that this library also provides a method to open a file picker. Usually both is needed. But if files were picked with that file picker, the on drop is not called. So my view is not updated.
Ho to solve that? Would it be an option to change this library to also call onDop if the filepickes is used?

Your example doesn't work out the gate

Am I doing something wrong? I pasted this into my .dart code and I get the following error:

The argument type 'Null Function(List<File>)' can't be assigned to the parameter type 'dynamic Function(List<File>?)?'.

Your sample code:

DropZone
(
    onDragEnter: () { print('drag enter'); },
    onDragExit:  () { print('drag exit'); },
    onDrop: (List<html.File> files) { print('files dropped'); print(files); },
    child: Container ( width: 300, height: 300, )
)

I added the dependency to my pubspec.yaml and imported it.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.