Na primeira postagem do blog, criamos um aplicativo da web do tipo Documentos Google que possui os seguintes recursos:

  • Edição de Rich Text (alterar a fonte do texto, tamanho, cor, estilo (negrito, itálico), alinhamento etc.).
  • Edição colaborativa em tempo real do mesmo documento. Vários usuários podem acessar o documento ao mesmo tempo e modificá-lo.
  • Carregue o conteúdo de um documento do Word existente em um editor.

Nesta postagem do blog, estenderemos nosso aplicativo da Web para incluir os seguintes recursos:

  • Baixe o conteúdo do editor como documento MS Word, PDF, TXT ou HTML.
  • Compartilhe a URL com amigos para que eles possam editar o documento ao mesmo tempo.

O produto final terá a seguinte aparência:

Google Docs como a interface do aplicativo

Baixar o conteúdo do editor como documento do Microsoft Word

Primeiro, adicionamos um <input> elemento do tipo submit ao nosso formulário para mostrar o botão “Download Document” no front-end. Usamos o atributo asp-page-handler para especificar o manipulador do botão. Nosso elemento de formulário agora tem a seguinte aparência:

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

Você deve ter notado que adicionamos outro <input> elemento do tipo oculto. Este elemento está vinculado à propriedade DocumentContent em Index.cshtml.cs. Usaremos esta propriedade para armazenar o conteúdo do editor como uma string HTML.

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

Firepad fornece outro evento sincronizado para escuta. Ele é acionado quando nosso cliente local edita o documento e quando essas edições são gravadas com sucesso no Firebase. Anexamos um callback a este tipo de evento para definir o valor da propriedade DocumentContent para firepad.getHtml(). Por favor, adicione o seguinte código na função init() em 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();
    }
});

Agora implementamos a funcionalidade do manipulador OnPostDownloadDocument(). Usamos a biblioteca GroupDocs.Editor para salvar o conteúdo do editor como documento do Microsoft Word, que é armazenado na propriedade DocumentContent. O manipulador retorna o documento do Word como resposta ao usuário.

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)
    };
}

A variável UploadedDocumentPath é definida como uma string volátil para manter o valor do caminho do documento carregado entre as sessões.

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();
}

Verifique os artigos Save Document e Create EditableDocument from file or markup para saber mais sobre as classes GroupDocs.Editor.

Execute o projeto e teste o seguinte caso de uso:

  1. Carregue o conteúdo de um documento do Word existente em um editor clicando no botão Upload Document.
  2. Faça as alterações desejadas no conteúdo.
  3. Clique no botão Baixar documento para baixar o conteúdo atualizado como um documento do Word.

Baixe o Conteúdo do Editor como Documento PDF

Precisamos fazer algumas modificações no manipulador OnPostDownloadDocument() para retornar o documento PDF como resposta. Usamos PdfSaveOptions em vez de WordProcessingSaveOptions e usamos application/pdf como um 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"
    };
}

Baixe o Conteúdo do Editor como Documento de Texto Simples

Para retornar um documento de texto simples (.txt) como resposta, usamos a classe TextSaveOptions e usamos text/plain como um 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"
    };
}

Compartilhar URL de um Editor com amigos

Devemos fornecer aos usuários uma maneira conveniente de copiar o URL de um editor e compartilhá-lo com amigos. Para fazer isso, adicione um <input> elemento do tipo text em Index.cshtml.

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

Adicione o acima<div> elemento antes de <div id="userlist"> etiqueta. Definimos o valor deste campo de entrada de texto para URL de um editor usando a seguinte linha de código. Adicione este código na função init() em Index.cshtml.

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

Faremos pequenas alterações em nosso CSS para garantir que o campo de entrada de texto seja exibido corretamente. Defina a posição superior do firepad e da lista de usuários para 100px e adicione uma margem esquerda ao 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;
}

Execute o projeto, você deverá ver um campo de texto que permite copiar a URL do editor. Compartilhe com seus amigos e edite o documento simultaneamente com eles.

O código fonte completo do projeto está disponível no GitHub.

Veja também