Module:TextPageTabs: Difference between revisions

From Bodhicitta
((by SublimeText.Mediawiker))
 
((by SublimeText.Mediawiker))
Line 60: Line 60:
         extraTabs = frame:preprocess(pArgs.ExtraTabs)
         extraTabs = frame:preprocess(pArgs.ExtraTabs)
     end
     end
    -- Add the JavaScript for lazy loading
    local script = [=[
<script>
(function() {
    // Function to load tab content
    function loadTabContent(tabElement) {
        var $tab = $(tabElement);
        if ($tab.data('loaded') === 'true' || $tab.data('loading') === 'true') {
            return;
        }
       
        $tab.data('loading', 'true');
        var tabType = $tab.data('tab-type');
        var page = $tab.data('page');
        var subpage = $tab.data('subpage');
       
        // Make API call to load the tab content
        $.ajax({
            url: mw.util.wikiScript('api'),
            data: {
                action: 'parse',
                format: 'json',
                text: '{{#invoke:TextPageTabsAjax|' + tabType + '|page=' + page + '|subpage=' + subpage + '}}',
                contentmodel: 'wikitext',
                disablelimitreport: true,
                wrapoutputclass: ''
            },
            success: function(data) {
                if (data.parse && data.parse.text) {
                    $tab.html(data.parse.text['*']);
                    $tab.data('loaded', 'true');
                } else {
                    $tab.html('<div class="alert alert-warning">Failed to load content.</div>');
                }
            },
            error: function() {
                $tab.html('<div class="alert alert-danger">Error loading content. Please refresh the page.</div>');
            },
            complete: function() {
                $tab.data('loading', 'false');
            }
        });
    }
   
    // Load first visible tab immediately after page load
    $(document).ready(function() {
        setTimeout(function() {
            // Find the first non-introduction tab that's visible
            $('.tabber__panel:visible .ajax-tab-content').first().each(function() {
                loadTabContent(this);
            });
        }, 100);
    });
   
    // Load tabs when clicked
    $(document).on('click', '.tabber__tab', function() {
        setTimeout(function() {
            $('.tabber__panel:visible .ajax-tab-content').each(function() {
                loadTabContent(this);
            });
        }, 50);
    });
   
    // Also handle when tabs become visible through other means
    var observer = new MutationObserver(function(mutations) {
        mutations.forEach(function(mutation) {
            if (mutation.type === 'attributes' && mutation.attributeName === 'class') {
                $(mutation.target).find('.ajax-tab-content').each(function() {
                    if ($(this).is(':visible') && $(this).data('loaded') !== 'true') {
                        loadTabContent(this);
                    }
                });
            }
        });
    });
   
    // Observe all tabber panels for visibility changes
    $('.tabber__panel').each(function() {
        observer.observe(this, { attributes: true });
    });
})();
</script>]=]
    -- Add CSS for spinner (if not already in your site CSS)
    local styles = [=[
<style>
.spinner-border {
    display: inline-block;
    width: 2rem;
    height: 2rem;
    vertical-align: text-bottom;
    border: .25em solid currentColor;
    border-right-color: transparent;
    border-radius: 50%;
    animation: spinner-border .75s linear infinite;
}
@keyframes spinner-border {
    to { transform: rotate(360deg); }
}
</style>]=]


     -- Return tabber with scripts
     -- Return tabber with scripts

Revision as of 16:50, 23 September 2025

Documentation for this module may be created at Module:TextPageTabs/doc

local p = {}

function p.main(frame)
    local pArgs = frame:getParent().args
    local qPage = pArgs.page
    local subPage = pArgs.queryPagename

    -- Build first tab content with intro and featured vid (loads immediately)
    local firstTab = 'Introduction = <div class="row mx-0">'

    if pArgs.FeaturedYoutubeID then
        firstTab = firstTab .. '<div class="col-md-8 pl-md-0">' .. pArgs.introduction .. '</div>'
        local featureVid = '<div class="col-md-4 pr-md-0">' .. frame:expandTemplate{
            title = 'YouTube',
            args = {
                id = pArgs.FeaturedYoutubeID,
                caption = pArgs.FeaturedVidCaption
            }
        } .. '</div>'
        firstTab = firstTab .. featureVid
    else
        firstTab = firstTab .. '<div class="col-12">' .. pArgs.introduction .. '</div>'
    end

    firstTab = firstTab .. '</div>'

    -- Build tab content, starting with first tab
    local tabContent = { firstTab }
    
    -- Create placeholder tabs with loading indicators
    -- Each tab gets a unique ID and data attributes for AJAX loading
    local tabs = {
        {name = 'Recensions', id = 'recensions'},
        {name = 'Translations', id = 'translations'},
        {name = 'Commentaries', id = 'commentaries'},
        {name = 'Teachings', id = 'teachings'},
        {name = 'Media', id = 'media'},
        {name = 'Related scholarship', id = 'scholarship'},
        {name = 'Other content', id = 'other'}
    }
    
    for _, tab in ipairs(tabs) do
        local tabHtml = tab.name .. ' = <div class="ajax-tab-content" ' ..
            'data-tab-type="' .. tab.id .. '" ' ..
            'data-page="' .. mw.text.encode(qPage) .. '" ' ..
            'data-subpage="' .. mw.text.encode(subPage) .. '" ' ..
            'data-loaded="false">' ..
            '<div class="text-center p-4">' ..
            '<div class="spinner-border text-primary" role="status">' ..
            '<span class="sr-only">Loading...</span>' ..
            '</div>' ..
            '<div class="mt-2">Loading ' .. tab.name:lower() .. '...</div>' ..
            '</div></div>'
        table.insert(tabContent, tabHtml)
    end

    -- Check for extra tabs added manually
    local extraTabs = ''
    if pArgs.ExtraTabs then 
        extraTabs = frame:preprocess(pArgs.ExtraTabs)
    end

    -- Return tabber with scripts
    if #tabContent > 0 or extraTabs then
        return frame:preprocess('{{#tag:tabber|' .. table.concat(tabContent, '{{!}}-{{!}}') .. '}}') .. 
               extraTabs .. script .. styles
    else
        return 'No related content found.'
    end
end

return p