utils.js 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. /**
  2. * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.
  3. * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
  4. */
  5. /**
  6. * @module image/imageupload/utils
  7. */
  8. /* global fetch, File */
  9. /**
  10. * Creates a regular expression used to test for image files.
  11. *
  12. * const imageType = createImageTypeRegExp( [ 'png', 'jpeg', 'svg+xml', 'vnd.microsoft.icon' ] );
  13. *
  14. * console.log( 'is supported image', imageType.test( file.type ) );
  15. *
  16. * @param {Array.<String>} types
  17. * @returns {RegExp}
  18. */
  19. export function createImageTypeRegExp( types ) {
  20. // Sanitize the MIME type name which may include: "+", "-" or ".".
  21. const regExpSafeNames = types.map( type => type.replace( '+', '\\+' ) );
  22. return new RegExp( `^image\\/(${ regExpSafeNames.join( '|' ) })$` );
  23. }
  24. /**
  25. * Creates a promise that fetches the image local source (Base64 or blob) and resolves with a `File` object.
  26. *
  27. * @param {module:engine/view/element~Element} image Image whose source to fetch.
  28. * @returns {Promise.<File>} A promise which resolves when an image source is fetched and converted to a `File` instance.
  29. * It resolves with a `File` object. If there were any errors during file processing, the promise will be rejected.
  30. */
  31. export function fetchLocalImage( image ) {
  32. return new Promise( ( resolve, reject ) => {
  33. const imageSrc = image.getAttribute( 'src' );
  34. // Fetch works asynchronously and so does not block browser UI when processing data.
  35. fetch( imageSrc )
  36. .then( resource => resource.blob() )
  37. .then( blob => {
  38. const mimeType = getImageMimeType( blob, imageSrc );
  39. const ext = mimeType.replace( 'image/', '' );
  40. const filename = `image.${ ext }`;
  41. const file = new File( [ blob ], filename, { type: mimeType } );
  42. resolve( file );
  43. } )
  44. .catch( reject );
  45. } );
  46. }
  47. /**
  48. * Checks whether a given node is an image element with a local source (Base64 or blob).
  49. *
  50. * @param {module:engine/view/node~Node} node The node to check.
  51. * @returns {Boolean}
  52. */
  53. export function isLocalImage( node ) {
  54. if ( !node.is( 'element', 'img' ) || !node.getAttribute( 'src' ) ) {
  55. return false;
  56. }
  57. return node.getAttribute( 'src' ).match( /^data:image\/\w+;base64,/g ) ||
  58. node.getAttribute( 'src' ).match( /^blob:/g );
  59. }
  60. // Extracts an image type based on its blob representation or its source.
  61. //
  62. // @param {String} src Image `src` attribute value.
  63. // @param {Blob} blob Image blob representation.
  64. // @returns {String}
  65. function getImageMimeType( blob, src ) {
  66. if ( blob.type ) {
  67. return blob.type;
  68. } else if ( src.match( /data:(image\/\w+);base64/ ) ) {
  69. return src.match( /data:(image\/\w+);base64/ )[ 1 ].toLowerCase();
  70. } else {
  71. // Fallback to 'jpeg' as common extension.
  72. return 'image/jpeg';
  73. }
  74. }
  75. /**
  76. * Creates integrations object that will be passed to the
  77. * {@link module:image/imageupload/ui/imageuploadpanelview~ImageUploadPanelView}.
  78. *
  79. * @returns {Object}
  80. */
  81. export function prepareIntegrations( editor ) {
  82. const panelItems = editor.config.get( 'image.upload.panel.items' );
  83. const imageUploadUIPlugin = editor.plugins.get( 'ImageUploadUI' );
  84. if ( !panelItems ) {
  85. return;
  86. }
  87. const PREDEFINED_INTEGRATIONS = {
  88. 'insertImageViaUrl': 'insertImageViaUrl'
  89. };
  90. // Prepares ckfinder component for the `openCKFinder` integration token.
  91. if ( editor.ui.componentFactory.has( 'ckfinder' ) ) {
  92. const ckFinderButton = editor.ui.componentFactory.create( 'ckfinder' );
  93. ckFinderButton.set( {
  94. withText: true,
  95. class: 'ck-image-upload__ck-finder-button'
  96. } );
  97. // We want to close the dropdown panel view when user clicks the ckFinderButton.
  98. ckFinderButton.delegate( 'execute' ).to( imageUploadUIPlugin, 'cancel' );
  99. PREDEFINED_INTEGRATIONS.openCKFinder = ckFinderButton;
  100. }
  101. // Creates integrations object of valid views to pass it to the ImageUploadPanelView.
  102. const integrations = panelItems.reduce( ( object, key ) => {
  103. if ( PREDEFINED_INTEGRATIONS[ key ] ) {
  104. object[ key ] = PREDEFINED_INTEGRATIONS[ key ];
  105. }
  106. return object;
  107. }, {} );
  108. return Object.keys( integrations ).length ? integrations : null;
  109. }