Needs work
Project:
CKEditor 4 - WYSIWYG HTML editor
Version:
1.0.x-dev
Component:
Code
Priority:
Major
Category:
Feature request
Assigned:
Unassigned
Reporter:
Created:
31 Aug 2015 at 14:58 UTC
Updated:
9 Sep 2022 at 11:26 UTC
Jump to comment: Most recent, Most recent file
Comments
Comment #2
yched commentedMight be interesting to reach out to @jcisio, he started to work on an intergration of file drag-n-drop with the D7 scald widgets : https://www.drupal.org/project/direct_upload
Comment #3
yched commentedAlso, in D8, "media / scald entity embed" is entity_embed, which, if enabled, will also likely want to integrate with a "drag-and-drop image upload" action.
So I guess we'll need to let site admins control what happens on "drag-and-drop image upload", depending on their media handling setup : simple image embed, creation and embed of a media entity, etc...
Comment #4
wim leers+1 to all that.
But IMO this would initially just skip two steps of uploading an inline image as it exists in D8: rather than having to click the image button and then clicking the "upload" button, you'd just drag in the image and have that open the dialog. That's IMO step 1.
Comment #5
wim leersComment #6
wim leersNo need for this to be postponed.
Comment #7
thpoul commentedComment #8
thpoul commentedLet's go with one thing at a time, so it's easier to review. Added uploadwidget.
Comment #9
thpoul commentedIn this step I added a new
DrupalImageDragNDropplugin which for now detects when a file is dropped in the CKEditor area and simply opens a the add a new file dialog just to get a simple poc working.This needs a review to check if it's on the right track.
Comment #10
droplet commentedIMO, this is not the right way.
I think it should be a centre API for all these uploads.
INPUT -> ACTION -> CALLBACK
1. Drop file
2. via CKEditor event API, trigger drupal new upload API (HTML5 dnd)
3. start upload file ( update the file list )
4. callback to CKEditor event to handle further actions, eg insert it as inline img.
the new API shareable with:
- #2113931: File Field design update: Upload field.
- any file upload plugin
I believe it can help to solve:
#2666746: Fix simultaneous file uploads re-posting data
and clientside progress instead of serverside:
#2662932: Fix file upload progress bar
Comment #11
wim leers#9: I'd like to get feedback from @mlewand on this, since this is using a CKEditor API and he's going to be far more knowledgeable about this than me.
#10: I don't see how this is remotely related to #2113931: File Field design update: Upload field.? It sounds like you're thinking/saying/arguing that images uploaded via CKEditor should always also be listed in a
@FieldType=filefield on the same entity? That's the only way I can make sense of #10. If that's what you mean, I agree that'd be nice, but A) it's not possible to require that, B) making that required would be a huge BC break. This issue is just about making the existing experience nicer. See #4.Comment #12
mlewand commentedThe code looks good, generally you'll be fine if you follow uploadimage implementation. I'm not able verify how it works at the end because temporarily I'm unable to install D8.
Comment #13
wim leersYou need to do
composer installnow — see https://www.drupal.org/node/2648064.Thanks, @mlewand! Now @thpoul can continue :)
Comment #14
thpoul commentedLet's see if we can make it in time to land this on 8.2.
2560457-14-no-vendor.txt contains only the Drupal plugin for easier review. The patch simply adds the CKE uploadwidget plugin in order to make dnd upload work.
Practically this patch uploads a dropped image into a CKEditor instance.
AFAICT there are two main tasks that still need to be done for this to be ready:
Comment #16
thpoul commentedOops :P
Comment #17
wim leersAWESOME WORK!!!
I think there are two big missing things:
<img src=…>being inserted yet!Once that's done, the behavior/experience is similar to that at http://sdk.ckeditor.com/samples/fileupload.html#uploading-dropped-and-pa..., but with one key UX difference: you're forced to enter an
alttag, because Drupal cares about accessibility. (And a bunch of technical differences, of course.)To address : do we even need a separate plugin? I don't think we do? I think this can live in the
drupalimageCKEditor plugin. I also don't see how it can work otherwise; how could it otherwise work withdrupalimagecaption?IOW: just remove the new PHP code, and just merge the JS code with the existing JS code in
drupalimage/plugin.jsComment #18
thpoul commentedThank you Wim for the review! I think that with this patch we are much closer! Point 2 is resolved. I will work on 1 now.
Comment #19
thpoul commentedI am thinking that point 1 might not be something that users need.
Image the following scenarios:
IMHO in both scenarios we shouldn't have an instant thumbnail (which btw is not instant at all since it has to go through FileReader's readAsDataUrl()) because it wouldn't add anything to the user's experience plus it would require some extra code to handle switching between the temporary thumb and the actual image.
So my question is, do we really need/want point 1?
Comment #20
wim leersSimulate 3G in your browser. It now takes a long time for your dialog to show up. Then it takes a long time for the image to upload.
Having that preview would make this much more tolerable. It ensures the user sees that things are working.
Comment #21
wim leersI now tested #20 myself. With both 3G and 2G simulation.
CKEditor shows a "preview" of the image while the uploading still happens at http://sdk.ckeditor.com/samples/fileupload.html#uploading-dropped-and-pa...
I could see that helping things a lot in those "slow network" scenarios.
We should hardcode this to match
\Drupal\editor\Form\EditorImageDialog::buildForm()'s hardcoded values:This means every created dialog in the future will have this happen. We need it to happen only once.
You should not use
[name=…], but instead[data-drupal-selector=…].Rather than doing this difficult-to-understand nesting, let's have a helper function to find the right AJAX object.
Comment #22
samuel.mortensonYou'll need to pass Underscore to the outer function/closure with CKEDITOR and jQuery. You also use
$.eachlater on, could we be consistent and use one or the other?Can we make this configurable? That could be a follow-up issue.
More comments in the
editor.on('paste')callback would be good too, to explain the logic. I'm not sure I understand the need formyAjaxObject.beforeSerialize.Comment #23
thpoul commentedThank you both for your reviews!
I totally agree with #20, as it's a reminder that this issue aims to improve the usability and ux of image uploading within the CKE.
This patch is a small step forward based on the feedback of #21 and #22. It shows the preview of the image while uploading but nothing more. I still need to figure out a way to properly show/hide the preview. Didn't have much luck with it yet.
PS: Excuse the spaghetti within
fileTools.addUploadWidget(), still trying to make it work properly :)Comment #24
wim leers#23 is a huge improvement, UX-wise!
I'd love to see something like
.cke_upload_uploading img { opacity: 0.3; }to indicate it's an in-progress thing. thpoul told me in IRC that he had difficulty finding the right place to do this: CKEditor'suploadwidgetusesCKEDITOR.addCss(), which we cannot use. Plus, that only works for iframe instances, we need it to work for inline and iframe instances, and it must be customizable by themes.After some searching, I found the solution:
Now reviewing the actual patch.
Comment #25
wim leersHmmm dammit! #24 assumes that the
DrupalImageplugin lives in theimagemodule, but it lives in theckeditormodule. So the library would be called something likeckeditor/plugins.drupalimage.drag-and-drop-uploads.Comment #26
wim leersbeforeSerialize()needs to be better documented. What does it do? Why specificallybeforeSerialize()and notbeforeSubmit()or one of the others?Why these overrides? Needs docs.
(Note that I even went back in time to see how they dealt with integrating
uploadimageandimage2, but they never integrated that. Note that Drupal'sdrupalimageplugins is just an extension of/a layer on top ofimage2.)EditorImageDialog, the placeholder image should be removed. The tricky thing there is that the design/assumption is that it's onlyEditor(Link|Image)Dialogthat's creating/inserting HTML. But in this case, we already insert HTML before opening the dialog, so we must remove it afterwards. That makes it more difficult than I hoped it would be.I considered making
saveCallbackbe called even upon closing (but this time with its argument not being the values, butundefined). Unfortunately, that would be an API change.But the reason that that is designed in that particular way, is because Drupal's AJAX Dialog API is designed to be used solely from the server side, not from the client side. It's literally impossible to specify a
close()callback for a specific dialog instance (you could do it for all of them, but that'd be beside the point), despite http://api.jqueryui.com/dialog/#event-close explicitly supporting that. This is also in part to the horrendous complexity/confusingness that jQuery UI (Dialog)'s API is. (Look atcore/misc/dialog/dialog.js+core/misc/dialog/dialog.position.js+core/misc/dialog/dialog.ajax.jsto get even a vague idea.)editor:dialogopen(to solve point 3) andeditor:dialogcloseevents (to solve the previous point), similar to the already-existingeditor:dialogsaveevent. We cannot tie it to this particular dialog instance due to the reasons given in the previous point, but we can make it reliable nonetheless: by adding a certain class to the dialog and then mappingdialog:aftercreatetoeditor:dialogopenanddialog:afterclosetoeditor:dialogclose, but only if those events are being triggered for a dialog that has that certain class, we have sufficient guarantees. Because there's guaranteed to only ever be one such modal dialog active.This reroll fixes points 3, 6 and 7. And my changes need further refinement, this is just providing some of the missing things that this issue really needs.
Comment #27
wim leers#26 took me >3 hours to figure out how to make those events work (i.e. points 6 + 7). Then once I had them, I fixed point 3 in a few minutes.
Comment #28
thpoul commentedSuperb! I was really stuck there, thank you for pushing it forward and for making this list of things we need to address!
This patch should solve #24. I'll try and submit a new one with points 1,2 and 4 tomorrow.
@Wim Leers: Should we ping mlewand for 5 once the rest is done?
Comment #30
wim leersI already pinged @mlewand for #26.5 :)
#28's interdiff is looking good! (The failing test is because you need to add the same stuff to the
stabletheme.)Comment #31
wim leersAnd to make it easier to see the changes for the CKEditor team people who review this: this is #28, minus the changes to our build of CKEditor. i.e. just the changes that need review.
Comment #32
thpoul commentedThis should solve 30. Still working on points 1,2 and 4.
Comment #33
thpoul commentedWorked a bit on 1 and 2 (hopefully they are on the right track) and solved 8 (credit to Reinmar of the CKE team). Getting closer :D
Edit: also ran eslint and fixed a couple of warnings.
Comment #35
thpoul commentedSome fixes after manual testing and test bot giving me a red light.
Comment #36
thpoul commentedMissed the proper interdiff
Comment #39
thpoul commentedGo testbot go!
Comment #40
wim leers#26.8 has not yet been addressed — or at least it's not yet working correctly for me.
EDIT: well, it works okay in case of canceling (drag + drop image, then close the image dialog). But it does not yet work correctly in case of the dialog being used as intended: alternative text filled out, click "save", and then undo.
Comment #41
wim leersPlus, this is still missing JS test coverage.
It'd also be great if the CKEditor team could review this of course, so I pinged them as well.
Comment #42
thpoul commentedThis is the diff without the CKEditor library rebuild.
Comment #43
thpoul commentedThis fixes #26.8
Comment #44
wim leersI'd love to RTBC this, but I can't, not without a
\Drupal\FunctionalJavascriptTests\JavascriptTestBasetest. I'd prefer to have the CKEditor team's approval of the JS too, but I could live without that since the code is so small, and easily revertible.The functionality now works great!
IMHO this should qualify for , since it's easily revertible.
Why do we not want to send a
Content-Typerequest header?We're not sending a
DOMDocument? (That's PHP!) We're sendingFormData?Don't assign, just return.
Just
return null.Comment #45
effulgentsia commentedFrom https://www.drupal.org/core/d8-allowed-changes#beta:
From https://www.drupal.org/project/drupal/releases/8.2.0-beta1:
I discussed this issue with @webchick and @xjm, and we agree that it's high impact, low disruption, and the beta1 release notes already mention it indirectly, so tagging as a beta target.
Comment #47
webchickNote that Wim is on honeymoon for the next 2 weeks, so if someone else is able to re-roll per his comments, that'd be awesome.
Comment #48
thpoul commented@webchick I'm still working on the test needed for this, plus Wim's comments :)
Comment #49
webchickYay, thanks Thanos! :)
Comment #50
thpoul commented#44-1: Setting any
Content-Typejust breaks the ajax request for some reason and I haven't been able to figure out why.#44-2: Yes we are sending
FormDatanotDOMDocument(btw the comments are from the jQuery.ajax documentation.)#44-3, 4: You can stop the loop from within the callback function by returning false. Assigning the value is necessary in order to return it out of the loop, not to mention that eslint was complaining about it too :) I switched from
$.eachtoArray.prototype.forEachin order to be inline with the other loops in the file.I am also working on a
JavascriptTestBasetest which is included in this patch. It took a lot of effort to actually be able to replicate the drag-and-drop functionality in a few js lines (kudos to Tade0 for his valuable input) and I think we are close to what we should have. The test fails right now withTypeError: Attempted to assign to readonly property.which I can't understand why (seems it has something to do withbeforeSerializeat/core/modules/ckeditor/js/plugins/drupalimage/plugin.js:306.You can still run the test using
phantomjs --ssl-protocol=any --ignore-ssl-errors=true vendor/jcalderonzumba/gastonjs/src/Client/main.js 8510 1024 768 false(note the false at the end which setsjs_errors = falseat the Poltergeist configuration) but it will still fail due toRuntimeException: Unfinished AJAX requests whilst tearing down a testwhich is most probably caused by the previousTypeError.Note: Pasting the JS code from the
with-blob-as-filetest in the console won't work because of theBlobnot being aFile(I struggled a lot with it because I was testing the JS code from my browser console but it's a known phantomjs bug). If you need to test in from your browser I have attached thewith-filealternative which unfortunately can't be in the test due to the phantomjs bug.Comment #53
xjmThanks @thpoul for helping address that feedback!
At this point we've essentially come to the deadline for beta targets, so this issue will need to go into 8.3.x. That commit could happen at any time once the issue is ready and it would be great to have this as one of the first features in 8.3.x.
Comment #54
webchickComment #56
sukanya.ramakrishnan commentedWe are in need of the 'resizing of an image using Drag' in CKEditor . Wondering if there are plans to provide this functionality soon.
Thanks in advance for any assistance.
Thanks,
Sukany
Comment #57
sukanya.ramakrishnan commentedApologies for the off track comment.
Whoever is looking for the drag resize functionality for images, i found that this functionality is already available in Drupal 8. Our FULL HTML editor was restricted to limit certain HTML tags and so it wasnt working properly. here is the solution, When text editor is configured, if the 'Limit allowed HTML tags and correct faulty HTML
Enabled ' filter is enabled, add the height and width attributes to the img tag in this setting and the drag resize handle works perfectly.
Comment #60
ahmed-ayman commentedthis feature is already working on Drupal 8.4.x.
Comment #61
martijn de witI don't know how this is tested. But I can't get this working.
If I read the documentation at https://ckeditor.com/cke4/addon/uploadwidget this only works when "uploadwidget" plug-in is loaded. But Drupal 8.6.x still doesn't do that at all! There is no 'uploadwidget' : 1 in the core/assets/vendor/ckeditor/build-config.js. So this plug in is not there.
The question if this feature is still relevant, is an other question. Maybe something to discuss at badcamp 2018.
Can imagine this should work diferend with the new media library in core and the way it will be integrated in the ckeditor.
Comment #62
effulgentsia commentedI don't know if #60 was or is true, but if this is a feature that isn't already in, then 8.7.x is the version that is currently open for new features.
Comment #64
volkswagenchickTagging for DrupalNorth 2019
Comment #66
dercheffeIMO it's quite important to upload not only as images. They should be handled as core media entities (new created during upload) and then embedded automatically.
The site builder should be able to pre-define which kind of media type the direct uploaded media should be connected with. Perhaps it can be handled as same as it's handled when embed a media entity with entity browser (default media type, default display style, allowed display styles).
Comment #72
quietone commentedCKEditor has been removed from core, CKEditor 4 is removed from Drupal Core in 10.0.0