### Example: Adding Multiple Users with IDomUserCommand Source: https://github.com/wai818/mormot-learning/blob/master/24_领域驱动设计.html This Delphi code demonstrates how to use the `IDomUserCommand` interface to add a batch of new `TUser` records. It illustrates resolving the command service via IoC, populating user data within a loop, calling `cmd.Add` for each user, and finally invoking `cmd.Commit` to persist all changes in a single transaction. Error handling is included. ```Delphi var cmd: IDomUserCommand; user: TUser; itext: RawUTF8; ... aServer.Services.Resolve(IDomUserCommand,cmd); user := TUser.Create; try for i := 1 to MAX do begin UInt32ToUtf8(i,itext); user.LogonName := ' '+itext; user.EmailValidated := evValidated; user.Name.Last := 'Last'+itext; user.Name.First := 'First'+itext; user.Address.Street1 := 'Street '+itext; user.Address.Country.Alpha2 := 'fr'; user.Phone1 := itext; if cmd.Add(user)<>cqrsSuccess then raise EMyApplicationException.CreateFmt('Invalid data: %s',[cmd.GetLastErrorInfo]); end; // here nothing is actually written to the database if cmd.Commit<>cqrsSuccess then raise EMyApplicationException.CreateFmt('Commit error: %s',[cmd.GetLastErrorInfo]); // here everything has been written to the database finally user.Free; end; ``` -------------------------------- ### SmartPascal Client-Side TSQLRecordPeople Instantiation Example Source: https://github.com/wai818/mormot-learning/blob/master/17_跨平台客户端.html An example demonstrating the instantiation of the `TSQLRecordPeople` class on the client-side using SmartPascal. This illustrates how the generated client-side ORM classes can be used to interact with remote data via standard CRUD operations, as shown in the `SQLite3\Samples\29 - SmartMobileStudio Client` example. ```SmartPascal people := new TSQLRecordPeople; ``` -------------------------------- ### OpenAIModel Class Constructor Source: https://github.com/wai818/mormot-learning/blob/master/2_架构原理.html This snippet defines the `__init__` method for the `OpenAIModel` class, outlining the `model_name` and `provider` parameters. It's crucial for configuring the specific OpenAI model and service provider to be used. ```APIDOC OpenAIModel: __init__(model_name: str, provider: str = 'openai') model_name: The name of the OpenAI model to use provider: The provider to use (defaults to 'openai') ``` -------------------------------- ### Delphi: Example of Method to be Stubbed with Custom Delegate Source: https://github.com/wai818/mormot-learning/blob/master/15_接口.html Presents a simple Subtract method from TServiceCalculator as an example of a function that could be stubbed using a custom delegate or event callback. This approach allows defining complex behavior for a method without implementing the full class. ```Delphi function TServiceCalculator.Subtract(n1, n2: double): double; begin result := n1-n2; end; ``` -------------------------------- ### Global CSS Styles for Responsive Layout and UI Elements Source: https://github.com/wai818/mormot-learning/blob/master/15_接口.html This CSS snippet defines global styles for a responsive web layout, including `container-fluid` and `col` classes for a grid system with media queries for different breakpoints (md, xl). It also includes utility classes for padding, display, and positioning, as well as specific styles for a sticky table of contents (`bd-toc`), a floating action button (`#floating-button`), and a modal image viewer (`.modal-box`). Keyframe animations for highlighting (`flash`) and zooming (`zoom`) are also present. ```CSS /* STYLE_GLOBAL_PLACE_HOLDER */ *, *::before, *::after { box-sizing: border-box; } .container-fluid { width: 100%; padding-right: 15px; padding-left: 15px; margin-right: auto; margin-left: auto; } .col, .col-1, .col-10, .col-11, .col-12, .col-2, .col-3, .col-4, .col-5, .col-6, .col-7, .col-8, .col-9, .col-auto, .col-lg, .col-lg-1, .col-lg-10, .col-lg-11, .col-lg-12, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-lg-auto, .col-md, .col-md-1, .col-md-10, .col-md-11, .col-md-12, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-md-auto, .col-sm, .col-sm-1, .col-sm-10, .col-sm-11, .col-sm-12, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-sm-auto, .col-xl, .col-xl-1, .col-xl-10, .col-xl-11, .col-xl-12, .col-xl-2, .col-xl-3, .col-xl-4, .col-xl-5, .col-xl-6, .col-xl-7, .col-xl-8, .col-xl-9, .col-xl-auto { position: relative; width: 100%; min-height: 1px; padding-right: 15px; padding-left: 15px; } .col-12 { -webkit-box-flex: 0; -ms-flex: 0 0 100%; flex: 0 0 100%; ``` -------------------------------- ### Incorrect: Querying Data with Direct SQL and TSQLTableJSON Source: https://github.com/wai818/mormot-learning/blob/master/6_日常的ORM.html Shows an example of querying data by executing a direct SQL `SELECT` statement and then manually parsing the results using `TSQLTableJSON` and iterating through fields. While `TSQLTableJSON` simplifies parsing, the direct SQL query is not the most ORM-friendly approach. ```Delphi procedure TMyClient.FillDrives(aList: TStrings); var table: TSQLTableJSON; X, FieldIndex: Integer; begin table := TSQLRestClientDB(GlobalClient).ExecuteList([TSQLDrives], 'SELECT * FROM drives'); if (table <> nil) then try FieldIndex := table.FieldIndex('drive'); if (FieldIndex >= 0) then for X := 1 to table.RowCount do Items.Add(UTF8ToString(table.GetU(X, FieldIndex))); finally table.Free; end; end; ``` -------------------------------- ### Correct: Querying Data with ORM using CreateAndFillPrepare Source: https://github.com/wai818/mormot-learning/blob/master/6_日常的ORM.html Demonstrates an ORM-centric way to fill a list with data using `TSQLDrives.CreateAndFillPrepare` and `FillOne` in a loop. This method abstracts SQL operations, providing a more robust and easier-to-understand approach, even if it might not be the absolute fastest due to abstraction. ```Delphi procedure TMyClient.FillDrives(aList: TStrings); begin aList.BeginUpdate; try aList.Clear; with TSQLDrives.CreateAndFillPrepare(GlobalClient,'') do try while FillOne do aList.Add(UTF8ToString(Drive)); finally Free; end; finally aList.EndUpdate; end; end; ``` -------------------------------- ### Atomic Integer Operations with TSynLocker's Internal Cache in Delphi Source: https://github.com/wai818/mormot-learning/blob/master/4_SynCommons单元.html This example illustrates how a class inheriting from TSynPersistentLocked can leverage TSynLocker's internal padded buffer for thread-safe data storage. It demonstrates using fSafe.LockedInt64[0] to read and fSafe.LockedInt64Increment(0,1) for atomic increment of an integer field, ensuring data integrity in multi-threaded environments. ```Delphi type TMyClass = class(TSynPersistentLocked) public procedure UseInternalIncrement; function FieldValue: integer; end; { TMyClass } function TMyClass.FieldValue: integer; begin // value read will also be protected by the mutex result := fSafe.LockedInt64[0]; end; procedure TMyClass.UseInternalIncrement; begin // this dedicated method will ensure an atomic increase fSafe.LockedInt64Increment(0,1); end; ``` -------------------------------- ### IDomUserCommand Methods and Two-Phase Commit Pattern Source: https://github.com/wai818/mormot-learning/blob/master/24_领域驱动设计.html This section outlines the core methods of `IDomUserCommand` and explains the two-phase commit pattern. It details how changes are prepared and validated before being explicitly committed to the persistent storage, ensuring data integrity and allowing for external service calls before final persistence. ```APIDOC IDomUserCommand: Commit: The main method for two-phase commit. Nothing is actually written to persistent storage until this method is called. Add(const aAggregate: TUser): TCQRSResult: Adds a new TUser aggregate. Update(const aUpdatedAggregate: TUser): TCQRSResult: Updates an existing TUser aggregate. Delete: TCQRSResult: Deletes the currently selected TUser aggregate. DeleteAll: TCQRSResult: Deletes all selected TUser aggregates. Rollback: TCQRSResult: Rolls back any pending changes. Typical Workflow for Modifying Existing Records: 1. Call an IDomUserQuery.Select* method (e.g., SelectByLogonName) to define the data scope. 2. Call an IDomUserCommand method (e.g., Update) to prepare the modification. 3. Call IDomUserCommand.Commit to persist the changes to the database. ``` -------------------------------- ### Initialize Dynamic Outline Panel on Page Load in JavaScript Source: https://github.com/wai818/mormot-learning/blob/master/23_非对称加密.html This event listener executes when the page finishes loading. It initializes the outline panel and floating container visibility, fetches all heading elements (h1-h6) from the `post-content` area, builds the table of contents (TOC) data, and then renders the TOC as an HTML tree within the outline panel. If no headings are found, the panel is hidden. ```JavaScript window.addEventListener('load', function() { var outlinePanel = document.getElementById('outline-panel'); outlinePanel.style.display = 'initial'; var floatingContainer = document.getElementById('container-floating'); floatingContainer.style.display = 'initial'; var outlineContent = document.getElementById('outline-content'); var postContent = document.getElementById('post-content'); // Fetch the outline. var headers = postContent.querySelectorAll("h1, h2, h3, h4, h5, h6"); toc = []; for (var i = 0; i < headers.length; ++i) { var header = headers[i]; toc.push({ level: parseInt(header.tagName.substr(1)), anchor: header.id, title: escapeHtml(header.textContent) }); } if (toc.length == 0) { setOutlinePanelVisible(false); setVisible(floatingContainer, false); return; } var baseLevel = baseLevelOfToc(toc); var tocTree = tocToTree(toPerfectToc(toc, baseLevel), baseLevel); outlineContent.innerHTML = tocTree; setOutlinePanelVisible(true); setVisible(floatingContainer, true); }); ``` -------------------------------- ### Declare a Delphi Interface (ICalculator) Source: https://github.com/wai818/mormot-learning/blob/master/15_接口.html This Delphi code snippet demonstrates how to declare an interface, `ICalculator`, which defines a contract for functionality without providing an implementation. It inherits from `IInvokable` and includes a GUID for unique identification. The interface declares a single abstract method, `Add`, for adding two integers, adhering to common Delphi interface conventions like 'I' prefixing and method-only definitions. ```Delphi type ICalculator = interface(IInvokable) ['{9A60C8ED-CEB2-4E09-87D4-4A16F496E5FE}'] /// add two signed 32-bit integers function Add(n1,n2: integer): integer; end; ``` -------------------------------- ### Delphi Simplified Stub and Mock Creation Source: https://github.com/wai818/mormot-learning/blob/master/15_接口.html After interfaces are registered, this snippet shows how `TInterfaceStub.Create` and `TInterfaceMock.Create` can be used directly with the interface name, simplifying the syntax by omitting `TypeInfo()`. ```Delphi TInterfaceStub.Create(ISmsSender,SmsSender); TInterfaceMock.Create(IUserRepository,UserRepository,self); ``` -------------------------------- ### Calculate Base Level and Perfect Table of Contents Hierarchy in JavaScript Source: https://github.com/wai818/mormot-learning/blob/master/23_非对称加密.html The `baseLevelOfToc` function determines the highest (smallest number) heading level present in the TOC data, serving as the starting point for hierarchy. `toPerfectToc` then adjusts the TOC structure by inserting 'empty' headers to ensure a strictly incremental level progression (e.g., h1 followed by h3 becomes h1, [EMPTY h2], h3), which is necessary for correct tree generation. ```JavaScript var baseLevelOfToc = function(p_toc) { var level = -1; for (i in p_toc) { if (level == -1) { level = p_toc[i].level; } else if (level > p_toc[i].level) { level = p_toc[i].level; } } if (level == -1) { level = 1; } return level; }; var toPerfectToc = function(p_toc, p_baseLevel) { var i; var curLevel = p_baseLevel - 1; var perfToc = []; for (i in p_toc) { var item = p_toc[i]; while (item.level > curLevel + 1) { curLevel += 1; var tmp = { level: curLevel, anchor: '', title: '[EMPTY]' }; perfToc.push(tmp); } perfToc.push(item); curLevel = item.level; } return perfToc; }; ``` -------------------------------- ### Responsive Layout and UI Component Styling with CSS Source: https://github.com/wai818/mormot-learning/blob/master/2_架构原理.html This snippet provides a comprehensive set of CSS rules for building responsive web interfaces. It includes a Bootstrap-like grid system with `col` and `row` classes, responsive breakpoints for different screen sizes (md, xl), utility classes for padding, display, and flexbox behavior, and specific styles for UI elements like a sticky table of contents, a floating action button, and a modal for image display with zoom animation. ```CSS /* STYLE_GLOBAL_PLACE_HOLDER */ *, *::before, *::after { box-sizing: border-box; } .container-fluid { width: 100%; padding-right: 15px; padding-left: 15px; margin-right: auto; margin-left: auto; } .col, .col-1, .col-10, .col-11, .col-12, .col-2, .col-3, .col-4, .col-5, .col-6, .col-7, .col-8, .col-9, .col-auto, .col-lg, .col-lg-1, .col-lg-10, .col-lg-11, .col-lg-12, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-lg-auto, .col-md, .col-md-1, .col-md-10, .col-md-11, .col-md-12, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-md-auto, .col-sm, .col-sm-1, .col-sm-10, .col-sm-11, .col-sm-12, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-sm-auto, .col-xl, .col-xl-1, .col-xl-10, .col-xl-11, .col-xl-12, .col-xl-2, .col-xl-3, .col-xl-4, .col-xl-5, .col-xl-6, .col-xl-7, .col-xl-8, .col-xl-9, .col-xl-auto { position: relative; width: 100%; min-height: 1px; padding-right: 15px; padding-left: 15px; } .col-12 { -webkit-box-flex: 0; -ms-flex: 0 0 100%; flex: 0 0 100%; max-width: 100%; } @media (min-width: 768px) { .col-md-3 { -webkit-box-flex: 0; -ms-flex: 0 0 25%; flex: 0 0 25%; max-width: 25%; } } @media (min-width: 768px) { .col-md-9 { -webkit-box-flex: 0; -ms-flex: 0 0 75%; flex: 0 0 75%; max-width: 75%; } } @media (min-width: 1200px) { .col-xl-2 { -webkit-box-flex: 0; -ms-flex: 0 0 16.666667%; flex: 0 0 16.666667%; max-width: 16.666667%; } } @media (min-width: 1200px) { .col-xl-10 { -webkit-box-flex: 0; -ms-flex: 0 0 83.333333%; flex: 0 0 83.333333%; max-width: 83.333333%; } } @media (min-width: 768px) { .pt-md-3, .py-md-3 { padding-top: 1rem!important; } } @media (min-width: 768px) { .pb-md-3, .py-md-3 { padding-bottom: 1rem!important; } } @media (min-width: 768px) { .pl-md-5, .px-md-5 { padding-left: 3rem!important; } } .d-none { display: none!important; } @media (min-width: 1200px) { .d-xl-block { display: block!important; } } @media (min-width: 768px) { .d-md-block { display: block!important; } } .bd-content { -webkit-box-ordinal-group: 1; -ms-flex-order: 0; order: 0; } .bd-toc { position: -webkit-sticky; position: sticky; top: 4rem; height: calc(100vh - 10rem); overflow-y: auto; } .bd-toc { -webkit-box-ordinal-group: 2; -ms-flex-order: 1; order: 1; padding-top: 1.5rem; padding-bottom: 1.5rem; font-size: .875rem; } .section-nav { padding-left: 0; } .section-nav ul { font-size: .875rem; list-style-type: none; } .section-nav li { font-size: .875rem; } .section-nav a { color: inherit !important; } .row { display: -webkit-box; display: -ms-flexbox; display: flex; -ms-flex-wrap: wrap; flex-wrap: wrap; margin-right: -15px; margin-left: -15px; } @media (min-width: 1200px) { .flex-xl-nowrap { flex-wrap: nowrap !important; } } #floating-button { width: 2.5rem; height: 2.5rem; border-radius: 50%; background: #00897B; position: fixed; top: .5rem; right: .5rem; cursor: pointer; box-shadow: 0px 2px 5px #666; } #floating-button .more { color: #F5F5F5; position: absolute; top: 0; display: block; bottom: 0; left: 0; right: 0; text-align: center; padding: 0; margin: 0; line-height: 2.5rem; font-size: 2rem; font-family: 'monospace'; font-weight: 300; } .hide-none { display: none !important; } .col-expand { -webkit-box-flex: 0; -ms-flex: 0 0 100% !important; flex: 0 0 100% !important; max-width: 100% !important; padding-right: 3rem !important; } .outline-bold { font-weight: bolder !important; } @media print { #floating-button { display: none !important; } } @keyframes flash { 0% { color: rgb(128, 203, 196); } 10% { color: rgb(0, 137, 123); } 40% { color: rgb(0, 137, 123); } 50% { color: rgb(128, 203, 196); } 60% { color: rgb(0, 137, 123); } 90% { color: rgb(0, 137, 123); } } .highlighted-anchor { animation: flash 1s; } div.mark-rect { background: transparent; border: 5px solid rgb(87, 104, 196); border-radius: 2px; position: absolute; } #vnote-footer { width: 100%; text-align: center; opacity: 0.2; margin-top: 3rem; } #vnote-footer p { font-size: 0.8rem; } #vnote-footer a { color: inherit !important; } x-eqs { display: flex; flex-direction: row; align-content: space-between; align-items: center; } x-eqs > x-eqn { width: 100%; margin-left: 3rem; } x-eqs > span { text-align: right; } .view-image, .view-svg { transition: 0.3s; } .modal-box { display: none; position: fixed; z-index: 1000; padding-top: 50px; left: 0px; top: 0px; width: 100%; height: 100%; overflow: hidden; background-color: rgba(68, 68, 68, 0.952941); } .modal-content { margin: auto; display: block; width: auto; height: auto; cursor: move; } .modal-content { animation-name: zoom; animation-duration: 0.6s; } @-webkit-keyframes zoom { 0% { transform: scale(0); } 100% { transform: scale(1); } } @keyframes zoom { 0% { transform: scale(0); } 100% { transform: scale(1); } } span.modal-close { position: absolute; z-index: 1000; top: 15px; right: 35px; color: rgb(218, 218, 218); font-size: 40px; font-weight: bold; transitio ``` -------------------------------- ### APIDOC: mORMot Mocking Framework Capabilities Overview Source: https://github.com/wai818/mormot-learning/blob/master/15_接口.html A comprehensive overview of the features provided by the mORMot mocking framework, detailing its capabilities for stubbing, mocking, and testing, including support for various argument matchers, return value handling, and performance considerations. ```APIDOC - Stubbing any method to return default values. - Defining stubbed behavior via a fluent interface using TInterfaceStub.Returns(), including simple definition of returned values for the entire method or subsequent parameter matchers. - Handling var, out method or function results, not just function results (unlike other Delphi implementations limited by TVirtualInterface), but all output values, including arrays of values. - Stubbed methods can run more complex processes using delegates or event callbacks defined by TInterfaceStub.Executes() rules, for the entire method or subsequent parameter matchers. - Stubbed methods can also raise exceptions defined by TInterfaceStub.Raises() rules, for the entire method or subsequent parameter matchers, if this is the behavior to test. - Clear distinction between mocks and stubs with two dedicated classes: TInterfaceStub and TInterfaceMock. - Mocks directly associated with mORMot's unified testing/test-driven classes. - Mocked methods can define triggering test case failures using TInterfaceMock.Fails(), including for the entire method or subsequent parameter matchers. - Choice of testing patterns: "expect-run-verify" or "run-verify" (aka "spy"), depending on testing needs. - Mocking methods or methods with parameter matching for validating effective execution counts or global execution tracing, where output counts can be compared with < <= = <> > >= operators, not just classic exact times and at least once verification. - Most common parameters and results can be defined as simple constant arrays in Delphi code, or via providing JSON arrays (e.g., for more complex record values). - Retrieving execution traces in an easy-to-read or write text format (instead of complex "fluent" interfaces, e.g., using When clauses). - Automatic release of TInterfaceStub TInterfaceMock TInterfaceMockSpy generated instances when interfaces are no longer needed, minimizing typed code and avoiding potential memory leaks. - Support for Delphi 6 to Delphi 10.3 Rio, as no generic-like syntactic sugar or RTTI.pas features are used. - Very good performance (faster Delphi mocking framework) due to very low overhead and reuse of mORMot's underlying interface-based service kernel with JSON serialization, not relying on slow and limited TVirtualInterface. ``` -------------------------------- ### Delphi Registering Service Interfaces for mORMot Source: https://github.com/wai818/mormot-learning/blob/master/15_接口.html This snippet demonstrates the recommended practice of registering service interfaces like `ISmsSender` and `IUserRepository` using `TInterfaceFactory.RegisterInterfaces`. This allows for simplified stub and mock creation without needing `TypeInfo()` later. ```Delphi unit MyServiceInterfaces; ... type ISmsSender = interface(IInvokable) ... IUserRepository = interface(IInvokable) ... initialization TInterfaceFactory.RegisterInterfaces( [TypeInfo(ISmsSender),TypeInfo(IUserRepository)]); end. ``` -------------------------------- ### Page Load Event Listener for TOC Initialization Source: https://github.com/wai818/mormot-learning/blob/master/11_客户端-服务端进程.html This event listener executes when the page finishes loading. It initializes the outline panel, fetches all header elements (h1-h6) from the `post-content` area, processes them into a structured table of contents using helper functions, and then renders the TOC into the `outline-content` element. If no headers are found, the outline panel is hidden. ```JavaScript window.addEventListener('load', function() { var outlinePanel = document.getElementById('outline-panel'); outlinePanel.style.display = 'initial'; var floatingContainer = document.getElementById('container-floating'); floatingContainer.style.display = 'initial'; var outlineContent = document.getElementById('outline-content'); var postContent = document.getElementById('post-content'); // Fetch the outline. var headers = postContent.querySelectorAll("h1, h2, h3, h4, h5, h6"); toc = []; for (var i = 0; i < headers.length; ++i) { var header = headers[i]; toc.push({ level: parseInt(header.tagName.substr(1)), anchor: header.id, title: escapeHtml(header.textContent) }); } if (toc.length == 0) { setOutlinePanelVisible(false); setVisible(floatingContainer, false); return; } var baseLevel = baseLevelOfToc(toc); var tocTree = tocToTree(toPerfectToc(toc, baseLevel), baseLevel); outlineContent.innerHTML = tocTree; setOutlinePanelVisible(true); setVisible(floatingContainer, true); }); ``` -------------------------------- ### JavaScript Document Load Handler for TOC Initialization Source: https://github.com/wai818/mormot-learning/blob/master/9_外部NoSQL数据库访问.html The main event listener that executes upon document load, responsible for fetching page headers, constructing the table of contents, and dynamically updating the UI to display the generated outline panel. ```JavaScript var toc = []; window.addEventListener('load', function() { var outlinePanel = document.getElementById('outline-panel'); outlinePanel.style.display = 'initial'; var floatingContainer = document.getElementById('container-floating'); floatingContainer.style.display = 'initial'; var outlineContent = document.getElementById('outline-content'); var postContent = document.getElementById('post-content'); var headers = postContent.querySelectorAll("h1, h2, h3, h4, h5, h6"); toc = []; for (var i = 0; i < headers.length; ++i) { var header = headers[i]; toc.push({ level: parseInt(header.tagName.substr(1)), anchor: header.id, title: escapeHtml(header.textContent) }); } if (toc.length == 0) { setOutlinePanelVisible(false); setVisible(floatingContainer, false); return; } var baseLevel = baseLevelOfToc(toc); var tocTree = tocToTree(toPerfectToc(toc, baseLevel), baseLevel); outlineContent.innerHTML = tocTree; setOutlinePanelVisible(true); setVisible(floatingContainer, true); }); ``` -------------------------------- ### Initialize Table of Contents and UI on Page Load in JavaScript Source: https://github.com/wai818/mormot-learning/blob/master/10_JSON RESTful客户端-服务端.html This event listener executes when the page finishes loading. It initializes the outline panel and floating container visibility, fetches all heading elements (h1-h6) from the post content, constructs a table of contents (TOC) array, normalizes it, converts it to an HTML tree, and then displays the outline panel if TOC entries exist. It includes a nested helper function for HTML escaping. ```JavaScript window.addEventListener('load', function() { var outlinePanel = document.getElementById('outline-panel'); outlinePanel.style.display = 'initial'; var floatingContainer = document.getElementById('container-floating'); floatingContainer.style.display = 'initial'; var outlineContent = document.getElementById('outline-content'); var postContent = document.getElementById('post-content'); // Escape @text to Html. var escapeHtml = function(text) { var map = { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }; return text.replace(/[&<>"']/g, function(m) { return map[m]; }); } // Fetch the outline. var headers = postContent.querySelectorAll("h1, h2, h3, h4, h5, h6"); toc = []; for (var i = 0; i < headers.length; ++i) { var header = headers[i]; toc.push({ level: parseInt(header.tagName.substr(1)), anchor: header.id, title: escapeHtml(header.textContent) }); } if (toc.length == 0) { setOutlinePanelVisible(false); setVisible(floatingContainer, false); return; } var baseLevel = baseLevelOfToc(toc); var tocTree = tocToTree(toPerfectToc(toc, baseLevel), baseLevel); outlineContent.innerHTML = tocTree; setOutlinePanelVisible(true); setVisible(floatingContainer, true); }); ``` -------------------------------- ### CSS Styles for UI Elements and Syntax Highlighting Source: https://github.com/wai818/mormot-learning/blob/master/9_外部NoSQL数据库访问.html This snippet contains comprehensive CSS rules for styling various HTML elements, including diagram containers, image alignment, captions, scrollbars, and a custom theme for `highlight.js` syntax highlighting. It defines colors, padding, margins, and other visual properties to ensure consistent UI presentation. ```CSS 0px; overflow-y: hidden; } div.flowchart-diagram { padding: 0px 5px; margin: 16px 0px; width: fit-content; overflow: hidden; } div.wavedrom-diagram { padding: 0px 5px; margin: 16px 0px; width: fit-content; overflow: hidden; } div.plantuml-diagram { padding: 5px 5px 0px; margin: 16px 0px; width: fit-content; overflow: hidden; } .img-package { text-align: center; } img.img-center { display: block; margin-left: auto; margin-right: auto; } span.img-caption { min-width: 20%; max-width: 80%; display: inline-block; padding: 10px; margin: 0px auto; border-bottom: 1px solid rgb(192, 192, 192); color: rgb(108, 108, 108); text-align: center; line-height: 1.5; } .emoji_zero, .emoji_one, .emoji_two, .emoji_three, .emoji_four, .emoji_five, .emoji_six, .emoji_seven, .emoji_eight, .emoji_nine { margin-left: 5px; margin-right: 8px; } div.preview-hint { opacity: 0.5; margin-top: 30%; margin-bottom: 30%; align-items: center; display: flex; flex-direction: column; justify-content: center; } table.hljs-ln tr { border: none; background-color: transparent; } table.hljs-ln tr td { border: none; background-color: transparent; } table.hljs-ln tr td.hljs-ln-numbers { user-select: none; text-align: center; color: rgb(170, 170, 170); border-right: 1px solid rgb(204, 204, 204); vertical-align: top; padding-right: 5px; white-space: nowrap; } table.hljs-ln tr td.hljs-ln-code { padding-left: 10px; } ::-webkit-scrollbar { background-color: rgb(234, 234, 234); width: 14px; height: 14px; border: none; } ::-webkit-scrollbar-corner { background-color: rgb(234, 234, 234); } ::-webkit-scrollbar-button { height: 14px; width: 14px; background-color: rgb(234, 234, 234); } ::-webkit-scrollbar-button:hover { background-color: rgb(208, 208, 208); } ::-webkit-scrollbar-button:active { background-color: rgb(178, 178, 178); } ::-webkit-scrollbar-track { background-color: rgb(234, 234, 234); } ::-webkit-scrollbar-thumb { border: none; background-color: rgb(218, 218, 218); } ::-webkit-scrollbar-thumb:hover { background-color: rgb(208, 208, 208); } ::-webkit-scrollbar-thumb:active { background-color: rgb(178, 178, 178); } ::-webkit-scrollbar-button:horizontal:increment { background-image: url('data:image/svg+xml;utf8, '); background-repeat: no-repeat; background-size: contain; } ::-webkit-scrollbar-button:horizontal:decrement { background-image: url('data:image/svg+xml;utf8, '); background-repeat: no-repeat; background-size: contain; } ::-webkit-scrollbar-button:vertical:increment { background-image: url('data:image/svg+xml;utf8, '); background-repeat: no-repeat; background-size: contain; } ::-webkit-scrollbar-button:vertical:decrement { background-image: url('data:image/svg+xml;utf8, '); background-repeat: no-repeat; background-size: contain; } ::selection { background: rgb(25, 118, 210); color: rgb(238, 238, 238); } .modal-box { background-color: rgba(234, 234, 234, 0.952941); } span.modal-close { color: rgb(102, 102, 102); } span.modal-close:hover, span.modal-close:focus { color: rgb(34, 34, 34); } .hljs { display: block; overflow-x: auto; padding: 0.5em; background: rgb(224, 224, 224); } .hljs, .hljs-subst { color: rgb(54, 54, 54); } .hljs-comment { color: rgb(118, 118, 118); } .hljs-keyword, .hljs-attribute, .hljs-selector-tag, .hljs-meta-keyword, .hljs-doctag, .hljs-name { color: rgb(0, 0, 238); } .hljs-type, .hljs-string, .hljs-number, .hljs-selector-id, .hljs-selector-class, .hljs-quote, .hljs-template-tag, .hljs-deletion { color: rgb(136, 0, 0); } .hljs-title, .hljs-section { color: rgb(136, 0, 0); font-weight: bold; } .hljs-regexp, .hljs-symbol, .hljs-variable, .hljs-template-variable, .hljs-link, .hljs-selector-attr, .hljs-selector-pseudo { color: rgb(188, 96, 96); } .hljs-literal { color: rgb(175, 0, 215); } .hljs-built_in, .hljs-bullet, .hljs-code, .hljs-addition { color: rgb(0, 135, 0); } .hljs-meta { color: rgb(31, 113, 153); } .hljs-meta-string { color: rgb(77, 153, 191); } .hljs-emphasis { font-style: italic; } .hljs-stron ``` -------------------------------- ### Initialize Dynamic Table of Contents on Window Load in JavaScript Source: https://github.com/wai818/mormot-learning/blob/master/21_安全.html This event listener executes when the window finishes loading. It initializes the outline panel and floating container, fetches all header elements (h1-h6) from the post content, constructs a Table of Contents (TOC) array, normalizes and converts it to an HTML tree, and then renders it into the outline panel. ```JavaScript window.addEventListener('load', function() { var outlinePanel = document.getElementById('outline-panel'); outlinePanel.style.display = 'initial'; var floatingContainer = document.getElementById('container-floating'); floatingContainer.style.display = 'initial'; var outlineContent = document.getElementById('outline-content'); var postContent = document.getElementById('post-content'); // Fetch the outline. var headers = postContent.querySelectorAll("h1, h2, h3, h4, h5, h6"); toc = []; for (var i = 0; i < headers.length; ++i) { var header = headers[i]; toc.push({ level: parseInt(header.tagName.substr(1)), anchor: header.id, title: escapeHtml(header.textContent) }); } if (toc.length == 0) { setOutlinePanelVisible(false); setVisible(floatingContainer, false); return; } var baseLevel = baseLevelOfToc(toc); var tocTree = tocToTree(toPerfectToc(toc, baseLevel), baseLevel); outlineContent.innerHTML = tocTree; setOutlinePanelVisible(true); setVisible(floatingContainer, true); }); ``` -------------------------------- ### Initialize and Render Dynamic Table of Contents (TOC) Source: https://github.com/wai818/mormot-learning/blob/master/7_数据库层.html This script initializes the dynamic table of contents (TOC) by querying all header elements (h1-h6) within the 'post-content' area. It then processes these headers to build a structured TOC, handles cases where no headers are found, and finally renders the TOC into the 'outline-content' element, making the floating container visible. ```JavaScript floatingContainer.style.display = 'initial'; var outlineContent = document.getElementById('outline-content'); var postContent = document.getElementById('post-content'); // Fetch the outline. var headers = postContent.querySelectorAll("h1, h2, h3, h4, h5, h6"); toc = []; for (var i = 0; i < headers.length; ++i) { var header = headers[i]; toc.push({ level: parseInt(header.tagName.substr(1)), anchor: header.id, title: escapeHtml(header.textContent) }); } if (toc.length == 0) { setOutlinePanelVisible(false); setVisible(floatingContainer, false); return; } var baseLevel = baseLevelOfToc(toc); var tocTree = tocToTree(toPerfectToc(toc, baseLevel), baseLevel); outlineContent.innerHTML = tocTree; setOutlinePanelVisible(true); setVisible(floatingContainer, true); }); ``` -------------------------------- ### Delphi Running a Test with Stubbed and Mocked Dependencies Source: https://github.com/wai818/mormot-learning/blob/master/15_接口.html This snippet shows how to instantiate the `TLoginController` with the previously defined stubbed `SmsSender` and mocked `UserRepository`. It then calls the `ForgotMyPassword` method, allowing the test to run against the fake implementations. ```Delphi with TLoginController.Create(UserRepository,SmsSender) do try ForgotMyPassword('toto'); finally Free; end; ``` -------------------------------- ### JavaScript DOM Initialization on Page Load Source: https://github.com/wai818/mormot-learning/blob/master/7_数据库层.html This snippet demonstrates how to execute JavaScript code once the entire page has loaded. It specifically targets and initializes the display style of an 'outline-panel' element and references a 'container-floating' element, ensuring UI components are correctly set up after the DOM is ready. ```JavaScript window.addEventListener('load', function() { var outlinePanel = document.getElementById('outline-panel'); outlinePanel.style.display = 'initial'; var floatingContainer = document.getElementById('container-floating'); }); ``` -------------------------------- ### JavaScript Page Load Initialization for TOC Source: https://github.com/wai818/mormot-learning/blob/master/6_日常的ORM.html This event listener executes when the page finishes loading. It initializes the outline panel and floating container visibility, fetches all heading elements (`h1`-`h6`) from the post content, constructs the Table of Contents (TOC) data, and then renders it into the outline panel, setting its initial visibility. ```JavaScript window.addEventListener('load', function() { var outlinePanel = document.getElementById('outline-panel'); outlinePanel.style.display = 'initial'; var floatingContainer = document.getElementById('container-floating'); floatingContainer.style.display = 'initial'; var outlineContent = document.getElementById('outline-content'); var postContent = document.getElementById('post-content'); var headers = postContent.querySelectorAll("h1, h2, h3, h4, h5, h6"); toc = []; for (var i = 0; i < headers.length; ++i) { var header = headers[i]; toc.push({ level: parseInt(header.tagName.substr(1)), anchor: header.id, title: escapeHtml(header.textContent) }); } if (toc.length == 0) { setOutlinePanelVisible(false); setVisible(floatingContainer, false); return; } var baseLevel = baseLevelOfToc(toc); var tocTree = tocToTree(toPerfectToc(toc, baseLevel), baseLevel); outlineContent.innerHTML = tocTree; setOutlinePanelVisible(true); setVisible(floatingContainer, true); }); ```