ลูกค้าหลายรายติดต่อเราและถามว่าจะสร้าง Google เอกสารเช่นเว็บแอปโดยใช้ API ของเราได้อย่างไร Google Docs เป็นโปรแกรมประมวลผลคำที่ช่วยให้ผู้ใช้สามารถสร้างและแก้ไขไฟล์ออนไลน์ในขณะที่ทำงานร่วมกับผู้ใช้รายอื่นแบบเรียลไทม์

โพสต์ในบล็อกนี้จะอธิบายว่าการสร้าง Google เอกสารเวอร์ชัน Lite ที่มีคุณสมบัติดังต่อไปนี้นั้นง่ายดายเพียงใด:

  • การแก้ไข Rich Text (เปลี่ยนแบบอักษร ขนาด สี สไตล์ (ตัวหนา ตัวเอียง) การจัดตำแหน่ง ฯลฯ)
  • การแก้ไขร่วมกันแบบเรียลไทม์ของเอกสารเดียวกัน ผู้ใช้หลายคนสามารถเข้าถึงเอกสารพร้อมกันและแก้ไขได้
  • อัปโหลดเนื้อหาของเอกสาร Word ที่มีอยู่ลงในโปรแกรมแก้ไข
  • บันทึกข้อความในตัวแก้ไขเป็นเอกสาร MS Word, PDF, TXT หรือ HTML

ผลิตภัณฑ์ขั้นสุดท้ายของเราจะมีลักษณะดังนี้:

Google เอกสารเช่น App Interface

เครื่องมือและเทคโนโลยี – สร้าง Google เอกสารเหมือนแอป

เราจะพัฒนา Google Docs เช่นเดียวกับเว็บแอปใน ASP.NET Core และใช้ไลบรารีสองไลบรารีต่อไปนี้:

  • แป้นดับเพลิง 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.

ฉันใช้ Visual Studio สำหรับ Mac เป็น IDE อย่างไรก็ตาม คุณสามารถดาวน์โหลด Visual Studio รุ่นชุมชนฟรีได้ ทั้งนี้ขึ้นอยู่กับแพลตฟอร์มของคุณ จาก ที่นี่ เริ่มกันเลย.

สร้างโครงการ ASP.NET Core Web Application ใหม่และตั้งชื่อโครงการ “GoogleDocsLite"

สร้าง ASP.NET Core Web App ใหม่

เรียกใช้แอปพลิเคชันเพื่อให้แน่ใจว่าทุกอย่างได้รับการตั้งค่าอย่างถูกต้อง

บูรณาการ Firepad

เราสามารถเพิ่ม Firepad ลงในเว็บแอปของเราโดยรวมไฟล์ JavaScript ต่อไปนี้ใน ส่วนของ 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>

โปรดแทนที่เนื้อหาของการกำหนดค่าด้วยการกำหนดค่าของโปรเจ็กต์ Firebase ของคุณเอง

เราต้องการให้สคริปต์ด้านบนทำงานเมื่อหน้าเว็บโหลดเนื้อหาทั้งหมดเรียบร้อยแล้ว (ไฟล์สคริปต์ ไฟล์ CSS ฯลฯ) ดังนั้นให้เรียกใช้ฟังก์ชัน init() จากแอตทริบิวต์เหตุการณ์ onLoad ของ องค์ประกอบใน Layout.cshtml

<body onload="init()">

ของคุณ ‘ องค์ประกอบควรมีลักษณะดังนี้ หากมีแท็กที่ไม่จำเป็นเช่น , ` โปรดลบออก

องค์ประกอบของร่างกาย

หากคุณรันโปรเจ็กต์ คุณจะสังเกตเห็นว่า firepad และรายชื่อผู้ใช้ไม่สอดคล้องกันอย่างเหมาะสม โปรดใช้โค้ด CSS ต่อไปนี้เพื่อปรับขนาด/ตำแหน่งของ firepad และรายการผู้ใช้ คุณสามารถเพิ่มรหัสต่อไปนี้ภายใน องค์ประกอบของ 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 สำเร็จแล้ว

อัปโหลดเนื้อหาของเอกสาร Word ที่มีอยู่ลงในโปรแกรมแก้ไข

ตอนนี้เราต้องการให้ผู้ใช้ของเรามีวิธีอัปโหลดเนื้อหาของเอกสาร Word ที่ออกจากโปรแกรมแก้ไขข้อความ ที่ส่วนหน้า เราเพิ่ม องค์ประกอบของไฟล์ประเภทที่อนุญาตให้ผู้ใช้เลือกเอกสาร Word จากเครื่องท้องถิ่นของตน ที่แบ็กเอนด์ เราใช้ไลบรารี GroupDocs.Editor เพื่อดึงเนื้อหาของเอกสาร Word เป็นสตริง HTML สุดท้ายนี้ เราใช้เมธอด setHtml() ของ Firepad เพื่อแสดงเนื้อหาในโปรแกรมแก้ไขข้อความ

เพิ่มสิ่งต่อไปนี้ องค์ประกอบในไฟล์ Index.cshtml มาก่อน แท็ก

<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 ในโครงการของเราก่อน

ผสานรวม GroupDocs.Editor

GroupDocs.Editor มีให้บริการในรูปแบบแพ็คเกจ NuGet ดังนั้นเราจึงสามารถเพิ่มลงในโปรเจ็กต์ของเราได้อย่างง่ายดาย คลิกขวาที่โครงการแล้วเลือกตัวเลือกจัดการแพ็คเกจ NuGet หน้าต่างจัดการแพ็คเกจ NuGet จะเปิดขึ้น เลือกแท็บเรียกดู และป้อน GroupDocs.Editor ในช่องค้นหา GroupDocs.Editor ควรปรากฏขึ้นเป็นผลลัพธ์แรก เลือกแล้วคลิกปุ่มเพิ่มแพ็คเกจ

เพิ่ม GroupDocs.Editor ผ่าน NuGet Package Manager

เมื่อเพิ่มแพ็คเกจสำเร็จแล้ว มันจะปรากฏใต้โฟลเดอร์ย่อย 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 ดึงข้อมูลเนื้อหาตัวแก้ไขเริ่มต้นแล้ว เราแนบการเรียกกลับเข้ากับเหตุการณ์ประเภทนี้ และในการเรียกกลับ เราจะส่งสตริง 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 ไปยังโปรแกรมแก้ไขได้

ใน ตอนที่ II ของโพสต์นี้ ฉันได้อธิบายว่าเราจะขยายแอปพลิเคชันของเราให้มีคุณสมบัติต่อไปนี้ได้อย่างไร:

  • ดาวน์โหลดเนื้อหาของโปรแกรมแก้ไขเป็นเอกสาร MS Word, PDF, TXT หรือ HTML
  • แบ่งปัน URL กับเพื่อน ๆ เพื่อให้พวกเขาสามารถแก้ไขเอกสารได้ในเวลาเดียวกัน

กรุณา ตรวจสอบออก.

ซอร์สโค้ดที่สมบูรณ์ของโครงการมีอยู่ใน GitHub

ดูสิ่งนี้ด้วย