«ميدياويكي:Common.js»: الفرق بين المراجعتين

من Sudan Memory
اذهب إلى: تصفح، ابحث
سطر ١: سطر ١:
 
/* الجافاسكريبت الموضوع هنا سيتم تحميله لكل المستخدمين مع كل تحميل للصفحة. */
 
/* الجافاسكريبت الموضوع هنا سيتم تحميله لكل المستخدمين مع كل تحميل للصفحة. */
  
function splitTrailingText(input) {
+
// =============================================================================
    var regex = /^(.*?[\u0620-\u064Aa-zA-Z])([^\u0620-\u064Aa-zA-Z]*)$/;
+
// Formate a poem
     var matches = input.match(regex);
+
// 2024-02-27: Created by Abdalla G. M. Ahmed
      
+
// =============================================================================
     if (matches && matches.length > 1) {
+
 
        var alphabeticPart = matches[1];
+
// -----------------------------------------------------------------------------
        var nonAlphabeticPart = matches[2];
+
// Measure displayed width of an HTML text
        return { alphabeticPart: alphabeticPart, nonAlphabeticPart: nonAlphabeticPart };
+
// -----------------------------------------------------------------------------
     }
+
 
     return { alphabeticPart: input, nonAlphabeticPart: '' };
+
function measureTextWidth(text, font) {
 +
     var tmpSpan = document.createElement("span");
 +
     tmpSpan.style.font = font;                                                  // Apply the font style
 +
     tmpSpan.style.position = "absolute";
 +
    tmpSpan.style.visibility = "hidden";
 +
    tmpSpan.style.whiteSpace = "nowrap";
 +
    tmpSpan.innerHTML = text;
 +
 
 +
     document.body.appendChild(tmpSpan);
 +
    var textWidth = tmpSpan.offsetWidth;
 +
    document.body.removeChild(tmpSpan);
 +
 
 +
     return textWidth;
 
}
 
}
  
function parsePoem(text, vWidth) {
+
// -----------------------------------------------------------------------------
     var lines = text.split('\n');
+
// Retrieve font specs of an element
     var formattedLines = lines.map(function(line) {
+
// -----------------------------------------------------------------------------
        //if (line.trim() === "") {
+
 
            // Replace empty lines with a line break
+
function getFontStyle(node) {
            //return '<br>';
+
     var computedStyle = window.getComputedStyle(node);
        //}
+
     var fontSize = computedStyle.fontSize;
        //else
+
    var fontFamily = computedStyle.fontFamily;
        if (line.startsWith(' ')) { // Check for lines starting with two or more spaces
+
    var fontWeight = computedStyle.fontWeight;
            var result = splitTrailingText(line.trim());
+
    var fontStyle = computedStyle.fontStyle;
            var alphabeticPart = result.alphabeticPart;
+
    var fontVariant = computedStyle.fontVariant;
            var nonAlphabeticPart = result.nonAlphabeticPart;
+
    return (
            return '<p class="vTail"><span class="vTail" style="width:' + vWidth + 'px">' + alphabeticPart + '</span><span class="vTrailer">' + nonAlphabeticPart + '</span></p>';
+
        fontStyle + " " + fontVariant + " " +
         } else if (line.startsWith('--') && line.endsWith('--')) { // Check for lines delimited with '--'
+
        fontWeight + " " + fontSize + " " + fontFamily
            return '<p class="vMid" style="width:' + vWidth + 'px">' + line.substring(2, line.length - 2).trim() + '</p>';
+
    );
        } else {
+
}
             return '<p class="vHead" style="width:' + (0.9 * vWidth) + 'px">' + line.trim() + '</p>'; // Default to a regular paragraph for other lines
+
 
 +
// -----------------------------------------------------------------------------
 +
// Trim empty leading and trailing entries of an array
 +
// -----------------------------------------------------------------------------
 +
 
 +
function arrayTrim(arr) {
 +
    var result = arr.slice();                                                  // Clone the array to avoid modifying the original array
 +
    while (result.length > 0 && !result[0]) { result.shift(); }                // Remove empty elements from the beginning
 +
    while (result.length > 0 && !result[result.length - 1]) { result.pop(); }  // Remove empty elements from the end
 +
    return result;
 +
}
 +
 
 +
// -----------------------------------------------------------------------------
 +
// Format contents of a container (e.g., div) as a poem
 +
// -----------------------------------------------------------------------------
 +
 
 +
function poemFormat(poem) {
 +
    var bWidth = parseFloat(poem.getAttribute('data-bWidth') || 0);            // Overall with of beit
 +
    var bGap = parseFloat(poem.getAttribute('data-bGap') || 50);
 +
    var pWidth = [0, 0, 0, 0, 0];                                               // Widths of part for different number of parts, index 0 is used for centered verses
 +
    var nGaps  = [2, 0, 1, 2, 3];                                               // Number of gaps for different number of parts, initially assuming no leading gaps
 +
    var fontStyle = getFontStyle(poem);
 +
    var lines = (
 +
        poem
 +
        .innerHTML                                                              // We get the HTML to retain some tags like <a,i,b>
 +
        .replace(/\s*(<p[^>]*>|<div[^>]*>|<pre[^>]*>)/gi, '')                  // Remove whitespace before opening container tags and the tags
 +
        .replace(/<\/p>|<\/div>|<\/pre>/gi, '')                                // Remove closing tags
 +
         .split('\n')                                                           // Break into lines, assuming one beit per line
 +
    );
 +
    lines = arrayTrim(lines);                                                  // Remove leading and trailing empty lines so that the enclosing <div> tag may be placed in separate lines
 +
    var formattedLines = [];
 +
    var tagPlaceholder = '<a><i></i></a>';                                      // Unlikely to be present and does not affect text size
 +
    var tags = [];                                                              // To store extracted tags
 +
    for (var i = 0; i < lines.length; i++) {
 +
        var line = lines[i];
 +
        var leadingSpace = (
 +
            /^ {2,}/.test(line) ?                                              // Starts with two or more spaces?
 +
             '<span class="gap" style="width:'+bGap+'px">  </span>' :            // Will be placed at the being
 +
            ''                                                                  // Default to none
 +
        );
 +
        line = line.trim();                                                    // Remove leading and trailing spaces
 +
        if (line === "") {                                              // Empty line
 +
            formattedLines.push('<br>');                                       // is replaced by a line break
 +
            continue;                                                          // Done with this line
 
         }
 
         }
 +
        if (/^!/.test(line)) {                                          // A line starting with an exclamation mark is a comment
 +
            formattedLines.push(
 +
                '<p class="bComment" style="width:%cWidth%px">'                // "cWidth" is a placeholder until line widths are computed
 +
                + line.substring(1) +                                          // Remove the exclamation mark
 +
                '</p>'
 +
            );
 +
            continue;                                                          // Done with this line
 +
        }
 +
        if (line.startsWith('.') && line.endsWith('.')) {                      // Lines delimited by dots are centered.
 +
            line = line.substring(1, line.length - 1).trim();                  // Remove delimiters and any white space
 +
            pWidth[0] = Math.max(pWidth[0], measureTextWidth(line));
 +
            formattedLines.push(
 +
                '<p class="bMid" style="width:%bWidth%px">' + line + '</p>'
 +
            );
 +
            continue;                                                          // Done with this line
 +
        }
 +
        // ---------------------------------------------------------------------
 +
        // From here we assume a regular classic column poem
 +
        // ---------------------------------------------------------------------
 +
        // ---------------------------------------------------------------------
 +
        // Distribute tags over words so that they can be split into parts,
 +
        // then save tags and replace them with no-space placeholders
 +
        // ---------------------------------------------------------------------
 +
        line = line.replace(
 +
            /(<([abi]+)(?:\s[^>]*)?>)(.*?)<\/\2>/gi,                            // Match the <a/i/b> tags and capture parameters into positional variables
 +
            function(match, openingTag, tagName, content) {                    // Compute replacements based on captured parameters
 +
                return content                                                  // Content inside tag
 +
                .split(/(\s+)/)                                                // Split at white space and include white spaces in the list
 +
                .map(function(item) {
 +
                    if (/\S/.test(item)) {                                      // If an item is non-white space
 +
                        tags.push(openingTag, '</' + tagName + '>');            // Save opening and closing tags
 +
                        item = tagPlaceholder + item + tagPlaceholder;          // Enclose text item in a dummy tag placeholder
 +
                    }
 +
                    return item;                                                // Whitespace is returned as is
 +
                }).join('');                                                    // Join all items back together
 +
            }
 +
        );
 +
        // ---------------------------------------------------------
 +
        // Extract trailing symbols to align at "قافية"
 +
        // ---------------------------------------------------------
 +
        var trailingSymbols = '';                                              // Default to none
 +
        line = line.replace(
 +
            /^(.*?[\u0620-\u064Aa-zA-Z])([^\u0620-\u064Aa-zA-Z]*)$/,            // Match trailing non-letter symbols and capture parameters
 +
            function(match, alphabeticPart, nonAlphabeticPart) {                // A function to handle parameters
 +
                if (match.endsWith(tagPlaceholder)) return match;              // Too complex to handle, may consider later
 +
                trailingSymbols = (                                            // Extract trailing symbols, if any
 +
                    '<span class="bTrailingSymbols">'                          // Enclose in a span element to enable separate formatting, if desirable
 +
                    + nonAlphabeticPart +
 +
                    '</span>'
 +
                );
 +
                return alphabeticPart;                                          // Return alphabetic part to replace the original line
 +
            }
 +
        );
 +
        // ---------------------------------------------------------------------
 +
        // Split parts
 +
        // ---------------------------------------------------------------------
 +
        var nParts = 0;                                                        // Number of parts
 +
        var partWidth = 0;                                                      // Maximum part length
 +
        line = (
 +
            line
 +
            .split(/(\s{2,})/)                                                  // Split at two or more spaces and include white spaces in the list
 +
            .map(function(item) {
 +
                if (/\S/.test(item)) {                                          // An item containing non-space contents is treated as a part
 +
                    nParts++;                                                  // Increment number of parts to count this one
 +
                    // ---------------------------------------------------------
 +
                    // Enclose words in spans to enable justification
 +
                    // ---------------------------------------------------------
 +
                    item = (
 +
                        item
 +
                        .split(/(\s+)/)                                        // Split at white space and include white spaces in the list
 +
                        .map(function(item) {
 +
                            if (
 +
                                /\S/.test(item)
 +
                                && !item.startsWith(tagPlaceholder)
 +
                            ) {                                                // If an item is non-white space and not already in a tag
 +
                                return '<span>' + item + '</span>';            // Enclose in a span to enable justification
 +
                            }
 +
                            return item;                                        // Return whitespace and tagged items as is
 +
                        })
 +
                        .join('')                                              // Join all items back together
 +
                    );
 +
                    // ---------------------------------------------------------
 +
                    partWidth = Math.max(
 +
                        partWidth, measureTextWidth(item, fontStyle)            // Update longest part length
 +
                    );
 +
                    return (
 +
                        '<span class="vJustified" style="width:%pWidth%px">'
 +
                        + item +
 +
                        '</span>'
 +
                    );
 +
                }
 +
                else {                                                          // White space separating parts
 +
                    return '<span class="gap">  </span>';                      // Enclose in a span, typically stylized to preserve spaces
 +
                }
 +
            })
 +
            .join('')                                                          // Join all items back together
 +
            .replace(/%pWidth%/g, '%pWidth' + nParts + '%')                    // The number of parts is known now
 +
        );
 +
        pWidth[nParts] = Math.max(pWidth[nParts], partWidth);
 +
        formattedLines.push(
 +
            '<p class="beit">'
 +
            + leadingSpace
 +
            + '<span class="vJustified" style="width:%bWidth%px">'
 +
            + line
 +
            + '</span>'
 +
            + trailingSymbols
 +
            + '</p>'
 +
        );
 +
    }
 +
    for (var i = 0; i < pWidth.length; i++) {
 +
        var bWidth_i = pWidth[i] ? pWidth[i] * i + nGaps[i] * bGap : 0;        // Width to accommodate this number/width of parts
 +
        bWidth = Math.max(bWidth, bWidth_i);                                    // Accommodate the widest
 +
    }
 +
    pWidth = pWidth.map(function(w, i) {
 +
        return (bWidth - nGaps[i] * bGap) / (i ? i : 1);
 
     });
 
     });
     return formattedLines.join('');
+
    var tagIndex = 0;                                                          // To track the current tag being replaced
 +
     return (
 +
        formattedLines
 +
        .join('')                                                              // Concatenate
 +
        .replace(new RegExp(tagPlaceholder, "g"), function() {                  // Restore saved tags
 +
            return tags[tagIndex++];
 +
        })
 +
        .replace(/%pWidth(\d+)%/g, function(match, i) {                        // Replace computed part widths
 +
            return pWidth[i].toFixed(1);
 +
        })
 +
        .replace(/%bWidth%/g, bWidth)                                          // Replace computed overall beit width
 +
        .replace(/%cWidth%/g, (0.9 * bWidth).toFixed(1))                        // Replace width of comments
 +
    );
 
}
 
}
  
 
$(function () {
 
$(function () {
     var poems = document.querySelectorAll('.poem');                        // Find all div elements with the class 'poem'
+
     document.querySelectorAll('.abyat').forEach(function(poem) {
    poems.forEach(function(poem) {                                         // Loop through each poem element and format it
+
         poem.innerHTML = poemFormat(poem);
        var vWidth = poem.getAttribute('data-vWidth') || 350;              // Verse width, default is for quads
+
         poem.innerHTML = parsePoem(poem.innerText, vWidth);
+
        poem.classList.remove('poem');
+
 
     });
 
     });
 +
 +
    document.querySelectorAll('.abyat').forEach(function(poem) {
 +
        poemFormat(poem);
 +
    });
 +
  
 
     var toggler = document.getElementsByClassName("treeBranch");
 
     var toggler = document.getElementsByClassName("treeBranch");

مراجعة ١٢:٢٤، ٢٧ فبراير ٢٠٢٤

/* الجافاسكريبت الموضوع هنا سيتم تحميله لكل المستخدمين مع كل تحميل للصفحة. */
 
// =============================================================================
// Formate a poem
// 2024-02-27: Created by Abdalla G. M. Ahmed
// =============================================================================
 
// -----------------------------------------------------------------------------
// Measure displayed width of an HTML text
// -----------------------------------------------------------------------------
 
function measureTextWidth(text, font) {
    var tmpSpan = document.createElement("span");
    tmpSpan.style.font = font;                                                  // Apply the font style
    tmpSpan.style.position = "absolute";
    tmpSpan.style.visibility = "hidden";
    tmpSpan.style.whiteSpace = "nowrap";
    tmpSpan.innerHTML = text;
 
    document.body.appendChild(tmpSpan);
    var textWidth = tmpSpan.offsetWidth;
    document.body.removeChild(tmpSpan);
 
    return textWidth;
}
 
// -----------------------------------------------------------------------------
// Retrieve font specs of an element
// -----------------------------------------------------------------------------
 
function getFontStyle(node) {
    var computedStyle = window.getComputedStyle(node);
    var fontSize = computedStyle.fontSize;
    var fontFamily = computedStyle.fontFamily;
    var fontWeight = computedStyle.fontWeight;
    var fontStyle = computedStyle.fontStyle;
    var fontVariant = computedStyle.fontVariant;
    return (
        fontStyle + " " + fontVariant + " " +
        fontWeight + " " + fontSize + " " + fontFamily
    );
}
 
// -----------------------------------------------------------------------------
// Trim empty leading and trailing entries of an array
// -----------------------------------------------------------------------------
 
function arrayTrim(arr) {
    var result = arr.slice();                                                   // Clone the array to avoid modifying the original array
    while (result.length > 0 && !result[0]) { result.shift(); }                 // Remove empty elements from the beginning
    while (result.length > 0 && !result[result.length - 1]) { result.pop(); }   // Remove empty elements from the end
    return result;
}
 
// -----------------------------------------------------------------------------
// Format contents of a container (e.g., div) as a poem
// -----------------------------------------------------------------------------
 
function poemFormat(poem) {
    var bWidth = parseFloat(poem.getAttribute('data-bWidth') || 0);             // Overall with of beit
    var bGap = parseFloat(poem.getAttribute('data-bGap') || 50);
    var pWidth = [0, 0, 0, 0, 0];                                               // Widths of part for different number of parts, index 0 is used for centered verses
    var nGaps  = [2, 0, 1, 2, 3];                                               // Number of gaps for different number of parts, initially assuming no leading gaps
    var fontStyle = getFontStyle(poem);
    var lines = (
        poem
        .innerHTML                                                              // We get the HTML to retain some tags like <a,i,b>
        .replace(/\s*(<p[^>]*>|<div[^>]*>|<pre[^>]*>)/gi, '')                   // Remove whitespace before opening container tags and the tags
        .replace(/<\/p>|<\/div>|<\/pre>/gi, '')                                 // Remove closing tags
        .split('\n')                                                            // Break into lines, assuming one beit per line
    );
    lines = arrayTrim(lines);                                                   // Remove leading and trailing empty lines so that the enclosing <div> tag may be placed in separate lines
    var formattedLines = [];
    var tagPlaceholder = '<a><i></i></a>';                                      // Unlikely to be present and does not affect text size
    var tags = [];                                                              // To store extracted tags
    for (var i = 0; i < lines.length; i++) {
        var line = lines[i];
        var leadingSpace = (
            /^ {2,}/.test(line) ?                                               // Starts with two or more spaces?
            '<span class="gap" style="width:'+bGap+'px">  </span>' :            // Will be placed at the being
            ''                                                                  // Default to none
        );
        line = line.trim();                                                     // Remove leading and trailing spaces
        if (line === "") {                                               // Empty line
            formattedLines.push('<br>');                                        // is replaced by a line break
            continue;                                                           // Done with this line
        }
        if (/^!/.test(line)) {                                           // A line starting with an exclamation mark is a comment
            formattedLines.push(
                '<p class="bComment" style="width:%cWidth%px">'                 // "cWidth" is a placeholder until line widths are computed
                + line.substring(1) +                                           // Remove the exclamation mark
                '</p>'
            );
            continue;                                                           // Done with this line
        }
        if (line.startsWith('.') && line.endsWith('.')) {                       // Lines delimited by dots are centered.
            line = line.substring(1, line.length - 1).trim();                   // Remove delimiters and any white space
            pWidth[0] = Math.max(pWidth[0], measureTextWidth(line));
            formattedLines.push(
                '<p class="bMid" style="width:%bWidth%px">' + line + '</p>'
            );
            continue;                                                           // Done with this line
        }
        // ---------------------------------------------------------------------
        // From here we assume a regular classic column poem
        // ---------------------------------------------------------------------
        // ---------------------------------------------------------------------
        // Distribute tags over words so that they can be split into parts,
        // then save tags and replace them with no-space placeholders
        // ---------------------------------------------------------------------
        line = line.replace(
            /(<([abi]+)(?:\s[^>]*)?>)(.*?)<\/\2>/gi,                            // Match the <a/i/b> tags and capture parameters into positional variables
            function(match, openingTag, tagName, content) {                     // Compute replacements based on captured parameters
                return content                                                  // Content inside tag
                .split(/(\s+)/)                                                 // Split at white space and include white spaces in the list
                .map(function(item) {
                    if (/\S/.test(item)) {                                      // If an item is non-white space
                        tags.push(openingTag, '</' + tagName + '>');            // Save opening and closing tags
                        item = tagPlaceholder + item + tagPlaceholder;          // Enclose text item in a dummy tag placeholder
                    }
                    return item;                                                // Whitespace is returned as is
                }).join('');                                                    // Join all items back together
            }
        );
        // ---------------------------------------------------------
        // Extract trailing symbols to align at "قافية"
        // ---------------------------------------------------------
        var trailingSymbols = '';                                               // Default to none
        line = line.replace(
            /^(.*?[\u0620-\u064Aa-zA-Z])([^\u0620-\u064Aa-zA-Z]*)$/,            // Match trailing non-letter symbols and capture parameters
            function(match, alphabeticPart, nonAlphabeticPart) {                // A function to handle parameters
                if (match.endsWith(tagPlaceholder)) return match;               // Too complex to handle, may consider later
                trailingSymbols = (                                             // Extract trailing symbols, if any
                    '<span class="bTrailingSymbols">'                           // Enclose in a span element to enable separate formatting, if desirable
                    + nonAlphabeticPart +
                    '</span>'
                );
                return alphabeticPart;                                          // Return alphabetic part to replace the original line
            }
        );
        // ---------------------------------------------------------------------
        // Split parts
        // ---------------------------------------------------------------------
        var nParts = 0;                                                         // Number of parts
        var partWidth = 0;                                                      // Maximum part length
        line = (
            line
            .split(/(\s{2,})/)                                                  // Split at two or more spaces and include white spaces in the list
            .map(function(item) {
                if (/\S/.test(item)) {                                          // An item containing non-space contents is treated as a part
                    nParts++;                                                   // Increment number of parts to count this one
                    // ---------------------------------------------------------
                    // Enclose words in spans to enable justification
                    // ---------------------------------------------------------
                    item = (
                        item
                        .split(/(\s+)/)                                         // Split at white space and include white spaces in the list
                        .map(function(item) {
                            if (
                                /\S/.test(item)
                                && !item.startsWith(tagPlaceholder)
                            ) {                                                 // If an item is non-white space and not already in a tag
                                return '<span>' + item + '</span>';             // Enclose in a span to enable justification
                            }
                            return item;                                        // Return whitespace and tagged items as is
                        })
                        .join('')                                               // Join all items back together
                    );
                    // ---------------------------------------------------------
                    partWidth = Math.max(
                        partWidth, measureTextWidth(item, fontStyle)            // Update longest part length
                    );
                    return (
                        '<span class="vJustified" style="width:%pWidth%px">'
                        + item +
                        '</span>'
                    );
                }
                else {                                                          // White space separating parts
                    return '<span class="gap">  </span>';                       // Enclose in a span, typically stylized to preserve spaces
                }
            })
            .join('')                                                           // Join all items back together
            .replace(/%pWidth%/g, '%pWidth' + nParts + '%')                     // The number of parts is known now
        );
        pWidth[nParts] = Math.max(pWidth[nParts], partWidth);
        formattedLines.push(
            '<p class="beit">'
            + leadingSpace
            + '<span class="vJustified" style="width:%bWidth%px">'
            + line
            + '</span>'
            + trailingSymbols
            + '</p>'
        );
    }
    for (var i = 0; i < pWidth.length; i++) {
        var bWidth_i = pWidth[i] ? pWidth[i] * i + nGaps[i] * bGap : 0;         // Width to accommodate this number/width of parts
        bWidth = Math.max(bWidth, bWidth_i);                                    // Accommodate the widest
    }
    pWidth = pWidth.map(function(w, i) {
        return (bWidth - nGaps[i] * bGap) / (i ? i : 1);
    });
    var tagIndex = 0;                                                           // To track the current tag being replaced
    return (
        formattedLines
        .join('')                                                               // Concatenate
        .replace(new RegExp(tagPlaceholder, "g"), function() {                  // Restore saved tags
            return tags[tagIndex++];
        })
        .replace(/%pWidth(\d+)%/g, function(match, i) {                         // Replace computed part widths
            return pWidth[i].toFixed(1);
        })
        .replace(/%bWidth%/g, bWidth)                                           // Replace computed overall beit width
        .replace(/%cWidth%/g, (0.9 * bWidth).toFixed(1))                        // Replace width of comments
    );
}
 
$(function () {
    document.querySelectorAll('.abyat').forEach(function(poem) {
        poem.innerHTML = poemFormat(poem);
    });
 
    document.querySelectorAll('.abyat').forEach(function(poem) {
        poemFormat(poem);
    });
 
 
    var toggler = document.getElementsByClassName("treeBranch");
    var i;
 
    for (i = 0; i < toggler.length; i++) {
        toggler[i].addEventListener("click", function() {
            this.parentElement.querySelector(".treeBranch-nested").classList.toggle("treeBranch-active");
            this.classList.toggle("treeBranch-down");
        });
    }
}());