Kilku klientów zwróciło się do nas i zapytało, w jaki sposób mogą stworzyć aplikację internetową przypominającą Dokumenty Google, korzystając z naszych interfejsów API. Dokumenty Google to edytor tekstu umożliwiający użytkownikom tworzenie i edytowanie plików online podczas współpracy z innymi użytkownikami w czasie rzeczywistym.

W tym poście na blogu wyjaśniono, jak łatwo jest utworzyć uproszczoną wersję Dokumentów Google zawierającą następujące funkcje:

  • Edycja tekstu sformatowanego (zmiana czcionki, rozmiaru, koloru, stylu (pogrubienie, kursywa), wyrównanie itp.).
  • Wspólna edycja tego samego dokumentu w czasie rzeczywistym. Wielu użytkowników może jednocześnie uzyskać dostęp do dokumentu i go modyfikować.
  • Prześlij zawartość istniejącego dokumentu programu Word do edytora.
  • Zapisz tekst w edytorze jako dokument MS Word, PDF, TXT lub HTML.

Nasz produkt końcowy będzie wyglądał następująco:

Dokumenty Google, takie jak interfejs aplikacji

Narzędzia i technologie — twórz Dokumenty Google, takie jak aplikacja

Opracujemy aplikację internetową podobną do Dokumentów Google w ASP.NET Core i skorzystamy z następujących dwóch bibliotek:

  • 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.
  • Edytor GroupDocs dla .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.

Użyłem Visual Studio dla komputerów Mac jako IDE. Możesz jednak pobrać bezpłatną wersję społecznościową programu Visual Studio, w zależności od platformy, z tutaj. Zaczynajmy.

Utwórz nowy projekt aplikacji internetowej ASP.NET Core i nadaj mu nazwę „GoogleDocsLite".

Utwórz nową aplikację internetową ASP.NET Core

Uruchom aplikację, aby upewnić się, że wszystko jest poprawnie skonfigurowane.

Zintegruj Firepada

Możemy dodać Firepad do naszej aplikacji internetowej, dołączając następujące pliki JavaScript w pliku sekcja 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" />

Aby utworzyć Firepad, zainicjujemy Firebase, CodeMirror, a następnie Firepad. Dodaj następujący skrypt i kod HTML w pliku 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>

Zastąp zawartość pliku config konfiguracją własnego projektu Firebase.

Chcemy, aby powyższy skrypt został wykonany, gdy strona internetowa całkowicie wczyta całą zawartość (pliki skryptów, pliki CSS itp.). Zatem wywołaj funkcję init() z atrybutu zdarzenia onLoad element w Layout.cshtml.

<body onload="init()">

Twoje <body> powinien wyglądać następująco. Jeśli zawiera niepotrzebne tagi, takie jak <header> , <footer> , usuń je.

Element ciała

Jeśli uruchomisz projekt, zauważysz, że firepad i lista użytkowników nie są odpowiednio wyrównane. Użyj poniższego kodu CSS, aby dostosować rozmiar/położenie Firepad i listę użytkowników. Możesz dodać następujący kod w obrębie element 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 został pomyślnie skonfigurowany.

Prześlij zawartość istniejącego dokumentu programu Word do edytora

Teraz chcemy dać naszym użytkownikom możliwość przesyłania zawartości wychodzącego dokumentu programu Word do edytora tekstu. Na froncie dodajemy plik element pliku typu, który pozwala użytkownikowi wybrać dokument programu Word z komputera lokalnego. Na zapleczu używamy biblioteki GroupDocs.Editor do pobierania zawartości dokumentu programu Word w postaci ciągu HTML. Na koniec używamy metody setHtml() Firepada, aby wyświetlić zawartość w edytorze tekstu.

Dodaj poniższe element w pliku Index.cshtml wcześniej etykietka.

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

W pliku Index.cshtml.cs zdefiniuj odpowiednią właściwość.

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

Uruchom projekt i kliknij przycisk Wybierz plik. Wybierz dokument programu Word, który chcesz przesłać, i kliknij przycisk Prześlij dokument. Nic się nie stanie, ponieważ nie zdefiniowaliśmy jeszcze procedury obsługi w Index.cshtml.cs. Zanim to zrobimy dodajmy najpierw do naszego projektu bibliotekę GroupDocs.Editor.

Zintegruj GroupDocs.Editor

GroupDocs.Editor jest dostępny jako pakiet NuGet, dzięki czemu możemy łatwo dodać go do naszego projektu. Kliknij projekt prawym przyciskiem myszy i wybierz opcję Zarządzaj pakietami NuGet. Otworzy się okno Zarządzaj pakietami NuGet, wybierz kartę Przeglądaj i w polu wyszukiwania wpisz GroupDocs.Editor. Jako pierwszy wynik powinien pojawić się GroupDocs.Editor, zaznacz go i kliknij przycisk Dodaj pakiet.

Dodaj GroupDocs.Editor za pomocą Menedżera pakietów NuGet

Po pomyślnym dodaniu pakietu pojawi się on w podfolderze NuGet w folderze Zależności.

Obsługa danych formularzy

Teraz napiszemy procedurę obsługi (metoda OnPostUploadDocument()), która zostanie wywołana, gdy użytkownik kliknie przycisk Prześlij dokument. Obiekt UploadedDocument (typu IFormFile) zawiera treść przesłanego dokumentu. Najpierw zapisujemy dokument na serwerze, a następnie korzystamy z biblioteki GroupDocs.Editor, aby pobrać jego zawartość w postaci ciągu HTML. Dodaj następujący kod w pliku 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 udostępnia dwa zdarzenia do nasłuchiwania. Jeden z nich jest „gotowy", który jest uruchamiany, gdy Firepad pobierze początkową zawartość edytora. Do tego typu zdarzenia dołączamy wywołanie zwrotne i w wywołaniu zwrotnym przekazujemy ciąg DocumentContent jako argument metody setHtml() obiektu Firepad. Dodaj następujący kod w funkcji init() w 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.");
        }
    }
});

Być może zauważyłeś, że najpierw przekazaliśmy ciąg documentContent do metody htmlDecode(), a następnie do metody setHtml(). Ma na celu zastąpienie jednostek znakowych, takich jak <, >, znakami (< i >). Metoda htmlDecode() wygląda następująco.

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

Uruchom projekt, teraz powinieneś móc przesłać zawartość dokumentu Word do edytora.

W części II tego wpisu wyjaśniłem, w jaki sposób możemy rozszerzyć naszą aplikację o następujące funkcje:

  • Pobierz zawartość edytora jako dokument MS Word, PDF, TXT lub HTML.
  • Udostępnij adres URL znajomym, aby mogli jednocześnie edytować dokument.

Proszę sprawdź to.

Pełny kod źródłowy projektu jest dostępny na GitHub.

Zobacz też