Drag 'n Drop Inline Images Frontend

Review Request #6510 — Created Oct. 26, 2014 and discarded

Information

Review Board
master

Reviewers

Adding support for dragging and dropping images into the markdown editor. Instead of having upload their image first and then link to that image, users can simply drag-and-drop their image file into the markdown editor. This will upload the image to reviewboard and insert a link to that image in the editor.

These changes focus on the frontend work and include:

  • Extending the DnDUploaderView to support multiple overlays on the page. Multiple DropTargets can be registered with the DnDOverlay instance.
  • Extending the TextEditorView to support dragging and dropping images
  • Adding a resource for UserFileAttachments

Tested in Chrome 38.0.2125.122, Firefox 32.0.2, Safari 8.0, Internet Explorer 11.0.9600

All existing unit tests pass.

  • Added tests for the changes done to the TextEditorView (testing the appendText method and the Drag and Drop functionality).
  • Added tests for serialization and parsing of the UserFileAttachment resource.
  • Added tests for the DnDUploader functionality.

Description From Last Updated

It might be better to use the / / multi line comments here

ML mloyzer

Wrap to 80 columns.

daviddavid

Wrap to 80 columns.

daviddavid

Wrap to 80 columns.

daviddavid

Variable definitions should all be the first thing in the method.

daviddavid

Can you leave this as-is?

daviddavid

I'd suggest defining a $window as the first thing, and then using that for both. That way it doesn't have …

daviddavid

Wrap to 80 column.

daviddavid

Wrap to 80 columns.

daviddavid

Wrap to 80 columns.

daviddavid

Wrap to 80 columns.

daviddavid

Wrap to 80 columns.

daviddavid

Wrap to 80 columns.

daviddavid

Wrap to 80 columns.

daviddavid

Nit - let's put these in the same order as the function args.

mike_conleymike_conley

Might as well throw bmp, tiff and svg in there too.

mike_conleymike_conley

This can be: return imageExtensions.some(function(extension) { return file.name.match(new RegExp("\\." + extension + "$", "i")); }); That'll work in IE9 and …

mike_conleymike_conley

Nit "and" -> "an"

mike_conleymike_conley

Even though this is supposed to be a very cheap request, synchronous XHR is best to be avoided, since it …

mike_conleymike_conley

We probably need some error handling here in case things go wrong with the upload.

mike_conleymike_conley

Where are these magic 6's coming from?

mike_conleymike_conley

Ah - is there were the magic 6 comes from? Can we apply an attribute or class on the element …

mike_conleymike_conley

Might be good to get this stuff in CSS instead - perhaps a class for the window overlay. Or a …

mike_conleymike_conley

This seems like it wants to be a model but doesn't want to adhere to model conventions. Models work with …

chipx86chipx86

This doesn't buy us anything that new already gives us. It's actually nicer to pass in the arguments as a …

chipx86chipx86

Blank line between these.

chipx86chipx86

And here.

chipx86chipx86

Two blank lines.

chipx86chipx86

Blank line between these.

chipx86chipx86

Most of these can go inline below, saving some lines of code.

chipx86chipx86

This can break down the road if styles are changed. Instead, use outerWidth() and outerHeight(), which account for the border.

chipx86chipx86

This should be a single .css({ ... }) statement.

chipx86chipx86

The var should go at the top of the file.

chipx86chipx86

Same comments here as above.

chipx86chipx86

No blank line here.

chipx86chipx86

Two blank lines.

chipx86chipx86

Not every page will need this. Is it not sufficient to create an instance in ReviewRequestEditorView, or any other pages …

chipx86chipx86
reviewbot
  1. Tool: PEP8 Style Checker
    Processed Files:
        reviewboard/staticbundles.py
    
    Ignored Files:
        reviewboard/static/rb/js/views/dndUploaderView.js
        reviewboard/static/rb/js/resources/models/fileAttachmentUserModel.js
        reviewboard/static/rb/js/views/reviewRequestEditorView.js
        reviewboard/static/rb/js/resources/models/apiTokenModel.js
        reviewboard/static/rb/js/views/commentDialogView.js
        reviewboard/static/rb/js/views/markdownEditorView.js
    
    
    
    Tool: Pyflakes
    Processed Files:
        reviewboard/staticbundles.py
    
    Ignored Files:
        reviewboard/static/rb/js/views/dndUploaderView.js
        reviewboard/static/rb/js/resources/models/fileAttachmentUserModel.js
        reviewboard/static/rb/js/views/reviewRequestEditorView.js
        reviewboard/static/rb/js/resources/models/apiTokenModel.js
        reviewboard/static/rb/js/views/commentDialogView.js
        reviewboard/static/rb/js/views/markdownEditorView.js
    
    
  2. 
      
dkus
chipx86
  1. Is this still valid, or has it been replaced by /r/6454/?

    1. This is indeed still valid. These changes cover the frontend work, the other review request is for the backend.

  2. 
      
dkus
reviewbot
  1. Tool: PEP8 Style Checker
    Processed Files:
        reviewboard/staticbundles.py
    
    Ignored Files:
        reviewboard/static/rb/js/views/reviewRequestEditorView.js
        reviewboard/static/rb/js/resources/models/userFileAttachmentModel.js
        reviewboard/static/rb/js/views/dndUploaderView.js
        reviewboard/static/rb/js/models/userFileModel.js
        reviewboard/static/rb/js/resources/models/apiTokenModel.js
        reviewboard/static/rb/js/views/commentDialogView.js
        reviewboard/static/rb/js/views/markdownEditorView.js
    
    
    
    Tool: Pyflakes
    Processed Files:
        reviewboard/staticbundles.py
    
    Ignored Files:
        reviewboard/static/rb/js/views/reviewRequestEditorView.js
        reviewboard/static/rb/js/resources/models/userFileAttachmentModel.js
        reviewboard/static/rb/js/views/dndUploaderView.js
        reviewboard/static/rb/js/models/userFileModel.js
        reviewboard/static/rb/js/resources/models/apiTokenModel.js
        reviewboard/static/rb/js/views/commentDialogView.js
        reviewboard/static/rb/js/views/markdownEditorView.js
    
    
  2. 
      
ML
  1. 
      
  2. Show all issues

    It might be better to use the / / multi line comments here

  3. 
      
dkus
reviewbot
  1. Tool: PEP8 Style Checker
    Processed Files:
        reviewboard/staticbundles.py
    
    Ignored Files:
        reviewboard/static/rb/js/models/dndDropTarget.js
        reviewboard/static/rb/css/ui/dnd-uploader.less
        reviewboard/static/rb/js/resources/models/userFileAttachmentModel.js
        reviewboard/static/rb/js/views/dndUploaderView.js
        reviewboard/static/rb/js/models/userFileModel.js
        reviewboard/static/rb/css/common.less
        reviewboard/static/rb/js/pages/views/pageView.js
        reviewboard/static/rb/js/ui/views/textEditorView.js
        reviewboard/static/rb/js/resources/models/apiTokenModel.js
        reviewboard/static/rb/js/views/reviewRequestEditorView.js
        reviewboard/static/rb/js/pages/views/reviewablePageView.js
    
    
    
    Tool: Pyflakes
    Processed Files:
        reviewboard/staticbundles.py
    
    Ignored Files:
        reviewboard/static/rb/js/models/dndDropTarget.js
        reviewboard/static/rb/css/ui/dnd-uploader.less
        reviewboard/static/rb/js/resources/models/userFileAttachmentModel.js
        reviewboard/static/rb/js/views/dndUploaderView.js
        reviewboard/static/rb/js/models/userFileModel.js
        reviewboard/static/rb/css/common.less
        reviewboard/static/rb/js/pages/views/pageView.js
        reviewboard/static/rb/js/ui/views/textEditorView.js
        reviewboard/static/rb/js/resources/models/apiTokenModel.js
        reviewboard/static/rb/js/views/reviewRequestEditorView.js
        reviewboard/static/rb/js/pages/views/reviewablePageView.js
    
    
  2. 
      
dkus
dkus
reviewbot
  1. Tool: Pyflakes
    Processed Files:
        reviewboard/staticbundles.py
    
    Ignored Files:
        reviewboard/static/rb/js/models/dndDropTarget.js
        reviewboard/static/rb/css/ui/dnd-uploader.less
        reviewboard/static/rb/js/views/tests/dndUploaderViewTests.js
        reviewboard/static/rb/js/resources/models/userFileAttachmentModel.js
        reviewboard/static/rb/js/views/dndUploaderView.js
        reviewboard/static/rb/js/resources/models/tests/userFileAttachmentModelTests.js
        reviewboard/static/rb/js/ui/views/tests/textEditorViewTests.js
        reviewboard/static/rb/css/common.less
        reviewboard/static/rb/js/ui/views/textEditorView.js
        reviewboard/static/rb/js/views/reviewRequestEditorView.js
    
    
    
    Tool: PEP8 Style Checker
    Processed Files:
        reviewboard/staticbundles.py
    
    Ignored Files:
        reviewboard/static/rb/js/models/dndDropTarget.js
        reviewboard/static/rb/css/ui/dnd-uploader.less
        reviewboard/static/rb/js/views/tests/dndUploaderViewTests.js
        reviewboard/static/rb/js/resources/models/userFileAttachmentModel.js
        reviewboard/static/rb/js/views/dndUploaderView.js
        reviewboard/static/rb/js/resources/models/tests/userFileAttachmentModelTests.js
        reviewboard/static/rb/js/ui/views/tests/textEditorViewTests.js
        reviewboard/static/rb/css/common.less
        reviewboard/static/rb/js/ui/views/textEditorView.js
        reviewboard/static/rb/js/views/reviewRequestEditorView.js
    
    
  2. 
      
david
  1. 
      
  2. Show all issues

    Wrap to 80 columns.

  3. Show all issues

    Wrap to 80 columns.

  4. Show all issues

    Wrap to 80 columns.

  5. Show all issues

    Variable definitions should all be the first thing in the method.

  6. Show all issues

    Can you leave this as-is?

  7. Show all issues

    I'd suggest defining a $window as the first thing, and then using that for both. That way it doesn't have to run the jquery selector twice.

  8. Show all issues

    Wrap to 80 column.

  9. Show all issues

    Wrap to 80 columns.

  10. Show all issues

    Wrap to 80 columns.

  11. Show all issues

    Wrap to 80 columns.

  12. Show all issues

    Wrap to 80 columns.

  13. Show all issues

    Wrap to 80 columns.

  14. Show all issues

    Wrap to 80 columns.

  15. 
      
dkus
reviewbot
  1. Tool: Pyflakes
    Processed Files:
        reviewboard/staticbundles.py
    
    Ignored Files:
        reviewboard/static/rb/js/models/dndDropTarget.js
        reviewboard/static/rb/css/ui/dnd-uploader.less
        reviewboard/static/rb/js/views/tests/dndUploaderViewTests.js
        reviewboard/static/rb/js/resources/models/userFileAttachmentModel.js
        reviewboard/static/rb/js/views/dndUploaderView.js
        reviewboard/static/rb/js/resources/models/tests/userFileAttachmentModelTests.js
        reviewboard/static/rb/js/ui/views/tests/textEditorViewTests.js
        reviewboard/static/rb/css/common.less
        reviewboard/static/rb/js/ui/views/textEditorView.js
        reviewboard/static/rb/js/views/reviewRequestEditorView.js
    
    
    
    Tool: PEP8 Style Checker
    Processed Files:
        reviewboard/staticbundles.py
    
    Ignored Files:
        reviewboard/static/rb/js/models/dndDropTarget.js
        reviewboard/static/rb/css/ui/dnd-uploader.less
        reviewboard/static/rb/js/views/tests/dndUploaderViewTests.js
        reviewboard/static/rb/js/resources/models/userFileAttachmentModel.js
        reviewboard/static/rb/js/views/dndUploaderView.js
        reviewboard/static/rb/js/resources/models/tests/userFileAttachmentModelTests.js
        reviewboard/static/rb/js/ui/views/tests/textEditorViewTests.js
        reviewboard/static/rb/css/common.less
        reviewboard/static/rb/js/ui/views/textEditorView.js
        reviewboard/static/rb/js/views/reviewRequestEditorView.js
    
    
  2. 
      
dkus
mike_conley
  1. 
      
  2. reviewboard/static/rb/js/models/dndDropTarget.js (Diff revision 5)
     
     
     
     
    Show all issues

    Nit - let's put these in the same order as the function args.

  3. Show all issues

    Might as well throw bmp, tiff and svg in there too.

  4. reviewboard/static/rb/js/ui/views/textEditorView.js (Diff revision 5)
     
     
     
     
     
     
     
    Show all issues

    This can be:

    return imageExtensions.some(function(extension) { return file.name.match(new RegExp("\\." + extension + "$", "i")); });

    That'll work in IE9 and up.

  5. Show all issues

    Nit "and" -> "an"

  6. Show all issues

    Even though this is supposed to be a very cheap request, synchronous XHR is best to be avoided, since it 100% blocks JS execution. If there are network problems (say, our DNS server is flaking out on us), this can absolutely lock up everything in the user's tab (or their entire browser).

    Is there a way of doing this asynchronously, and passing in a callback to do the upload of the whole file? Also, what happens if that first save fails?

  7. Show all issues

    We probably need some error handling here in case things go wrong with the upload.

    1. What would you recommend happen if things go wrong? Also, it can fail at 2 places (when doing the first POST and then after when updating with the file), should we handle both errors?

    2. Good question. Our error reporting isn't very consistent - at times, we show an error that can be unfolded from the "Loading" spinner when we're updating a review request. Other times, we pop up an alert (ugh). Othertimes, there's inline error reporting (like when you try to set a reviewer on a review request to a username that does not exist).

      Do we show any kind of progress or spinner while the upload is occurring? Ideally, the error would be located in or around there.

    3. We don't show any progress / spinner while uploading right now. It's something that we decided to cut out so that I could have something finished before the pencils down date.

    4. Ah, right. In that case, we should at least log it to the error console, and then follow up bugs for more robust error reporting.

    5. Alright. Should I just use console.error()? I don't see that being used anywhere in the code base.

  8. Show all issues

    Where are these magic 6's coming from?

  9. Show all issues

    Ah - is there were the magic 6 comes from?

    Can we apply an attribute or class on the element instead, and have a selector to apply the border? Putting non-positional styling in JS should be avoided if possible.

  10. Show all issues

    Might be good to get this stuff in CSS instead - perhaps a class for the window overlay. Or a separate class for the text input overlays.

  11. 
      
dkus
reviewbot
  1. Tool: Pyflakes
    Processed Files:
        reviewboard/staticbundles.py
    
    Ignored Files:
        reviewboard/static/rb/js/models/dndDropTarget.js
        reviewboard/static/rb/css/ui/dnd-uploader.less
        reviewboard/static/rb/js/views/tests/dndUploaderViewTests.js
        reviewboard/static/rb/js/resources/models/userFileAttachmentModel.js
        reviewboard/static/rb/js/views/dndUploaderView.js
        reviewboard/static/rb/js/resources/models/tests/userFileAttachmentModelTests.js
        reviewboard/static/rb/js/ui/views/tests/textEditorViewTests.js
        reviewboard/static/rb/css/common.less
        reviewboard/static/rb/js/ui/views/textEditorView.js
        reviewboard/static/rb/js/views/reviewRequestEditorView.js
    
    
    
    Tool: PEP8 Style Checker
    Processed Files:
        reviewboard/staticbundles.py
    
    Ignored Files:
        reviewboard/static/rb/js/models/dndDropTarget.js
        reviewboard/static/rb/css/ui/dnd-uploader.less
        reviewboard/static/rb/js/views/tests/dndUploaderViewTests.js
        reviewboard/static/rb/js/resources/models/userFileAttachmentModel.js
        reviewboard/static/rb/js/views/dndUploaderView.js
        reviewboard/static/rb/js/resources/models/tests/userFileAttachmentModelTests.js
        reviewboard/static/rb/js/ui/views/tests/textEditorViewTests.js
        reviewboard/static/rb/css/common.less
        reviewboard/static/rb/js/ui/views/textEditorView.js
        reviewboard/static/rb/js/views/reviewRequestEditorView.js
    
    
  2. 
      
dkus
reviewbot
  1. Tool: Pyflakes
    Processed Files:
        reviewboard/staticbundles.py
    
    Ignored Files:
        reviewboard/static/rb/js/models/dndDropTarget.js
        reviewboard/static/rb/css/ui/dnd-uploader.less
        reviewboard/static/rb/js/views/tests/dndUploaderViewTests.js
        reviewboard/static/rb/js/resources/models/userFileAttachmentModel.js
        reviewboard/static/rb/js/views/dndUploaderView.js
        reviewboard/static/rb/js/resources/models/tests/userFileAttachmentModelTests.js
        reviewboard/static/rb/js/ui/views/tests/textEditorViewTests.js
        reviewboard/static/rb/css/common.less
        reviewboard/static/rb/js/ui/views/textEditorView.js
        reviewboard/static/rb/js/views/reviewRequestEditorView.js
    
    
    
    Tool: PEP8 Style Checker
    Processed Files:
        reviewboard/staticbundles.py
    
    Ignored Files:
        reviewboard/static/rb/js/models/dndDropTarget.js
        reviewboard/static/rb/css/ui/dnd-uploader.less
        reviewboard/static/rb/js/views/tests/dndUploaderViewTests.js
        reviewboard/static/rb/js/resources/models/userFileAttachmentModel.js
        reviewboard/static/rb/js/views/dndUploaderView.js
        reviewboard/static/rb/js/resources/models/tests/userFileAttachmentModelTests.js
        reviewboard/static/rb/js/ui/views/tests/textEditorViewTests.js
        reviewboard/static/rb/css/common.less
        reviewboard/static/rb/js/ui/views/textEditorView.js
        reviewboard/static/rb/js/views/reviewRequestEditorView.js
    
    
  2. 
      
chipx86
  1. Looking good. Got some things to fix up that are largely stylistic or JavaScript/jQuery/Backbone-isms that will help reduce code and logic.

  2. reviewboard/static/rb/js/models/dndDropTarget.js (Diff revision 7)
     
     
     
     
     
     
     
     
     
     
     
     
     
     
    Show all issues

    This seems like it wants to be a model but doesn't want to adhere to model conventions.

    Models work with attributes instead of direct properties (like target). It also uses defaults for any default options.

    You probably want to fill defaults with default values for target, dropAction, context, and active. You can then remove the initialize call.

    Consumers will then need to access this data using get().

    This is also missing documentation.

  3. reviewboard/static/rb/js/models/dndDropTarget.js (Diff revision 7)
     
     
     
     
     
     
     
     
    Show all issues

    This doesn't buy us anything that new already gives us. It's actually nicer to pass in the arguments as a dictionary instead of positional, since it's more self-documenting.

  4. Show all issues

    Blank line between these.

  5. Show all issues

    And here.

  6. Show all issues

    Two blank lines.

  7. Show all issues

    Blank line between these.

  8. reviewboard/static/rb/js/views/dndUploaderView.js (Diff revision 7)
     
     
     
     
     
     
     
    Show all issues

    Most of these can go inline below, saving some lines of code.

  9. Show all issues

    This can break down the road if styles are changed. Instead, use outerWidth() and outerHeight(), which account for the border.

    1. This won't really work for my case. It's not the target that has the borders, it's the element who's height/width I'm setting. I would need to do something like setOuterWidth() and setOuterHeight() (I don't think those exist). Just setting the height of the element doesn't include it's borders, so with the borders it exceeds the height of the target.

    2. Ahh. What you can do then is:

      var width = target.width() + this.$el.getExtents('b', 'lr'),
          height = target.height() + this.$el.getExtents('b', 'tb');
      

      That will get the total border size for the proper dimensions on this.$el add that to the target width/height.

    3. Works fine in Firefox but doesn't seem to work in Chrome (returning 0 instead of 6).

  10. Show all issues

    This should be a single .css({ ... }) statement.

  11. Show all issues

    The var should go at the top of the file.

  12. Show all issues

    Same comments here as above.

  13. Show all issues

    No blank line here.

  14. Show all issues

    Two blank lines.

  15. Show all issues

    Not every page will need this. Is it not sufficient to create an instance in ReviewRequestEditorView, or any other pages that need this?

    1. What if I create it in the ReviewablePageView?

    2. That works fine too.

  16. 
      
dkus
reviewbot
  1. Tool: PEP8 Style Checker
    Processed Files:
        reviewboard/staticbundles.py
    
    Ignored Files:
        reviewboard/static/rb/js/models/dndDropTarget.js
        reviewboard/static/rb/css/ui/dnd-uploader.less
        reviewboard/static/rb/js/views/tests/dndUploaderViewTests.js
        reviewboard/static/rb/js/resources/models/userFileAttachmentModel.js
        reviewboard/static/rb/js/views/dndUploaderView.js
        reviewboard/static/rb/js/pages/views/tests/reviewablePageViewTests.js
        reviewboard/static/rb/js/resources/models/tests/userFileAttachmentModelTests.js
        reviewboard/static/rb/js/ui/views/tests/textEditorViewTests.js
        reviewboard/static/rb/css/common.less
        reviewboard/static/rb/js/ui/views/textEditorView.js
        reviewboard/static/rb/js/views/reviewRequestEditorView.js
        reviewboard/static/rb/js/pages/views/reviewablePageView.js
    
    
    
    Tool: Pyflakes
    Processed Files:
        reviewboard/staticbundles.py
    
    Ignored Files:
        reviewboard/static/rb/js/models/dndDropTarget.js
        reviewboard/static/rb/css/ui/dnd-uploader.less
        reviewboard/static/rb/js/views/tests/dndUploaderViewTests.js
        reviewboard/static/rb/js/resources/models/userFileAttachmentModel.js
        reviewboard/static/rb/js/views/dndUploaderView.js
        reviewboard/static/rb/js/pages/views/tests/reviewablePageViewTests.js
        reviewboard/static/rb/js/resources/models/tests/userFileAttachmentModelTests.js
        reviewboard/static/rb/js/ui/views/tests/textEditorViewTests.js
        reviewboard/static/rb/css/common.less
        reviewboard/static/rb/js/ui/views/textEditorView.js
        reviewboard/static/rb/js/views/reviewRequestEditorView.js
        reviewboard/static/rb/js/pages/views/reviewablePageView.js
    
    
  2. 
      
dkus
reviewbot
  1. Tool: Pyflakes
    Processed Files:
        reviewboard/staticbundles.py
    
    Ignored Files:
        reviewboard/static/rb/js/models/dndDropTarget.js
        reviewboard/static/rb/css/ui/dnd-uploader.less
        reviewboard/static/rb/js/views/tests/dndUploaderViewTests.js
        reviewboard/static/rb/js/resources/models/userFileAttachmentModel.js
        reviewboard/static/rb/js/views/dndUploaderView.js
        reviewboard/static/rb/js/pages/views/tests/reviewablePageViewTests.js
        reviewboard/static/rb/js/resources/models/tests/userFileAttachmentModelTests.js
        reviewboard/static/rb/js/ui/views/tests/textEditorViewTests.js
        reviewboard/static/rb/css/common.less
        reviewboard/static/rb/js/ui/views/textEditorView.js
        reviewboard/static/rb/js/views/reviewRequestEditorView.js
        reviewboard/static/rb/js/pages/views/reviewablePageView.js
    
    
    
    Tool: PEP8 Style Checker
    Processed Files:
        reviewboard/staticbundles.py
    
    Ignored Files:
        reviewboard/static/rb/js/models/dndDropTarget.js
        reviewboard/static/rb/css/ui/dnd-uploader.less
        reviewboard/static/rb/js/views/tests/dndUploaderViewTests.js
        reviewboard/static/rb/js/resources/models/userFileAttachmentModel.js
        reviewboard/static/rb/js/views/dndUploaderView.js
        reviewboard/static/rb/js/pages/views/tests/reviewablePageViewTests.js
        reviewboard/static/rb/js/resources/models/tests/userFileAttachmentModelTests.js
        reviewboard/static/rb/js/ui/views/tests/textEditorViewTests.js
        reviewboard/static/rb/css/common.less
        reviewboard/static/rb/js/ui/views/textEditorView.js
        reviewboard/static/rb/js/views/reviewRequestEditorView.js
        reviewboard/static/rb/js/pages/views/reviewablePageView.js
    
    
  2. 
      
dkus
Review request changed
Status:
Discarded
Change Summary:

Discarded in favor of /r/8147/