CKEditor5 With Custom Image Uploader in React

WHAT TO KNOW - Sep 21 - - Dev Community

CKEditor5 with Custom Image Uploader in React: A Comprehensive Guide

In the ever-evolving landscape of web development, providing users with a seamless and intuitive experience is paramount. Rich text editors, like CKEditor5, play a crucial role in empowering users to create engaging content without requiring extensive coding knowledge. This comprehensive guide delves into the intricacies of integrating a custom image uploader into CKEditor5 within a React application, offering practical insights and step-by-step instructions for a smooth implementation.

1. Introduction

1.1. The Need for Rich Text Editors

Rich text editors bridge the gap between simple text input fields and complex web applications that demand sophisticated content creation capabilities. They enable users to format text, insert media, and structure content visually, enhancing user experience and website interactivity.

1.2. CKEditor5: A Modern Rich Text Editor

CKEditor5, a powerful and versatile open-source rich text editor, stands out with its modular architecture, intuitive interface, and extensive customization options. It allows developers to tailor the editor to their specific needs, integrating various functionalities like image uploading, embedding videos, and managing tables.

1.3. Custom Image Uploader: Enhancing Control and User Experience

While CKEditor5 provides basic image uploading functionality, a custom image uploader offers enhanced control and a more tailored user experience. This allows developers to implement custom validation logic, integrate with specific storage solutions, and provide a seamless and intuitive image management workflow within the editor.

2. Key Concepts, Techniques, and Tools

2.1. CKEditor5 Essentials

  • Editor Building Blocks: CKEditor5 utilizes a modular architecture where functionalities are built as separate plugins. These plugins extend the editor's capabilities, adding features like image uploading, embedding videos, and formatting options.
  • Editor Configuration: CKEditor5 relies on configuration options to customize its behavior and features. These configurations can be specified in JavaScript files, allowing for granular control over the editor's functionality.
  • Data Processing Pipeline: CKEditor5 uses a data processing pipeline to manage the editor's content. This pipeline converts the user's input into a structured format, enabling the editor to handle various content types effectively.

    2.2. Custom Image Uploader Architecture

  • Image Upload Component: This component handles user interaction with the image upload process, including file selection, progress display, and error handling.
  • Backend Integration: The image upload component communicates with a backend API to handle image storage and processing. This API might involve a cloud storage solution, a custom server, or a file management system.
  • Editor Integration: The custom image uploader needs to seamlessly integrate with CKEditor5's data processing pipeline, allowing uploaded images to be inserted into the editor's content.

    2.3. Essential Tools and Libraries

  • CKEditor5: The core library for building the rich text editor.
  • React: A JavaScript library for building user interfaces.
  • Axios: A library for making HTTP requests to the backend API.
  • Cloud Storage (Optional): Services like AWS S3, Google Cloud Storage, or Azure Blob Storage can provide scalable and secure image storage.

    1. Practical Use Cases and Benefits

    3.1. Real-World Applications

  • Content Management Systems (CMS): Websites and platforms built with CMS, like WordPress, Drupal, or Joomla, can leverage custom image uploaders to provide users with a more controlled and flexible image management experience within CKEditor5.
  • Online Forums and Communities: Forums and online communities benefit from custom image uploaders to enable members to easily share images and visual content, fostering engagement and enriching the user experience.
  • E-commerce Platforms: E-commerce sites can utilize custom image uploaders to streamline product image management, allowing sellers to easily upload and edit product images within the CKEditor5 interface.

    3.2. Advantages of Custom Image Uploader

  • Enhanced Control: Developers have full control over the upload process, including file validation, image resizing, and storage options.
  • Improved User Experience: A well-designed custom uploader provides a more intuitive and user-friendly image management workflow within the editor.
  • Integration with Specific Storage Solutions: The custom uploader can be tailored to integrate seamlessly with specific cloud storage services or custom backend systems.

    1. Step-by-Step Guide: Implementing a Custom Image Uploader

    This step-by-step guide demonstrates how to implement a custom image uploader in a React application using CKEditor5.

    4.1. Project Setup

  • Create a React project:

    npx create-react-app my-ckeditor5-app
    cd my-ckeditor5-app
    
  1. Install necessary packages:

    npm install @ckeditor/ckeditor5-build-classic @ckeditor/ckeditor5-upload @ckeditor/ckeditor5-react
    

4.2. Defining the Image Upload Component

import React, { useState } from 'react';
import axios from 'axios';

const ImageUploadComponent = () => {
  const [selectedFile, setSelectedFile] = useState(null);
  const [isLoading, setIsLoading] = useState(false);
  const [uploadError, setUploadError] = useState(null);

  const handleFileChange = (event) => {
    setSelectedFile(event.target.files[0]);
  };

  const handleUpload = async () => {
    if (!selectedFile) {
      setUploadError('Please select an image file.');
      return;
    }

    setIsLoading(true);
    setUploadError(null);

    try {
      const formData = new FormData();
      formData.append('image', selectedFile);

      // Replace with your actual backend API endpoint
      const response = await axios.post('/api/upload', formData, {
        headers: {
          'Content-Type': 'multipart/form-data',
        },
      });

      // Update the editor with the uploaded image URL
      // (This step will be covered in the next section)

      setIsLoading(false);
    } catch (error) {
      setUploadError(error.message);
      setIsLoading(false);
    }
  };

  return (
<div>
 <input accept="image/*" onchange="{handleFileChange}" type="file"/>
 <button disabled="{isLoading}" onclick="{handleUpload}">
  {isLoading ? 'Uploading...' : 'Upload Image'}
 </button>
 {uploadError &amp;&amp;
 <p classname="error">
  {uploadError}
 </p>
 }
</div>
);
};

export default ImageUploadComponent;
Enter fullscreen mode Exit fullscreen mode

Explanation:

  • The component uses useState to manage the selected file, upload status, and any errors.
  • handleFileChange updates the selected file state when a user chooses an image.
  • handleUpload handles the image upload process:
    • It validates if a file is selected.
    • It sets the loading state to true.
    • It creates a FormData object to send the image to the backend.
    • It makes a POST request to your backend API using axios.
    • It handles success and error scenarios, updating the loading state and displaying any errors.
  • The component renders an input element for file selection, a button to trigger the upload, and displays any error messages.

    4.3. Integrating with CKEditor5


javascript
import React, { useRef, useEffect, useState } from 'react';
import { CKEditor } from '@ckeditor/ckeditor5-react';
import ClassicEditor from '@ckeditor/ckeditor5-build-classic';
import ImageUploadComponent from './ImageUploadComponent';

const CkeditorWithCustomUpload = () =&gt; {
  const editorRef = useRef(null);
  const [imageUrl, setImageUrl] = useState(null);

  useEffect(() =&gt; {
    // This effect runs after the editor instance is created.
    if (editorRef.current) {
      // Get the editor instance
      const editor = editorRef.current.instance;

      // Function to handle image upload
      const handleImageUpload = (file, callback) =&gt; {
        // Call the handleUpload function from the ImageUploadComponent
        // (This will trigger your backend image upload)
        handleUpload(file)
          .then((uploadedImageUrl) =&gt; {
            callback(uploadedImageUrl);
            setImageUrl(uploadedImageUrl);
          })
          .catch((error) =&gt; {
            console.error('Image upload failed:', error);
          });
      };

      // Register the custom image upload command
      editor.commands.add('insertImage', {
        exec(editor) {
          // Trigger the custom image upload dialog
          // ...
        },
      });

      // Add a new "Upload Image" button to the toolbar
      editor.ui.component.add('toolbar', {
        id: 'imageUploadButton',
        label: 'Upload Image',
        template: `
<button aria-haspopup="true" aria-label="Upload Image" class="cke_button cke_button_icon cke_button_toolbar" data-cke-button-name="imageUpload" role="button" tabindex="0" type="button">
 &lt;span class="cke_icon" aria-hidden="true" style="background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNnB4IiBoZWlnaHQ9IjE2cHAiIHZpZXdCb3g9IjAgMCAxNiAxNiI+PGcgZmlsbD0iI2ZmZiI+PHBhdGggZD0iTTcgMTMuODlBMy42NyAzLjY3IDAgMCAxIDMuODkgN2gzLjQzVjE2aDMuNDNWMzguNzVBNy43NiA3Ljc2IDAgMCAxIDEwLjM2IDdjMy4yNCAwIDYuNDEgMi40MyA3LjYgNi4yNWMxLjE2IDMuODMgMC40MiA3LjQ5LTMuMjUgOS41N0MtMy41MiAxNS4zOCAwIDguMzkgMCA3LjE0VjMuODlBNy43NiA3Ljc2IDAgMCAxIDMuODkgMWgzLjQzdjEuMzJBNzIuNjcgNzIuNjcgMCAwIDEgMTEuNjggN2gzLjQzVjE2aDMuNDNWMzguNzVBNzIuNjcgNzIuNjcgMCAwIDEgMTUuNjggN2gzLjQzVjMuODlBNzIuNjcgNzIuNjcgMCAwIDEgMjEuNjkgMWgzLjQzdjEuMzJBNzIuNjcgNzIuNjcgMCAwIDEgMjUuNjggN2gzLjQzVjE2aDMuNDNWMzguNzVBNzIuNjcgNzIuNjcgMCAwIDEgMjkuNjggN2gzLjQzVjMuODlBNzIuNjcgNzIuNjcgMCAwIDEgMzMuNjggMWgzLjQzdjEuMzJBNzIuNjcgNzIuNjcgMCAwIDEgMzcuNjggN2gzLjQzVjE2aDMuNDNWMzguNzVBNzIuNjcgNzIuNjcgMCAwIDEgNDIuNjggN2gzLjQzVjMuODlBNzIuNjcgNzIuNjcgMCAwIDEgNDcuNjggMWgzLjQzdjEuMzJBNzIuNjcgNzIuNjcgMCAwIDEgNTIuNjggN2gzLjQzVjE2aDMuNDNWMzguNzVBNzIuNjcgNzIuNjcgMCAwIDEgNTcuNjggN2gzLjQzVjMuODlBNzIuNjcgNzIuNjcgMCAwIDEgNjIuNjggMWgzLjQzdjEuMzJBNzIuNjcgNzIuNjcgMCAwIDEgNjcuNjggN2gzLjQzVjE2aDMuNDNWMzguNzVBNzIuNjcgNzIuNjcgMCAwIDEgNzIuNjggN2gzLjQzVjMuODlBNzIuNjcgNzIuNjcgMCAwIDEgNzcuNjggMWgzLjQzdjEuMzJBNzIuNjcgNzIuNjcgMCAwIDEgODIuNjggN2gzLjQzVjE2aDMuNDNWMzguNzVBNzIuNjcgNzIuNjcgMCAwIDEgODcuNjggN2gzLjQzVjMuODlBNzIuNjcgNzIuNjcgMCAwIDEgOTIuNjggMWgzLjQzdjEuMzJBNzIuNjcgNzIuNjcgMCAwIDEgOTcuNjggN2gzLjQzVjE2aDMuNDNWMzguNzVBNzIuNjcgNzIuNjcgMCAwIDEgMTAyLjY4N2gzLjQzVjMuODlBNzIuNjcgNzIuNjcgMCAwIDEgMTA3LjY4N2gzLjQzdjEuMzJBNzIuNjcgNzIuNjcgMCAwIDEgMTEyLjY4N2gzLjQzVjE2aDMuNDNWMzguNzVBNzIuNjcgNzIuNjcgMCAwIDEgMTE3LjY4N2gzLjQzVjMuODlBNzIuNjcgNzIuNjcgMCAwIDEgMTIyLjY4N2gzLjQzVjE2aDMuNDNWMzguNzVBNzIuNjcgNzIuNjcgMCAwIDEgMTIzLjY4N2gzLjQzVjMuODlBNzIuNjcgNzIuNjcgMCAwIDEgMTM0LjY4N2gzLjQzVjE2aDMuNDNWMzguNzVBNzIuNjcgNzIuNjcgMCAwIDEgMTM5LjY4N2gzLjQzVjMuODlBNzIuNjcgNzIuNjcgMCAwIDEgMTQ0LjY4N2gzLjQzVjE2aDMuNDNWMzguNzVBNzIuNjcgNzIuNjcgMCAwIDEgMTQ5LjY4N2gzLjQzVjMuODlBNzIuNjcgNzIuNjcgMCAwIDEgMTU0LjY4N2gzLjQzVjE2aDMuNDNWMzguNzVBNzIuNjcgNzIuNjcgMCAwIDEgMTU5LjY4N2gzLjQzVjMuODlBNzIuNjcgNzIuNjcgMCAwIDEgMTY0LjY4N2gzLjQzVjE2aDMuNDNWMzguNzVBNzIuNjcgNzIuNjcgMCAwIDEgMTY5LjY4N2gzLjQzVjMuODlBNzIuNjcgNzIuNjcgMCAwIDEgMTc0LjY4N2gzLjQzVjE2aDMuNDNWMzguNzVBNzIuNjcgNzIuNjcgMCAwIDEgMTc5LjY4N2gzLjQzVjMuODlBNzIuNjcgNzIuNjcgMCAwIDEgMTg0LjY4N2gzLjQzVjE2aDMuNDNWMzguNzVBNzIuNjcgNzIuNjcgMCAwIDEgMTg5LjY4N2gzLjQzVjMuODlBNzIuNjcgNzIuNjcgMCAwIDEgMTk0LjY4N2gzLjQzVjE2aDMuNDNWMzguNzVBNzIuNjcgNzIuNjcgMCAwIDEgMTk5LjY4N2gzLjQzVjMuODlBNzIuNjcgNzIuNjcgMCAwIDEgMjAwLjY4N2gzLjQzVjE2aDMuNDNWMzguNzVBNzIuNjcgNzIuNjcgMCAwIDEgMjA1LjY4N2gzLjQzVjMuODlBNzIuNjcgNzIuNjcgMCAwIDEgMjEwLjY4N2gzLjQzVjE2aDMuNDNWMzguNzVBNzIuNjcgNzIuNjcgMCAwIDEgMjE1LjY4N2gzLjQzVjMuODlBNzIuNjcgNzIuNjcgMCAwIDEgMjIwLjY4N2gzLjQzVjE2aDMuNDNWMzguNzVBNzIuNjcgNzIuNjcgMCAwIDEgMjI1LjY4N2gzLjQzVjMuODlBNzIuNjcgNzIuNjcgMCAwIDEgMjMwLjY4N2gzLjQzVjE2aDMuNDNWMzguNzVBNzIuNjcgNzIuNjcgMCAwIDEgMjM1LjY4N2gzLjQzVjMuODlBNzIuNjcgNzIuNjcgMCAwIDEgMjQwLjY4N2gzLjQzVjE2aDMuNDNWMzguNzVBNzIuNjcgNzIuNjcgMCAwIDEgMjQ1LjY4N2gzLjQzVjMuODlBNzIuNjcgNzIuNjcgMCAwIDEgMjUwLjY4N2gzLjQzVjE2aDMuNDNWMzguNzVBNzIuNjcgNzIuNjcgMCAwIDEgMjU1LjY4N2gzLjQzVjMuODlBNzIuNjcgNzIuNjcgMCAwIDEgMjYwLjY4N2gzLjQzVjE2aDMuNDNWMzguNzVBNzIuNjcgNzIuNjcgMCAwIDEgMjY1LjY4N2gzLjQzVjMuODlBNzIuNjcgNzIuNjcgMCAwIDEgMjcxLjY4N2gzLjQzVjE2aDMuNDNWMzguNzVBNzIuNjcgNzIuNjcgMCAwIDEgMjcyLjY4N2gzLjQzVjMuODlBNzIuNjcgNzIuNjcgMCAwIDEgMjgzLjY4N2gzLjQzVjE2aDMuNDNWMzguNzVBNzIuNjcgNzIuNjcgMCAwIDEgMjgzLjY4N2gzLjQzVjMuODlBNzIuNjcgNzIuNjcgMCAwIDEgMjkyLjY4N2gzLjQzVjE2aDMuNDNWMzguNzVBNzIuNjcgNzIuNjcgMCAwIDEgMjkyLjY4N2gzLjQzVjMuODlBNzIuNjcgNzIuNjcgMCAwIDEgMzAwLjY4N2gzLjQzVjE2aDMuNDNWMzguNzVBNzIuNjcgNzIuNjcgMCAwIDEgMzA1LjY4N2gzLjQzVjMuODlBNzIuNjcgNzIuNjcgMCAwIDEgMzEwLjY4N2gzLjQzVjE2aDMuNDNWMzguNzVBNzIuNjcgNzIuNjcgMCAwIDEgMzE1LjY4N2gzLjQzVjMuODlBNzIuNjcgNzIuNjcgMCAwIDEgMzIwLjY4N2gzLjQzVjE2aDMuNDNWMzguNzVBNzIuNjcgNzIuNjcgMCAwIDEgMzI1LjY4N2gzLjQzVjMuODlBNzIuNjcgNzIuNjcgMCAwIDEgMzMwLjY4N2gzLjQzVjE2aDMuNDNWMzguNzVBNzIuNjcgNzIuNjcgMCAwIDEgMzM1LjY4N2gzLjQzVjMuODlBNzIuNjcgNzIuNjcgMCAwIDEgMzQwLjY4N2gzLjQzVjE2aDMuNDNWMzguNzVBNzIuNjcgNzIuNjcgMCAwIDEgMzQ1LjY4N2gzLjQzVjMuODlBNzIuNjcgNzIuNjcgMCAwIDEgMzUwLjY4N2gzLjQzVjE2aDMuNDNWMzguNzVBNzIuNjcgNzIuNjcgMCAwIDEgMzU1LjY4N2gzLjQzVjMuODlBNzIuNjcgNzIuNjcgMCAwIDEgMzYwLjY4N2gzLjQzVjE2aDMuNDNWMzguNzVBNzIuNjcgNzIuNjcgMCAwIDEgMzY1LjY4N2gzLjQzVjMuODlBNzIuNjcgNzIuNjcgMCAwIDEgMzcxLjY4N2gzLjQzVjE2aDMuNDNWMzguNzVBNzIuNjcgNzIuNjcgMCAwIDEgMzcyLjY4N2gzLjQzVjMuODlBNzIuNjcgNzIuNjcgMCAwIDEgMzgzLjY4N2gzLjQzVjE2aDMuNDNWMzguNzVBNzIuNjcgNzIuNjcgMCAwIDEgMzgyLjY4N2gzLjQzVjMuODlBNzIuNjcgNzIuNjcgMCAwIDEgMzkyLjY4N2gzLjQzVjE2aDMuNDNWMzguNzVBNzIuNjcgNzIuNjcgMCAwIDEgMzkyLjY4N2gzLjQzVjMuODlBNzIuNjcgNzIuNjcgMCAwIDEgNDA0LjY4N2gzLjQzVjE2aDMuNDNWMzguNzVBNzIuNjcgNzIuNjcgMCAwIDEgNDA5LjY4N2gzLjQzVjMuODlBNzIuNjcgNzIuNjcgMCAwIDEgNDEwLjY4N2gzLjQzVjE2aDMuNDNWMzguNzVBNzIuNjcgNzIuNjcgMCAwIDEgNDExLjY4N2gzLjQzVjMuODlBNzIuNjcgNzIuNjcgMCAwIDEgNDEyLjY4N2gzLjQzVjE2aDMuNDNWMzguNzVBNzIuNjcgNzIuNjcgMCAwIDEgNDEzLjY4N2gzLjQzVjMuODlBNzIuNjcgNzIuNjcgMCAwIDEgNDE0LjY4N2gzLjQzVjE2aDMuNDNWMzguNzVBNzIuNjcgNzIuNjcgMCAwIDEgNDE1LjY4N2gzLjQzVjMuODlBNzIuNjcgNzIuNjcgMCAwIDEgNDE2LjY4N2gzLjQzVjE2aDMuNDNWMzguNzVBNzIuNjcgNzIuNjcgMCAwIDEgNDE3LjY4N2gzLjQzVjMuODlBNzIuNjcgNzIuNjcgMCAwIDEgNDE4LjY4N2gzLjQzVjE2aDMuNDNWMzguNzVBNzIuNjcgNzIuNjcgMCAwIDEgNDE5LjY4N2gzLjQzVjMuODlBNzIuNjcgNzIuNjcgMCAwIDEgNDIwLjY4N2gzLjQzVjE2aDMuNDNWMzguNzVBNzIuNjcgNzIuNjcgMCAwIDEgNDIxLjY4N2gzLjQzVjMuODlBNzIuNjcgNzIuNjcgMCAwIDEgNDIyLjY4N2gzLjQzVjE2aDMuNDNWMzguNzVBNzIuNjcgNzIuNjcgMCAwIDEgNDIzLjY4N2gzLjQzVjMuODlBNzIuNjcgNzIuNjcgMCAwIDEgNDI0LjY4N2gzLjQzVjE2aDMuNDNWMzguNzVBNzIuNjcgNzIuNjcgMCAwIDEgNDI1LjY4N2gzLjQzVjMuODlBNzIuNjcgNzIuNjcgMCAwIDEgNDI2LjY4N2gzLjQzVjE2aDMuNDNWMzguNzVBNzIuNjcgNzIuNjcgMCAwIDEgNDI3LjY4N2gzLjQzVjMuODlBNzIuNjcgNzIuNjcgMCAwIDEgNDI4LjY4N2gzLjQzVjE2aDMuNDNWMzguNzVBNzIuNjcgNzIuNjcgMCAwIDEgNDI5LjY4N2gzLjQzVjMuODlBNzIuNjcgNzIuNjcgMCAwIDEgNDMwLjY4N2gzLjQzVjE2aDMuNDNWMzguNzVBNzIuNjcgNzIuNjcgMCAwIDEgNDMxLjY4N2gzLjQzVjMuODlBNzIuNjcgNzIuNjcgMCAwIDEgNDMyLjY4N2gzLjQzVjE2aDMuNDNWMzguNzVBNzIuNjcgNzIuNjcgMCAwIDEgNDMzLjY4N2gzLjQzVjMuODlBNzIuNjcgNzIuNjcgMCAwIDEgNDM0LjY4N2gzLjQzVjE2aDMuNDNWMzguNzVBNzIuNjcgNzIuNjcgMCAwIDEgNDM1LjY4N2gzLjQzVjMuODlBNzIuNjcgNzIuNjcgMCAwIDEgNDM2LjY4N2gzLjQzVjE2aDMuNDNWMzguNzVBNzIuNjcgNzIuNjcgMCAwIDEgNDM3LjY4N2gzLjQzVjMuODlBNzIuNjcgNzIuNjcgMCAwIDEgNDM4LjY4N2gzLjQzVjE2aDMuNDNWMzguNzVBNzIuNjcgNzIuNjcgMCAwIDEgNDM5LjY4N2gzLjQzVjMuODlBNzIuNjcgNzIuNjcgMCAwIDEgNDQwLjY4N2gzLjQzVjE2aDMuNDNWMzguNzVBNzIuNjcgNzIuNjcgMCAwIDEgNDQxLjY4N2gzLjQzVjMuODlBNzIuNjcgNzIuNjcgMCAwIDEgNDQyLjY4N2gzLjQzVjE2aDMuNDNWMzguNzVBNzIuNjcgNzIuNjcgMCAwIDEgNDQzLjY4N2gzLjQzVjMuODlBNzIuNjcgNzIuNjcgMCAwIDEgNDQ0LjY4N2gzLjQzVjE2aDMuNDNWMzguNzVBNzIuNjcgNzIuNjcgMCAwIDEgNDQ1LjY4N2gzLjQzVjMuODlBNzIuNjcgNzIuNjcgMCAwIDEgNDQ2LjY4N2gzLjQzVjE2aDMuNDNWMzguNzVBNzIuNjcgNzIuNjcgMCAwIDEgNDQ3LjY4N2gzLjQzVjMuODlBNzIuNjcgNzIuNjcgMCAwIDEgNDQ4LjY4N2gzLjQzVjE2aDMuNDNWMzguNzVBNzIuNjcgNzIuNjcgMCAwIDEgNDQ5LjY4N2gzLjQzVjMuODlBNzIuNjcgNzIuNjcgMCAwIDEgNDUwLjY4N2gzLjQzVjE2aDMuNDNWMzguNzVBNzIuNjcgNzIuNjcgMCAwIDEgNDU1LjY4N2gzLjQzVjMuODlBNzIuNjcgNzIuNjcgMCAwIDEgNDU2LjY4N2gzLjQzVjE2aDMuNDNWMzguNzVBNzIuNjcgNzIuNjcgMCAwIDEgNDU3LjY4N2gzLjQzVjMuODlBNzIuNjcgNzIuNjcgMCAwIDEgNDU4LjY4N2gzLjQzVjE2aDMuNDNWMzguNzVBNzIuNjcgNzIuNjcgMCAwIDEgNDU5LjY4N2gzLjQzVjMuODlBNzIuNjcgNzIuNjcgMCAwIDEgNDYwLjY4N2gzLjQzVjE2aDMuNDNWMzguNzVBNzIuNjcgNzIuNjcgMCAwIDEgNDYxLjY4N2gzLjQzVjMuODlBNzIuNjcgNzIuNjcgMCAwIDEgNDYyLjY4N2gzLjQzVjE2aDMuNDNWMzguNzVBNzIuNjcgNzIuNjcgMCAwIDEgNDYzLjY4N2gzLjQzVjMuODlBNzIuNjcgNzIuNjcgMCAwIDEgNDY0LjY4N2gzLjQzVjE2aDMuNDNWMzguNzVBNzIuNjcgNzIuNjcgMCAwIDEgNDY1LjY4N2gzLjQzVjMuODlBNzIuNjcgNzIuNjcgMCAwIDEgNDY2LjY4N2gzLjQzVjE2aDMuNDNWMzguNzVBNzIuNjcgNzIuNjcgMCAwIDEgNDY3LjY4N2gzLjQzVjMuODlBNzIuNjcgNzIuNjcgMCAwIDEgNDY4LjY4N2gzLjQzVjE2aDMuNDNWMzguNzVBNzIuNjcgNzIuNjcgMCAwIDEgNDY5LjY4N2gzLjQzVjMuODlBNzIuNjcgNzIuNjcgMCAwIDEgNDcwLjY4N2gzLjQzVjE2aDMuNDNWMzguNzVBNzIuNjcgNzIuNjcgMCAwIDEgNDcxLjY4N2gzLjQzVjMuODlBNzIuNjcgNzIuNjcgMCAwIDEgNDcyLjY4N2gzLjQzVjE2aDMuNDNWMzguNzVBNzIuNjcgNzIuNjcgMCAwIDEgNDczLjY4N2gzLjQzVjMuODlBNzIuNjcgNzIuNjcgMCAwIDEgNDc0LjY4N2gzLjQzVjE2aDMuNDNWMzguNzVBNzIuNjcgNzIuNjcgMCAwIDEgNDc1LjY4N2gzLjQzVjMuODlBNzIuNjcgNzIuNjcgMCAwIDEgNDc2LjY4N2gzLjQzVjE2aDMuNDNWMzguNzVBNzIuNjcgNzIuNjcgMCAwIDEgNDc3LjY4N2gzLjQzVjMuODlBNzIuNjcgNzIuNjcgMCAwIDEgNDc4LjY4N2gzLjQzVjE2aDMuNDNWMzguNzVBNzIuNjcgNzIuNjcgMCAwIDEgNDc5LjY4N2gzLjQzVjMuODlBNzIuNjcgNzIuNjcgMCAwIDEgNDgwLjY4N2gzLjQzVjE2aDMuNDNWMzguNzVBNzIuNjcgNzIuNjcgMCAwIDEgNDgxLjY4N2gzLjQzVjMuODlBNzIuNjcgNzIuNjcgMCAwIDEgNDgyLjY4N2gzLjQzVjE2aDMuNDNWMzguNzVBNzIuNjcgNzIuNjcgMCAwIDEgNDgzLjY4N2gzLjQzVjMuODlBNzIuNjcgNzIuNjcgMCAwIDEgNDg0LjY4N2gzLjQzVjE2aDMuNDNWMzguNzVBNzIuNjcgNzIuNjcgMCAwIDEgNDg1LjY4N2gzLjQzVjMuODlBNzIuNjcgNzIuNjcgMCAwIDEgNDg2LjY4N2gzLjQzVjE2aDMuNDNWMzguNzVBNzIuNjcgNzIuNjcgMCAwIDEgNDg3LjY4N2gzLjQzVjMuODlBNzIuNjcgNzIuNjcgMCAwIDEgNDg4LjY4N2gzLjQzVjE2aDMuNDNWMzguNzVBNzIuNjcgNzIuNjcgMCAwIDEgNDg5LjY4N2gzLjQzVjMuODlBNzIuNjcgNzIuNjcgMCAwIDEgNDkwLjY4N2gzLjQzVjE2aDMuNDNWMzguNzVBNzIuNjcgNzIuNjcgMCAwIDEgNDkxLjY4N2gzLjQzVjMuODlBNzIuNjcgNzIuNjcgMCAwIDEgNDkyLjY4N2gzLjQzVjE2aDMuNDNWMzguNzVBNzIuNjcgNzIuNjcgMCAwIDEgNDkzLjY4N2gzLjQzVjMuODlBNzIuNjcgNzIuNjcgMCAwIDEgNDk0LjY4N2gzLjQzVjE2aDMuNDNWMzguNzVBNzIuNjcgNzIuNjcgMCAwIDEgNDk1LjY4N2gzLjQzVjMuODlBNzIuNjcgNzIuNjcgMCAwIDEgNDk2LjY4N2gzLjQzVjE2aDMuNDNWMzguNzVBNzIuNjcgNzIuNjcgMCAwIDEgNDk3
</button>
Enter fullscreen mode Exit fullscreen mode
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Terabox Video Player