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

من Sudan Memory
اذهب إلى: تصفح، ابحث
 
(٢٨ مراجعات متوسطة بواسطة نفس المستخدم غير معروضة)
سطر ١: سطر ١:
 
/* الجافاسكريبت الموضوع هنا سيتم تحميله لكل المستخدمين مع كل تحميل للصفحة. */
 
/* الجافاسكريبت الموضوع هنا سيتم تحميله لكل المستخدمين مع كل تحميل للصفحة. */
  
// =============================================================================
+
console.log("Entering Common.js");
// Formate a poem
+
// 2024-02-27: Created by Abdalla G. M. Ahmed
+
// =============================================================================
+
  
// -----------------------------------------------------------------------------
+
$(function () {
// Measure displayed width of an HTML text
+
     if (document.querySelectorAll('.abyat').length > 0) {
// -----------------------------------------------------------------------------
+
         var script = document.createElement('script');
 
+
         script.src = "https://abdallagafar.github.io/poemFormat/poemFormat.js";
function measureTextWidth(text, font) {
+
         script.addEventListener('load', function() {                           // Now the external script is loaded and its functions are ready to be used
     var tmpSpan = document.createElement("span");
+
             document.querySelectorAll('.abyat').forEach(function(poem) {       // Search for poems
    tmpSpan.style.font = font;                                                  // Apply the font style
+
                 poem.innerHTML = poemFormat(poem);
    tmpSpan.style.position = "absolute";
+
             });
    tmpSpan.style.visibility = "hidden";
+
             console.log('Processed ' + poemFormatGrossCounter + ' beit.');
    tmpSpan.style.whiteSpace = "nowrap";
+
        });
    tmpSpan.innerHTML = text;
+
         document.head.appendChild(script);                                     // Append the script element to the document's head to start loading the script
 
+
    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(/<\/p><p>/gi, '<br>\n')                                        // Undo wiki removal of single empty lines
+
        .replace(/\s*(<p[^>]*>|<div[^>]*>|<pre[^>]*>)/gi, '')                  // Remove whitespace before opening container tags and the tags
+
        .replace(/<\/p>|<\/div>|<\/pre>/gi, '')                                // Remove closing tags
+
        .replace(/\s*<hr[^>]*>\s*/gi, '\n----\n')
+
        .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
+
    var staggered = false;
+
    for (var i = 0; i < lines.length; i++) {
+
         var line = lines[i];
+
        var indented = line.match(/^ {2,}/);                                    // Starts with two or more spaces?
+
        if (indented) staggered = true;                                        // Once is enough!
+
        line = line.trim();                                                    // Remove leading and trailing spaces
+
        if (line === "" || line.match(/<br>/)) {                                // Empty line
+
            formattedLines.push('<br>');                                       // is replaced by a line break
+
            continue;                                                          // Done with this line
+
         }
+
        if (line === "----") {                                                  // Separator line
+
            formattedLines.push('<hr style="width:%bWidth%px">');
+
            continue;                                                          // Done with this line
+
        }
+
        if (line.match(/^!/)) {                                                // 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
+
         }
+
        var closingHalf = false;
+
        if (line.startsWith('..') && line.endsWith('..')) {                     // Lines delimited by two dots are treated as closing halves.
+
            line = line.substring(2, line.length - 2).trim();                  // Remove delimiters and any white space
+
            line = '*  ' + line.replace(/(\s+)/g, ' ');                        // Insert a minimal-width dummy half, and remove gaps, if any, to process as two halves
+
             closingHalf = true;
+
            indented = false;
+
        }
+
        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="beit">'
+
                + '<span class="bJustified">'
+
                + line
+
                + '</span>'
+
                + '</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
+
                if (nonAlphabeticPart) 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
+
        var parts = (
+
            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="bJustified" style="width:%pWidth%px">'
+
                        + item +
+
                        '</span>'
+
                    );
+
                }
+
                else {                                                          // White space separating parts
+
                    return '<span class="bGap">  </span>';                      // Enclose in a span, typically stylized to preserve spaces
+
                }
+
            })
+
        );
+
        pWidth[nParts] = Math.max(pWidth[nParts], partWidth);
+
        line = (
+
            closingHalf ?
+
            parts[2] :
+
            '<span class="bJustified" style="width:%bWidth%px">'
+
                + parts.join('')
+
                + '</span>'
+
        ).replace(/%pWidth%/g, '%pWidth' + nParts + '%');                      // The number of parts is known now
+
        if (indented) { line = '%margin%' + line; }
+
        else          { line = line + '%margin%'; }
+
        formattedLines.push(
+
            '<p class="beit">'
+
            + line
+
            + 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 margin = (
 
        staggered ?
 
        '<span class="bGap" style="width:' + bGap + 'px">  </span>' :
 
        ''                                                                      // Default to none
 
    );
 
    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
 
        .replace(/%margin%/g, margin)
 
    );
 
}
 
 
$(function () {
 
    document.querySelectorAll('.ash3ar').forEach(function(poems) {              // Divisions declared as lists of أشعار
 
        poems.innerHTML = (                                                    // Replace their content with ..
 
            poems.innerHTML                                                    // Take innerHTML to preserve formatting
 
            .split(/\+{3,}/)                                                    // Use three or more "+" characters to split
 
            .map(function(txt) { return '<div class="abyat">'+txt+'</div>'; })  // Enclose in a class declared as abyat for subsequent identification
 
            .join('\n<hr>\n')                                                         
 
        );
 
    });
 
 
    document.querySelectorAll('.abyat').forEach(function(poem) {                // Iterate through containers declared as أبيات
 
        poem.innerHTML = poemFormat(poem);                                      // Process to format
 
    });
 
  
 
     var toggler = document.getElementsByClassName("treeBranch");
 
     var toggler = document.getElementsByClassName("treeBranch");

المراجعة الحالية بتاريخ ١٧:٣٥، ٢٦ مارس ٢٠٢٤

/* الجافاسكريبت الموضوع هنا سيتم تحميله لكل المستخدمين مع كل تحميل للصفحة. */
 
console.log("Entering Common.js");
 
$(function () {
    if (document.querySelectorAll('.abyat').length > 0) {
        var script = document.createElement('script');
        script.src = "https://abdallagafar.github.io/poemFormat/poemFormat.js";
        script.addEventListener('load', function() {                            // Now the external script is loaded and its functions are ready to be used
            document.querySelectorAll('.abyat').forEach(function(poem) {        // Search for poems
                poem.innerHTML = poemFormat(poem);
            });
            console.log('Processed ' + poemFormatGrossCounter + ' beit.');
        });
        document.head.appendChild(script);                                      // Append the script element to the document's head to start loading the script
    }
 
    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");
        });
    }
}());