چندین مشتری به ما مراجعه کرده‌اند و پرسیده‌اند که چگونه می‌توانند یک برنامه وب مشابه Google Docs با استفاده از APIهای ما ایجاد کنند. Google Docs یک ویرایشگر متن است که به کاربران اجازه می‌دهد فایل‌ها را به صورت آنلاین ایجاد و ویرایش کنند و در عین حال با دیگر کاربران به صورت Real-time همکاری کنند.

این پست وبلاگ توضیح می‌دهد که چگونه آسان است تا یک نسخه سبک از Google Docs ایجاد کنید که ویژگی‌های زیر را داشته باشد:

  • ویرایش متن غنی (تغییر فونت متن، اندازه، رنگ، سبک (درشت، کج)، تراز و غیره).
  • ویرایش مشارکتی آنی یک سند واحد. چندین کاربر می‌توانند به سند در همان زمان دسترسی پیدا کرده و آن را ویرایش کنند.
  • محتوای یک سند Word موجود را به یک ویرایشگر بارگذاری کنید.
  • متن را در ویرایشگر به عنوان سند MS Word، PDF، TXT یا HTML ذخیره کنید.

محصول نهایی ما به شکل زیر خواهد بود:

رابط کاربری اپلیکیشن مشابه Google Docs

Tools and Technologies – Create Google Docs like App

ما یک برنامه وب شبیه Google Docs را در ASP.NET Core توسعه خواهیم داد و از دو کتابخانه زیر استفاده خواهیم کرد:

  • 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 برای .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.

I have used Visual Studio for Mac as an IDE. However, you can download the free community edition of Visual Studio, depending upon your platform, from here. Let’s start.

Create a new ASP.NET Core Web Application project and name the project `GoogleDocsLite”.

یک اپ وب ASP.NET Core جدید ایجاد کنید

برنامه را اجرا کنید تا اطمینان حاصل شود که همه چیز به درستی تنظیم شده است.

Integrate Firepad

ما می‌توانیم Firepad را به برنامه وب خود اضافه کنیم با گنجاندن فایل‌های جاوااسکریپت زیر در بخش فایل 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" />

برای ایجاد یک Firepad، ما Firebase، CodeMirror و سپس Firepad را راه‌اندازی خواهیم کرد. کد اسکریپت و HTML زیر را در 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>

لطفاً محتوای config را با پیکربندی پروژه Firebase خودتان جایگزین کنید.

ما می‌خواهیم اسکریپت بالا پس از بارگذاری کامل تمام محتویات وب‌سایت (مانند فایل‌های اسکریپت، فایل‌های CSS و غیره) اجرا شود. بنابراین، تابع init() را از ویژگی رویداد onLoad عنصر در Layout.cshtml فراخوانی کنید.

<body onload="init()">

عنصر <body> شما باید به صورت زیر باشد. اگر شامل تگ‌های غیرضروری مانند <header>، <footer> است، لطفاً آنها را حذف کنید.

عنصر بدنی

اگر پروژه را اجرا کنید، متوجه خواهید شد که firepad و userlist به درستی هم‌راستا نیستند. لطفاً از کد CSS زیر برای تنظیم اندازه/موقعیت firepad و userlist استفاده کنید. می‌توانید کد زیر را درون عنصر در 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 با موفقیت راه‌اندازی شده است.

محتوای یک سند ورد موجود را به یک ویرایشگر بارگذاری کنید

اکنون می‌خواهیم به کاربرانمان راهی برای بارگذاری محتوای یک سند ورد موجود در ویرایشگر متن ارائه دهیم. در سمت کاربر، یک عنصر از نوع فایل اضافه می‌کنیم که به کاربر اجازه می‌دهد یک سند ورد را از دستگاه محلی خود انتخاب کند. در سمت سرور، از کتابخانه GroupDocs.Editor برای بازیابی محتوای یک سند ورد به عنوان رشته HTML استفاده می‌کنیم. در نهایت، از متد setHtml() فایرپد برای نمایش محتوا در ویرایشگر متن استفاده می‌کنیم.

Add the following element in Index.cshtml file before tag.

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

در فایل Index.cshtml.cs، یک ویژگی مربوطه را تعریف کنید.

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

پروژه را اجرا کنید و بر روی دکمه انتخاب فایل کلیک کنید. یک سند Word که می‌خواهید بارگذاری کنید را انتخاب کنید و بر روی دکمه بارگذاری سند کلیک کنید. هیچ اتفاقی نخواهد افتاد زیرا ما هنوز هندلر را در Index.cshtml.cs تعریف نکرده‌ایم. قبل از اینکه این کار را انجام دهیم، بیایید ابتدا کتابخانه GroupDocs.Editor را به پروژه‌مان اضافه کنیم.

Integrate GroupDocs.Editor

GroupDocs.Editor به عنوان یک بسته NuGet در دسترس است، بنابراین می‌توانیم به راحتی آن را به پروژه خود اضافه کنیم. بر روی پروژه کلیک راست کرده و گزینه Manage NuGet Packages را انتخاب کنید. پنجره Manage NuGet Packages باز خواهد شد، برگه Browse را انتخاب کنید و GroupDocs.Editor را در فیلد جستجو وارد کنید. GroupDocs.Editor باید به عنوان نتیجه اول ظاهر شود، آن را انتخاب کرده و سپس بر روی دکمه Add Package کلیک کنید.

GroupDocs.Editor را از طریق مدیر بسته NuGet اضافه کنید

وقتی که بسته با موفقیت افزوده شود، در زیر زیر پوشه NuGet در پوشه Dependencies ظاهر خواهد شد.

مدیریت داده‌های فرم

حالا ما یک هندلر (متد OnPostUploadDocument()) می‌نویسیم که هنگام کلیک بر روی دکمه بارگذاری سند توسط کاربر فراخوانی می‌شود. شی UploadedDocument (از نوع IFormFile) محتویات سند بارگذاری شده را شامل می‌شود. ابتدا، ما سند را در سرور ذخیره می‌کنیم و سپس از کتابخانه GroupDocs.Editor برای دریافت محتویات آن به عنوان رشته HTML استفاده می‌کنیم. لطفاً کد زیر را در فایل 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 دو رویداد برای گوش دادن ارائه می‌دهد. یکی از آن‌ها ‘آماده‘ است که یک بار هنگامی که Firepad محتویات اولیه ویرایشگر را بازیابی کرده است، فعال می‌شود. ما یک callback به این نوع رویداد متصل می‌کنیم و در callback، رشته DocumentContent را به عنوان یک آرگومان به متد setHtml() شیء firepad منتقل می‌کنیم. لطفاً کد زیر را در تابع init() در 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.");
        }
    }
});

شما ممکن است متوجه شده باشید که ما اولین بار رشته documentContent را به متد htmlDecode() منتقل کردیم و سپس آن را به متد setHtml() منتقل کردیم. این برای جایگزینی موجودیت‌های کاراکتری مانند < و > با علائم (< و > است).متد htmlDecode() به صورت زیر است.

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

پروژه را اجرا کنید، اکنون باید قادر باشید محتوای یک سند Word را به یک ویرایشگر بارگذاری کنید.

در part II این پست، توضیح داده‌ام که چگونه می‌توانیم برنامه خود را برای شامل کردن ویژگی‌های زیر گسترش دهیم:

  • محتوای ویرایشگر را به عنوان سند MS Word، PDF، TXT یا HTML دانلود کنید.
  • URL را با دوستان به اشتراک بگذارید تا بتوانند به طور همزمان سند را ویرایش کنند.

لطفاً check it out.

کد منبع کامل پروژه در GitHub در دسترس است.

به همچنین نگاه کنید