imageuploadcommand.js 3.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. /**
  2. * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
  3. * For licensing, see LICENSE.md.
  4. */
  5. import ModelDocumentFragment from '@ckeditor/ckeditor5-engine/src/model/documentfragment';
  6. import ModelElement from '@ckeditor/ckeditor5-engine/src/model/element';
  7. import ModelRange from '@ckeditor/ckeditor5-engine/src/model/range';
  8. import ModelPosition from '@ckeditor/ckeditor5-engine/src/model/position';
  9. import ModelSelection from '@ckeditor/ckeditor5-engine/src/model/selection';
  10. import FileRepository from './filerepository';
  11. import { isImageType } from './utils';
  12. import Command from '@ckeditor/ckeditor5-core/src/command';
  13. /**
  14. * @module upload/imageuploadcommand
  15. */
  16. /**
  17. * Image upload command.
  18. *
  19. * @extends module:core/command~Command
  20. */
  21. export default class ImageUploadCommand extends Command {
  22. /**
  23. * Executes the command.
  24. *
  25. * @fires execute
  26. * @param {Object} options Options for executed command.
  27. * @param {File} options.file Image file to upload.
  28. * @param {module:engine/model/position~Position} [options.insertAt] Position of the inserted image.
  29. * If the option won't be provided the position will be calculated by the {@link module:upload/imageuploadcommand~getInsertionPosition}.
  30. * @param {module:engine/model/batch~Batch} [options.batch] Batch to collect all the change steps.
  31. * New batch will be created if this option is not set.
  32. */
  33. execute( options ) {
  34. const editor = this.editor;
  35. const doc = editor.document;
  36. const batch = options.batch || doc.batch();
  37. const file = options.file;
  38. const selection = doc.selection;
  39. const fileRepository = editor.plugins.get( FileRepository );
  40. if ( !isImageType( file ) ) {
  41. return;
  42. }
  43. doc.enqueueChanges( () => {
  44. const insertAt = options.insertAt || getInsertionPosition( doc );
  45. // No position to insert.
  46. if ( !insertAt ) {
  47. return;
  48. }
  49. const imageElement = new ModelElement( 'image', {
  50. uploadId: fileRepository.createLoader( file ).id
  51. } );
  52. const documentFragment = new ModelDocumentFragment( [ imageElement ] );
  53. const range = new ModelRange( insertAt );
  54. const insertSelection = new ModelSelection();
  55. insertSelection.setRanges( [ range ] );
  56. editor.data.insertContent( documentFragment, insertSelection, batch );
  57. selection.setRanges( [ ModelRange.createOn( imageElement ) ] );
  58. } );
  59. }
  60. }
  61. /**
  62. * Returns correct image insertion position.
  63. *
  64. * @param {module:engine/model/document~Document} doc
  65. * @returns {module:engine/model/position~Position|undefined}
  66. */
  67. function getInsertionPosition( doc ) {
  68. const selection = doc.selection;
  69. const selectedElement = selection.getSelectedElement();
  70. // If selected element is placed directly in root - return position after that element.
  71. if ( selectedElement && selectedElement.parent.is( 'rootElement' ) ) {
  72. return ModelPosition.createAfter( selectedElement );
  73. }
  74. const firstBlock = doc.selection.getSelectedBlocks().next().value;
  75. if ( firstBlock ) {
  76. const positionAfter = ModelPosition.createAfter( firstBlock );
  77. // If selection is at the end of the block - return position after the block.
  78. if ( selection.focus.isTouching( positionAfter ) ) {
  79. return positionAfter;
  80. }
  81. // Otherwise return position before the block.
  82. return ModelPosition.createBefore( firstBlock );
  83. }
  84. }