En la primera publicación de blog, creamos una aplicación web similar a Google Docs que tiene 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.

En esta publicación de blog, ampliaremos nuestra aplicación web para incluir las siguientes características:

  • 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.

El producto final se verá de la siguiente manera:

Google Docs como la interfaz de la aplicación

Descargar Contenido del Editor como Documento de Microsoft Word

Primero, agregamos un <input> elemento de tipo enviar a nuestro formulario para mostrar el botón “Descargar documento” en el front-end. Usamos el atributo asp-page-handler para especificar el controlador del botón. Nuestro elemento de formulario ahora tiene el siguiente aspecto:

<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" />
    <input type="submit" value="Download Document" class="btn btn-primary" asp-page-handler="DownloadDocument" />

    <input asp-for="DocumentContent" type="hidden" />
</form>

Es posible que haya notado que hemos agregado otro <input> elemento de tipo oculto. Este elemento está vinculado a la propiedad DocumentContent en Index.cshtml.cs. Usaremos esta propiedad para almacenar el contenido del editor como una cadena HTML.

[BindProperty]
public string DocumentContent { get; set; }

Firepad proporciona otro evento sincronizado para escuchar. Se activa cuando nuestro cliente local edita el documento y cuando esas ediciones se han escrito correctamente en Firebase. Adjuntamos una devolución de llamada a este tipo de evento para establecer el valor de la propiedad DocumentContent en firepad.getHtml(). Agregue el siguiente código en la función init() en Index.cshtml.

firepad.on('synced', function (isSynced) {
    // isSynced will be false immediately after the user edits 
    // the pad, and true when their edit has been saved to Firebase.
    if (isSynced) {
        document.getElementById("DocumentContent").value = firepad.getHtml();
    }
});

Ahora implementamos la funcionalidad del controlador OnPostDownloadDocument(). Usamos la biblioteca GroupDocs.Editor para guardar el contenido del editor como documento de Microsoft Word, que se almacena en la propiedad DocumentContent. El controlador devuelve el documento de Word como respuesta al usuario.

public FileResult OnPostDownloadDocument()
{
    // Editor object is referencing to the document initially uploaded for editing.
    WordProcessingLoadOptions loadOptions = new WordProcessingLoadOptions();
    Editor editor = new Editor(UploadedDocumentPath, delegate { return loadOptions; });
    
    // <html>, <head> and <body> tags are missing in the HTML string stored in DocumentContent, so we are adding them manually.
    string completeHTML = "<!DOCTYPE html><html><head><title></title></head><body>" + DocumentContent + "</body></html>";
    EditableDocument document = EditableDocument.FromMarkup(completeHTML, null);
    
    // Path to the output document        
    var projectRootPath = Path.Combine(_hostingEnvironment.ContentRootPath, "DownloadedDocuments");
    var outputPath = Path.Combine(projectRootPath, Path.GetFileName(UploadedDocumentPath));
    
    // Save the Word Document at the outputPath 
    WordProcessingSaveOptions saveOptions = new WordProcessingSaveOptions(WordProcessingFormats.Docx);
    editor.Save(document, outputPath, saveOptions);
    
    // Return the Word Document as response to the User
    var bytes = System.IO.File.ReadAllBytes(outputPath);        
    return new FileContentResult(bytes, new MediaTypeHeaderValue("application/vnd.openxmlformats-officedocument.wordprocessingml.document"))
    {
        FileDownloadName = Path.GetFileName(UploadedDocumentPath)
    };
}

La variable UploadedDocumentPath se define como una cadena volátil para mantener el valor de la ruta del documento cargado entre sesiones.

static volatile string UploadedDocumentPath;

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

    // Retain the path of uploaded document between sessions.
    UploadedDocumentPath = filePath;

    ShowDocumentContentInTextEditor();
}

Consulte los artículos Guardar documento y Crear documento editable a partir de archivo o marcado para obtener más información sobre las clases de GroupDocs.Editor.

Ejecute el proyecto y pruebe el siguiente caso de uso:

  1. Cargue el contenido de un documento de Word existente en un editor haciendo clic en el botón Cargar documento.
  2. Realice los cambios deseados en el contenido.
  3. Haga clic en el botón Descargar documento para descargar el contenido actualizado como un documento de Word.

Descargar Contenido del Editor como Documento PDF

Necesitamos hacer algunas modificaciones en el controlador OnPostDownloadDocument() para devolver el documento PDF como respuesta. Usamos PdfSaveOptions en lugar de WordProcessingSaveOptions y usamos application/pdf como tipo MIME.

public FileResult OnPostDownloadDocument()
{
    WordProcessingLoadOptions loadOptions = new WordProcessingLoadOptions();
    Editor editor = new Editor(UploadedDocumentPath, delegate { return loadOptions; });

    string completeHTML = "<!DOCTYPE html><html><head><title></title></head><body>" + DocumentContent + "</body></html>";
    EditableDocument document = EditableDocument.FromMarkup(completeHTML, null);

    var projectRootPath = Path.Combine(_hostingEnvironment.ContentRootPath, "DownloadedDocuments");
    var outputPath = Path.Combine(projectRootPath, Path.GetFileNameWithoutExtension(UploadedDocumentPath) + ".pdf");

    PdfSaveOptions saveOptions = new PdfSaveOptions();
    editor.Save(document, outputPath, saveOptions);

    var bytes = System.IO.File.ReadAllBytes(outputPath);
    return new FileContentResult(bytes, new MediaTypeHeaderValue("application/pdf"))
    {
        FileDownloadName = Path.GetFileNameWithoutExtension(UploadedDocumentPath) + ".pdf"
    };
}

Descargar contenido del editor como documento de texto sin formato

Para devolver un documento de texto sin formato (.txt) como respuesta, usamos la clase TextSaveOptions y usamos text/plain como un tipo MIME.

public FileResult OnPostDownloadDocument()
{
    WordProcessingLoadOptions loadOptions = new WordProcessingLoadOptions();
    Editor editor = new Editor(UploadedDocumentPath, delegate { return loadOptions; });

    string completeHTML = "<!DOCTYPE html><html><head><title></title></head><body>" + DocumentContent + "</body></html>";
    EditableDocument document = EditableDocument.FromMarkup(completeHTML, null);

    var projectRootPath = Path.Combine(_hostingEnvironment.ContentRootPath, "DownloadedDocuments");
    var outputPath = Path.Combine(projectRootPath, Path.GetFileNameWithoutExtension(UploadedDocumentPath) + ".txt");

    TextSaveOptions saveOptions = new TextSaveOptions();
    editor.Save(document, outputPath, saveOptions);

    var bytes = System.IO.File.ReadAllBytes(outputPath);
    return new FileContentResult(bytes, new MediaTypeHeaderValue("text/plain"))
    {
        FileDownloadName = Path.GetFileNameWithoutExtension(UploadedDocumentPath) + ".txt"
    };
}

Comparte la URL de un Editor con amigos

Deberíamos proporcionar a los usuarios una forma conveniente de copiar la URL de un editor y compartirla con amigos. Para hacer esto, agregue un <input> elemento de tipo texto en Index.cshtml.

<div>
    <strong>
        <label for="shareURL">Edit with Friends: </label>
    </strong>
    <input type="text" name="shareURL" id="shareURL" size="50">
</div>

Agregue el anterior <div> elemento antes de <div id="userlist"> etiqueta. Establecemos el valor de este campo de entrada de texto en la URL de un editor usando la siguiente línea de código. Agregue este código en la función init() en Index.cshtml.

document.getElementById("shareURL").value = window.location.origin + window.location.pathname + window.location.hash;

Realizaremos cambios menores en nuestro CSS para garantizar que el campo de entrada de texto se muestre correctamente. Establezca la posición superior de Firepad y la lista de usuarios en 100 px, y agregue un margen izquierdo al campo de entrada de texto.

#userlist {
    position: absolute;
    left: 0;
    top: 100px;
    bottom: 0;
    height: auto;
    width: 175px;
}

#firepad {
    position: absolute;
    left: 175px;
    top: 100px;
    bottom: 0;
    right: 0;
    height: auto;
}

#uploadForm {
    margin: 16px 2px;
}

#shareURL {
    margin-left: 123px;
}

Ejecute el proyecto, debería ver un campo de texto que le permite copiar la URL del editor. Compártelo con tus amigos y edita el documento simultáneamente con ellos.

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

Ver también