Varios clientes se han acercado a nosotros y nos han preguntado cómo pueden crear una aplicación web similar a Google Docs utilizando nuestras API. Documentos de Google es un procesador de textos que permite a los usuarios crear y editar archivos en línea mientras colaboran con otros usuarios en tiempo real.

Esta publicación de blog explica lo fácil que es crear una versión liviana de Google Docs que tenga las siguientes características:

  • Edición de texto enriquecido (cambiar la fuente del texto, el tamaño, el color, el estilo (negrita, cursiva), la alineación, etc.).
  • Edición colaborativa en tiempo real de un mismo documento. Varios usuarios pueden acceder al documento al mismo tiempo y modificarlo.
  • Cargue el contenido de un documento de Word existente en un editor.
  • Guarde texto en el editor como documento MS Word, PDF, TXT o HTML.

Nuestro producto final se verá de la siguiente manera:

Google Docs como la interfaz de la aplicación

Herramientas y tecnologías: cree Google Docs como una aplicación

Desarrollaremos la aplicación web similar a Google Docs en ASP.NET Core y usaremos las siguientes dos bibliotecas:

  • Firepad is an open-source, collaborative text editor. It uses the Firebase Realtime Database as a backend so it requires no server-side code and can be added to any web app simply by including the JavaScript files.
  • GroupDocs.Editor para .NET gives us an ability to edit most popular document formats using any WYSIWYG editor without any additional applications. We will load document via GroupDocs.Editor into Firepad, edit document in a way we want and save it back to original document format.

He usado Visual Studio para Mac como IDE. Sin embargo, puede descargar la edición comunitaria gratuita de Visual Studio, según su plataforma, desde aquí. Empecemos.

Cree un nuevo proyecto de aplicación web ASP.NET Core y asígnele el nombre “GoogleDocsLite”.

Crear una nueva aplicación web ASP.NET Core

Ejecute la aplicación para asegurarse de que todo esté configurado correctamente.

Integrar Firepad

Podemos agregar Firepad a nuestra aplicación web al incluir los siguientes archivos JavaScript en el sección de Layout.cshtml.

<!-- Firebase -->
<script src="https://www.gstatic.com/firebasejs/7.13.2/firebase-app.js"></script>
<script src="https://www.gstatic.com/firebasejs/7.13.2/firebase-auth.js"></script>
<script src="https://www.gstatic.com/firebasejs/7.13.2/firebase-database.js"></script>

<!-- CodeMirror -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.17.0/codemirror.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.17.0/codemirror.css" />

<!-- Firepad -->
<link rel="stylesheet" href="https://firepad.io/releases/v1.5.9/firepad.css" />
<script src="https://firepad.io/releases/v1.5.9/firepad.min.js"></script>

<!-- userlist -->
<script src="~/js/firepad-userlist.js"></script>
<link rel="stylesheet" href="~/css/firepad-userlist.css" />

Para crear un Firepad, inicializaremos Firebase, CodeMirror y luego Firepad. Agregue el siguiente script y código HTML en Index.cshtml.

<script>
    function init() {
        // Initialize Firebase.
        // TODO: replace with your Firebase project configuration.
        var config = {
            apiKey: '',
            authDomain: "",
            databaseURL: ""
        };
        firebase.initializeApp(config);
        
        // Get Firebase Database reference.
        var firepadRef = getExampleRef();
        
        // Create CodeMirror (with lineWrapping on).
        var codeMirror = CodeMirror(document.getElementById('firepad'), { lineWrapping: true });

        // Create a random ID to use as our user ID (we must give this to firepad and FirepadUserList).
        var userId = Math.floor(Math.random() * 9999999999).toString();

        // Create Firepad (with rich text features and our desired userId).
        var firepad = Firepad.fromCodeMirror(firepadRef, codeMirror,
                    { richTextToolbar: true, richTextShortcuts: true, userId: userId });

        // Create FirepadUserList (with our desired userId).
        var firepadUserList = FirepadUserList.fromDiv(firepadRef.child('users'),
        document.getElementById('userlist'), userId);
    }
    
    // Helper to get hash from end of URL or generate a random one.
    function getExampleRef() {
        var ref = firebase.database().ref();
        var hash = window.location.hash.replace(/#/g, '');
        if (hash) {
            ref = ref.child(hash);
        } else {
            ref = ref.push(); // generate unique location.
            window.location = window.location + '#' + ref.key; // add it as a hash to the URL.
        }
        if (typeof console !== 'undefined') {
            console.log('Firebase data: ', ref.toString());
        }
        return ref;
    }
</script>

<div id="userlist"></div>
<div id="firepad"></div>

Reemplace el contenido de la configuración con la configuración de su propio proyecto de Firebase.

Queremos que el script anterior se ejecute una vez que una página web haya cargado completamente todo el contenido (archivos de script, archivos CSS, etc.). Por lo tanto, llame a la función init() desde el atributo de evento onLoad de elemento en Layout.cshtml.

<body onload="init()">

tu <body> El elemento debe tener el siguiente aspecto. Si contiene etiquetas innecesarias como <header> , <footer> , por favor elimínelos.

Elemento del cuerpo

Si ejecuta el proyecto, notará que firepad y la lista de usuarios no están alineados correctamente. Utilice el siguiente código CSS para ajustar el tamaño/posición del firepad y la lista de usuarios. Puede agregar el siguiente código dentro elemento de Layout.cshtml.

<style>
    html {
        height: 100%;
    }

    body {
        margin: 0;
        height: 100%;
    }

    /* We make the user list 175px and firepad fill the rest of the page. */
    #userlist {
        position: absolute;
        left: 0;
        top: 50px;
        bottom: 0;
        height: auto;
        width: 175px;
    }

    #firepad {
        position: absolute;
        left: 175px;
        top: 50px;
        bottom: 0;
        right: 0;
        height: auto;
    }
</style>

Firepad se ha configurado correctamente.

Cargar contenido de un documento de Word existente en un editor

Ahora queremos brindarles a nuestros usuarios una forma de cargar contenido de un documento de Word existente en el editor de texto. En la interfaz, agregamos un elemento de tipo archivo que permite a un usuario seleccionar un documento de Word desde su máquina local. En el backend, usamos la biblioteca GroupDocs.Editor para recuperar el contenido de un documento de Word como una cadena HTML. Finalmente, usamos el método setHtml() de Firepad para mostrar el contenido en el editor de texto.

Agrega lo siguiente elemento en el archivo Index.cshtml antes etiqueta.

<form method="post" enctype="multipart/form-data" id="uploadForm">
    <input asp-for="UploadedDocument" />
    <input type="submit" value="Upload Document" class="btn btn-primary" asp-page-handler="UploadDocument" />
</form>

En el archivo Index.cshtml.cs, defina una propiedad correspondiente.

[BindProperty]
public IFormFile UploadedDocument { get;  set; }

Ejecute el proyecto y haga clic en el botón Elegir archivo. Seleccione un documento de Word que desee cargar y haga clic en el botón Cargar documento. No pasará nada porque aún no hemos definido el controlador en Index.cshtml.cs. Antes de hacer esto, primero agreguemos la biblioteca GroupDocs.Editor en nuestro proyecto.

Integrar GroupDocs.Editor

GroupDocs.Editor está disponible como un paquete NuGet para que podamos agregarlo fácilmente a nuestro proyecto. Haga clic con el botón derecho en el proyecto y seleccione la opción Administrar paquetes NuGet. Se abrirá la ventana Administrar paquetes NuGet, seleccione la pestaña Examinar e ingrese GroupDocs.Editor en el campo de búsqueda. GroupDocs.Editor debería aparecer como primer resultado, selecciónelo y luego haga clic en el botón Agregar paquete.

Agregar GroupDocs.Editor a través de NuGet Package Manager

Cuando el paquete se agrega correctamente, aparecerá en la subcarpeta NuGet en la carpeta Dependencias.

Manejo de datos de formularios

Ahora escribimos un controlador (método OnPostUploadDocument()) que se llamará cuando un usuario haga clic en el botón Cargar documento. El objeto UploadedDocument (de tipo IFormFile) contiene el contenido del documento cargado. Primero, guardamos el documento en el servidor y luego usamos la biblioteca GroupDocs.Editor para obtener su contenido como cadena HTML. Agregue el siguiente código en el archivo Index.cshtml.cs.

private readonly IWebHostEnvironment _hostingEnvironment;

public string DocumentContent { get; set; }

public IndexModel(IWebHostEnvironment hostingEnvironment)
{
    _hostingEnvironment = hostingEnvironment;
}

public void OnPostUploadDocument()
{
    var projectRootPath = Path.Combine(_hostingEnvironment.ContentRootPath, "UploadedDocuments");
    var filePath = Path.Combine(projectRootPath, UploadedDocument.FileName);
    UploadedDocument.CopyTo(new FileStream(filePath, FileMode.Create));
    ShowDocumentContentInTextEditor(filePath);
}

private void ShowDocumentContentInTextEditor(string filePath)
{
    WordProcessingLoadOptions loadOptions = new WordProcessingLoadOptions();
    Editor editor = new Editor(filePath, delegate { return loadOptions; }); //passing path and load options (via delegate) to the constructor
    EditableDocument document = editor.Edit(new WordProcessingEditOptions()); //opening document for editing with format-specific edit options

    DocumentContent = document.GetContent();
}

Firepad proporciona dos eventos para escuchar. Uno de ellos está ’listo’ y se activa una vez que Firepad ha recuperado el contenido inicial del editor. Adjuntamos una devolución de llamada a este tipo de evento y en la devolución de llamada, pasamos la cadena DocumentContent como argumento al método setHtml() del objeto firepad. Agregue el siguiente código en la función init() en Index.cshtml.

firepad.on('ready', function () {
    if (firepad.isHistoryEmpty()) {
        var documentContent = '@Model.DocumentContent';
        if (documentContent.length != 0) {   
            firepad.setHtml(htmlDecode(documentContent));
        } else {
            firepad.setText("Welcome to your own private pad! Share the URL above and collaborate with your friends.");
        }
    }
});

Es posible que haya notado que pasamos la cadena documentContent primero al método htmlDecode() antes de pasar al método setHtml(). Es para reemplazar entidades de caracteres como <, > con signos (< y >). El método htmlDecode() tiene el siguiente aspecto.

function htmlDecode(input) {
    var e = document.createElement('div');
    e.innerHTML = input;
    return e.childNodes[0].nodeValue;
}

Ejecute el proyecto, ahora debería poder cargar el contenido de un documento de Word en un editor.

En la parte II de esta publicación, expliqué cómo podemos ampliar nuestra aplicación para incluir las siguientes funciones:

  • Descargue el contenido del editor como documento MS Word, PDF, TXT o HTML.
  • Comparta la URL con amigos para que puedan editar el documento al mismo tiempo.

Por favor, échale un vistazo.

El código fuente completo del proyecto está disponible en GitHub.

Ver también