В первом сообщении в блоге мы создали веб-приложение, похожее на Google Документы, со следующими функциями:

  • Редактирование расширенного текста (изменение шрифта текста, размера, цвета, стиля (полужирный, курсив), выравнивание и т. д.).
  • Совместное редактирование одного и того же документа в режиме реального времени. Несколько пользователей могут одновременно получать доступ к документу и изменять его.
  • Загрузите содержимое существующего документа Word в редактор.

В этом сообщении блога мы расширим наше веб-приложение, включив в него следующие функции:

  • Загрузите содержимое редактора в виде документа MS Word, PDF, TXT или HTML.
  • Поделитесь URL-адресом с друзьями, чтобы они могли одновременно редактировать документ.

Конечный продукт будет выглядеть следующим образом:

Документы Google как интерфейс приложения

Загрузить содержимое редактора в виде документа Microsoft Word

Сначала мы добавляем <input> элемент типа отправить в нашу форму, чтобы отобразить кнопку «Загрузить документ» во внешнем интерфейсе. Мы используем атрибут asp-page-handler, чтобы указать обработчик кнопки. Теперь наш элемент формы выглядит следующим образом:

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

Вы могли заметить, что мы добавили еще один <input> элемент скрытого типа. Этот элемент привязан к свойству DocumentContent в Index.cshtml.cs. Мы будем использовать это свойство для хранения содержимого редактора в виде строки HTML.

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

Firepad предоставляет другое событие, синхронизированное для прослушивания. Он запускается, когда наш локальный клиент редактирует документ, и когда эти изменения были успешно записаны в Firebase. Мы присоединяем обратный вызов к этому типу события, чтобы установить значение свойства DocumentContent в firepad.getHtml(). Добавьте следующий код в функцию init() в 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();
    }
});

Теперь реализуем функционал обработчика OnPostDownloadDocument(). Мы используем библиотеку GroupDocs.Editor для сохранения содержимого редактора в виде документа Microsoft Word, который хранится в свойстве DocumentContent. Обработчик возвращает документ Word в качестве ответа пользователю.

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

Переменная UploadedDocumentPath определяется как изменяемая строка для хранения значения пути загруженного документа между сеансами.

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

Ознакомьтесь со статьями Сохранить документ и Создать EditableDocument из файла или разметки, чтобы узнать больше о классах GroupDocs.Editor.

Запустите проект и протестируйте следующий вариант использования:

  1. Загрузите содержимое существующего документа Word в редактор, нажав кнопку «Загрузить документ».
  2. Внесите желаемые изменения в содержимое.
  3. Нажмите кнопку «Загрузить документ», чтобы загрузить обновленный контент в виде документа Word.

Загрузить содержимое редактора в виде PDF-документа

Нам нужно внести несколько изменений в обработчик OnPostDownloadDocument(), чтобы возвращать PDF-документ в качестве ответа. Мы используем PdfSaveOptions вместо WordProcessingSaveOptions и используем application/pdf в качестве типа 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"
    };
}

Загрузить содержимое редактора в виде простого текстового документа

Чтобы вернуть простой текстовый документ (.txt) в качестве ответа, мы используем класс TextSaveOptions и используем text/plain в качестве типа 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"
    };
}

Поделитесь URL-адресом редактора с друзьями

Мы должны предоставить пользователям удобный способ скопировать URL-адрес редактора и поделиться им с друзьями. Для этого добавьте <input> элемент типа text в Index.cshtml.

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

Добавьте указанный выше <div> элемент перед<div id="userlist"> тег. Мы устанавливаем значение этого поля ввода текста в URL-адрес редактора, используя следующую строку кода. Добавьте этот код в функцию init() в Index.cshtml.

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

Мы внесем небольшие изменения в наш CSS, чтобы убедиться, что поле ввода текста отображается правильно. Установите верхнюю позицию firepad и списка пользователей на 100 пикселей и добавьте левое поле к полю ввода текста.

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

Запустите проект, вы должны увидеть текстовое поле, позволяющее скопировать URL-адрес редактора. Поделитесь им с друзьями и редактируйте документ одновременно с ними.

Полный исходный код проекта доступен на GitHub.

Смотрите также