VisualEditor

repository·master·Indexed 42 days ago

https://github.com/wikimedia/visualeditor

A JavaScript-based, stand-alone contentEditable rich Web editor designed for editing HTML documents directly in a web browser.

Tokens
8.4K
Snippets
32
Records
51
Agent score
47%

What's inside VisualEditor

  1. Overview of jsdifflib

    master

    jsdifflib is a JavaScript library designed for visual diffing. It provides two main capabilities:

    1. Algorithmic Diffing: A partial reimplementation of Python's difflib module, specifically the SequenceMatcher class. This allows you to calculate differences between sequences (like lines of text) in the browser.
    2. Visual Diff View: A generator that creates a visual representation of diff data, supporting both side-by-side and inline formatting (similar to the Trac project).

    The library is standalone and does not require jQuery or any other external JavaScript libraries.

  2. Use unicodejs for text segmentation

    master

    UnicodeJS provides methods for detecting boundaries in text according to the Unicode Text Segmentation specification. Specifically, it supports:

    • Word Boundaries: Identifying where words start and end.
    • Grapheme Cluster Boundaries: Identifying boundaries between user-perceived characters (grapheme clusters).

    For full API details, refer to the official documentation at https://doc.wikimedia.org/unicodejs/master/.

  3. What is rangefix and when should I use it?

    master

    rangefix is a workaround for known bugs in various browser implementations of Range.prototype.getClientRects and Range.prototype.getBoundingClientRect.

    Use it if you need to support:

    • Chrome <= 54: Selections spanning multiple nodes return rectangles for all parents of the endContainer.
    • Chrome 55: Images wrapped in a node return no rectangle when selected across.
    • Safari: Similar to Chrome <= 54, triggered near block node edges or programmatically near inline nodes.
    • Firefox: Similar to Chrome <= 54, triggered near inline node edges.
    • IE <= 10: Incorrect rectangle scaling when using browser zoom.
    • Chrome/Firefox: Bounding rectangles failing to cover all individual rectangles when a selection spans two lines (including spaces or text on the next line).

    Note: There are no known issues in Chrome >= 56, Edge, and IE >= 11. In these browsers, rangefix will fall through to native behavior.

  4. How to load OOUI library files

    master

    While the distribution directory contains many files, a standard implementation typically only requires three main components:

    1. oojs-ui.js: The full library.
    2. Theme Styles: Either oojs-ui-wikimediaui.css or oojs-ui-apex.css.
    3. Theme Code: Either oojs-ui-wikimediaui.js or oojs-ui-apex.js.

    Additional assets:

    • Icons: You can load icon packs using oojs-ui-wikimediaui-icons-*.css or oojs-ui-apex-icons-*.css.
    • RTL Support: Every CSS file has a right-to-left (RTL) version available for pages using RTL languages if your environment does not automatically flip them.
  5. How to use Python for server-side diffing with jsdifflib

    master

    For very large files (e.g., > 100K lines), it is recommended to perform the diff calculation on a Python server to avoid browser performance issues. Because jsdifflib's API matches Python's difflib.SequenceMatcher exactly, you can compute the opcodes in Python and send them to the client.

    Server-side (Python) requirement: Your backend should use Python's difflib.SequenceMatcher to generate opcodes and return a JSON object containing:

    • baseTextLines: The original lines.
    • newTextLines: The new lines.
    • opcodes: The result of SequenceMatcher(a, b).get_opcodes().
    • baseTextName: Title for the base text.
    • newTextName: Title for the new text.

    Client-side (JavaScript) requirement: Once the JSON data is received, pass it directly into diffview.buildView().

    // Example Python backend logic (conceptual)
    @jsonify
    def diff (self, baseText, newText, baseTextName="Base Text", newTextName="New Text"):
        opcodes = SequenceMatcher(isjunk, baseText, newText).get_opcodes()
        return dict(baseTextLines=baseText, newTextLines=newText, opcodes=opcodes,
                    baseTextName=baseTextName, newTextName=newTextName)
    
    // Example Client-side consumption
    // Assuming 'data' is the JSON response from the server
    // data = { baseTextLines: [...], newTextLines: [...], opcodes: [...], ... }
    // 
    // $(
  6. Message File Formats for jQuery.i18n

    master

    jQuery.i18n supports two primary JSON-based localization formats:

    Create a folder (e.g., i18n/) containing one JSON file per locale named after its ISO 639 language code (e.g., en.json, fr.json). This is best for scalability and collaboration.

    2. Single message file

    For smaller applications, use one JSON file where top-level keys are language codes. Values can be either an object of messages or a string pointing to an external file path.

    Metadata and Keys

    • @metadata: A special top-level key used to store non-message data like authors, last-updated, or locale.
    • Message Keys: It is recommended to use a namespace prefix (e.g., appname-title) and use lowercase words separated by hyphens.
    // Example: Single file format with external path reference
    {
    	"@metadata": { "locale": "en" },
    	"en": {
    		"appname-title": "Example Application"
    	},
    	"ml": "path/to/ml.json"
    }
  7. How treeDiffer works and its transaction format

    master

    treeDiffer is a JavaScript library that calculates the minimum set of transactions required to transform one tree structure into another. It implements an algorithm based on tree diffing that identifies changes between two trees.

    Nodes in both trees must be labeled in post order, starting from 0. The output is a list of transactions, where each transaction is represented as a pair [nodeToRemove, nodeToInsert].

    Transaction types:

    • [nodeId, null]: The node was removed from the first tree.
    • [null, nodeId]: The node was inserted into the second tree.
    • [nodeId1, nodeId2]: The node from the first tree was changed into the node in the second tree.
  8. Diffing text using JavaScript

    master

    To perform a diff entirely in the browser, follow these steps:

    1. Convert your input strings into arrays of lines using difflib.stringAsLines().
    2. Create a new difflib.SequenceMatcher instance passing the base and new line arrays.
    3. Call .get_opcodes() on the matcher instance to retrieve a list of 3-tuples describing the changes.
    4. Use diffview.buildView() to generate the visual DOM elements for the diff.

    diffview.buildView() accepts a configuration object with the following keys:

    • baseTextLines: Array of lines from the original text.
    • newTextLines: Array of lines from the modified text.
    • opcodes: The list of opcodes generated by SequenceMatcher.
    • baseTextName: String for the display title of the base text.
    • newTextName: String for the display title of the new text.
    • contextSize: Number of lines of context to show around changes.
    • viewType: Integer determining the view mode (e.g., 1 for inline, 0 for side-by-side).
    function diffUsingJS() {
        // 1. Prepare lines
        var base = difflib.stringAsLines($("baseText").value);
        var newtxt = difflib.stringAsLines($("newText").value);
    
        // 2. Create SequenceMatcher
        var sm = new difflib.SequenceMatcher(base, newtxt);
    
        // 3. Get opcodes
        var opcodes = sm.get_opcodes();
    
        // 4. Build and append the view
        var diffoutputdiv = $("diffoutput");
        diffoutputdiv.appendChild(diffview.buildView({
            baseTextLines: base,
            newTextLines: newtxt,
            opcodes: opcodes,
            baseTextName: "Base Text",
            newTextName: "New Text",
            contextSize: null,
            viewType: 1 // inline
        }));
    }