<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://dunedb.com/index.php?action=history&amp;feed=atom&amp;title=MediaWiki%3AGadget-ResourcePage.js</id>
	<title>MediaWiki:Gadget-ResourcePage.js - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://dunedb.com/index.php?action=history&amp;feed=atom&amp;title=MediaWiki%3AGadget-ResourcePage.js"/>
	<link rel="alternate" type="text/html" href="https://dunedb.com/index.php?title=MediaWiki:Gadget-ResourcePage.js&amp;action=history"/>
	<updated>2026-05-20T01:11:46Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.43.1</generator>
	<entry>
		<id>https://dunedb.com/index.php?title=MediaWiki:Gadget-ResourcePage.js&amp;diff=1173&amp;oldid=prev</id>
		<title>Operator at 05:51, 4 June 2025</title>
		<link rel="alternate" type="text/html" href="https://dunedb.com/index.php?title=MediaWiki:Gadget-ResourcePage.js&amp;diff=1173&amp;oldid=prev"/>
		<updated>2025-06-04T05:51:37Z</updated>

		<summary type="html">&lt;p&gt;&lt;/p&gt;
&lt;a href=&quot;https://dunedb.com/index.php?title=MediaWiki:Gadget-ResourcePage.js&amp;amp;diff=1173&amp;amp;oldid=1170&quot;&gt;Show changes&lt;/a&gt;</summary>
		<author><name>Operator</name></author>
	</entry>
	<entry>
		<id>https://dunedb.com/index.php?title=MediaWiki:Gadget-ResourcePage.js&amp;diff=1170&amp;oldid=prev</id>
		<title>Operator at 05:45, 4 June 2025</title>
		<link rel="alternate" type="text/html" href="https://dunedb.com/index.php?title=MediaWiki:Gadget-ResourcePage.js&amp;diff=1170&amp;oldid=prev"/>
		<updated>2025-06-04T05:45:49Z</updated>

		<summary type="html">&lt;p&gt;&lt;/p&gt;
&lt;a href=&quot;https://dunedb.com/index.php?title=MediaWiki:Gadget-ResourcePage.js&amp;amp;diff=1170&amp;amp;oldid=921&quot;&gt;Show changes&lt;/a&gt;</summary>
		<author><name>Operator</name></author>
	</entry>
	<entry>
		<id>https://dunedb.com/index.php?title=MediaWiki:Gadget-ResourcePage.js&amp;diff=921&amp;oldid=prev</id>
		<title>Operator: Created page with &quot;/**  * ResourcePage Gadget  * Handles recipe popups and search functionality for resource pages  *   * @requires jquery  * @requires mediawiki.api  * @requires mediawiki.util  */  (function($, mw) {     &#039;use strict&#039;;          // Only run on pages with resource page elements     if (!$(&#039;.crafting-section, .recipe-table&#039;).length) {         return;     }          // Cache for storing recipe data     var recipeCache = {         craftedWith: null,         craftedFrom: null...&quot;</title>
		<link rel="alternate" type="text/html" href="https://dunedb.com/index.php?title=MediaWiki:Gadget-ResourcePage.js&amp;diff=921&amp;oldid=prev"/>
		<updated>2025-06-03T16:49:59Z</updated>

		<summary type="html">&lt;p&gt;Created page with &amp;quot;&lt;span class=&quot;autocomment&quot;&gt;*  * ResourcePage Gadget  * Handles recipe popups and search functionality for resource pages  *   * @requires jquery  * @requires mediawiki.api  * @requires mediawiki.util: &lt;/span&gt;  (function($, mw) {     &amp;#039;use strict&amp;#039;;          // Only run on pages with resource page elements     if (!$(&amp;#039;.crafting-section, .recipe-table&amp;#039;).length) {         return;     }          // Cache for storing recipe data     var recipeCache = {         craftedWith: null,         craftedFrom: null...&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;/**&lt;br /&gt;
 * ResourcePage Gadget&lt;br /&gt;
 * Handles recipe popups and search functionality for resource pages&lt;br /&gt;
 * &lt;br /&gt;
 * @requires jquery&lt;br /&gt;
 * @requires mediawiki.api&lt;br /&gt;
 * @requires mediawiki.util&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
(function($, mw) {&lt;br /&gt;
    &amp;#039;use strict&amp;#039;;&lt;br /&gt;
    &lt;br /&gt;
    // Only run on pages with resource page elements&lt;br /&gt;
    if (!$(&amp;#039;.crafting-section, .recipe-table&amp;#039;).length) {&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    // Cache for storing recipe data&lt;br /&gt;
    var recipeCache = {&lt;br /&gt;
        craftedWith: null,&lt;br /&gt;
        craftedFrom: null&lt;br /&gt;
    };&lt;br /&gt;
    &lt;br /&gt;
    // Initialize module&lt;br /&gt;
    function init() {&lt;br /&gt;
        // Add table search functionality&lt;br /&gt;
        initTableSearch();&lt;br /&gt;
        &lt;br /&gt;
        // Add popup handlers&lt;br /&gt;
        initPopupHandlers();&lt;br /&gt;
        &lt;br /&gt;
        // Format tables&lt;br /&gt;
        formatTables();&lt;br /&gt;
        &lt;br /&gt;
        // Add animation styles once&lt;br /&gt;
        addAnimationStyles();&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    // Format tables to ensure proper styling&lt;br /&gt;
    function formatTables() {&lt;br /&gt;
        $(&amp;#039;.recipe-table&amp;#039;).each(function() {&lt;br /&gt;
            var $table = $(this);&lt;br /&gt;
            &lt;br /&gt;
            // Ensure proper header styling&lt;br /&gt;
            $table.find(&amp;#039;thead tr&amp;#039;).addClass(&amp;#039;tr-dark&amp;#039;);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    // Initialize table search functionality&lt;br /&gt;
    function initTableSearch() {&lt;br /&gt;
        // Crafted With search&lt;br /&gt;
        $(&amp;#039;#craftedWithSearch&amp;#039;).on(&amp;#039;input&amp;#039;, function() {&lt;br /&gt;
            filterTable(&amp;#039;#craftedWithTable&amp;#039;, $(this).val());&lt;br /&gt;
        });&lt;br /&gt;
        &lt;br /&gt;
        // Crafted From search&lt;br /&gt;
        $(&amp;#039;#craftedFromSearch&amp;#039;).on(&amp;#039;input&amp;#039;, function() {&lt;br /&gt;
            filterTable(&amp;#039;#craftedFromTable&amp;#039;, $(this).val());&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    // Filter table rows based on search input&lt;br /&gt;
    function filterTable(tableId, searchTerm) {&lt;br /&gt;
        var $table = $(tableId);&lt;br /&gt;
        var term = searchTerm.toLowerCase();&lt;br /&gt;
        &lt;br /&gt;
        $table.find(&amp;#039;tbody tr&amp;#039;).each(function() {&lt;br /&gt;
            var $row = $(this);&lt;br /&gt;
            var text = $row.text().toLowerCase();&lt;br /&gt;
            &lt;br /&gt;
            if (text.indexOf(term) &amp;gt; -1) {&lt;br /&gt;
                $row.show();&lt;br /&gt;
            } else {&lt;br /&gt;
                $row.hide();&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    // Initialize popup handlers&lt;br /&gt;
    function initPopupHandlers() {&lt;br /&gt;
        // View All Crafted With button&lt;br /&gt;
        $(document).on(&amp;#039;click&amp;#039;, &amp;#039;.view-all-crafted-with&amp;#039;, function(e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            var resourceName = $(this).data(&amp;#039;resource&amp;#039;);&lt;br /&gt;
            showRecipePopup(&amp;#039;craftedWith&amp;#039;, resourceName);&lt;br /&gt;
        });&lt;br /&gt;
        &lt;br /&gt;
        // View All Crafted From button&lt;br /&gt;
        $(document).on(&amp;#039;click&amp;#039;, &amp;#039;.view-all-crafted-from&amp;#039;, function(e) {&lt;br /&gt;
            e.preventDefault();&lt;br /&gt;
            var resourceName = $(this).data(&amp;#039;resource&amp;#039;);&lt;br /&gt;
            showRecipePopup(&amp;#039;craftedFrom&amp;#039;, resourceName);&lt;br /&gt;
        });&lt;br /&gt;
        &lt;br /&gt;
        // Close popup handlers&lt;br /&gt;
        $(document).on(&amp;#039;click&amp;#039;, &amp;#039;.recipe-popup-overlay, .popup-close&amp;#039;, function(e) {&lt;br /&gt;
            if (e.target === this || $(e.target).hasClass(&amp;#039;popup-close&amp;#039;)) {&lt;br /&gt;
                closeRecipePopup();&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
        &lt;br /&gt;
        // Escape key to close popup&lt;br /&gt;
        $(document).on(&amp;#039;keydown&amp;#039;, function(e) {&lt;br /&gt;
            if (e.key === &amp;#039;Escape&amp;#039; &amp;amp;&amp;amp; $(&amp;#039;.recipe-popup-overlay&amp;#039;).hasClass(&amp;#039;active&amp;#039;)) {&lt;br /&gt;
                closeRecipePopup();&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    // Show recipe popup&lt;br /&gt;
    function showRecipePopup(type, resourceName) {&lt;br /&gt;
        var title = type === &amp;#039;craftedWith&amp;#039; &lt;br /&gt;
            ? &amp;#039;All Recipes Using &amp;#039; + resourceName&lt;br /&gt;
            : &amp;#039;All Recipes Creating &amp;#039; + resourceName;&lt;br /&gt;
        &lt;br /&gt;
        // Show loading state&lt;br /&gt;
        showLoadingPopup();&lt;br /&gt;
        &lt;br /&gt;
        // First, check for full data in hidden elements&lt;br /&gt;
        var $fullDataElement = $(&amp;#039;.&amp;#039; + type.replace(&amp;#039;craftedWith&amp;#039;, &amp;#039;crafted-with&amp;#039;).replace(&amp;#039;craftedFrom&amp;#039;, &amp;#039;crafted-from&amp;#039;) + &amp;#039;-full-data&amp;#039;);&lt;br /&gt;
        &lt;br /&gt;
        if ($fullDataElement.length &amp;amp;&amp;amp; $fullDataElement.text().trim()) {&lt;br /&gt;
            try {&lt;br /&gt;
                // Parse JSON data from hidden element&lt;br /&gt;
                var jsonData = JSON.parse($fullDataElement.text());&lt;br /&gt;
                var rows = jsonData.results || [];&lt;br /&gt;
                &lt;br /&gt;
                // Transform to expected format&lt;br /&gt;
                var formattedRows = rows.map(function(row) {&lt;br /&gt;
                    return {&lt;br /&gt;
                        item: row.OutputItem || row.output_item || &amp;#039;&amp;#039;,&lt;br /&gt;
                        resources: row.Resources || row.resources || &amp;#039;&amp;#039;,&lt;br /&gt;
                        stations: row.Stations || row.station || &amp;#039;&amp;#039;,&lt;br /&gt;
                        water: row.WaterML || row.water_ml || &amp;#039;N/A&amp;#039;,&lt;br /&gt;
                        craftTime: row.CraftTime || row.craft_time || &amp;#039;N/A&amp;#039;,&lt;br /&gt;
                        schematic: row.Schematic || row.schematic || &amp;#039;N/A&amp;#039;&lt;br /&gt;
                    };&lt;br /&gt;
                });&lt;br /&gt;
                &lt;br /&gt;
                displayPopup(title, formattedRows, false);&lt;br /&gt;
                return;&lt;br /&gt;
            } catch (e) {&lt;br /&gt;
                console.warn(&amp;#039;Failed to parse full recipe data:&amp;#039;, e);&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        // Fallback to visible data&lt;br /&gt;
        var $table = $(type === &amp;#039;craftedWith&amp;#039; ? &amp;#039;#craftedWithTable&amp;#039; : &amp;#039;#craftedFromTable&amp;#039;);&lt;br /&gt;
        var rows = getVisibleRows(type);&lt;br /&gt;
        displayPopup(title, rows, true);&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    // Get visible rows as fallback&lt;br /&gt;
    function getVisibleRows(type) {&lt;br /&gt;
        var $table = $(type === &amp;#039;craftedWith&amp;#039; ? &amp;#039;#craftedWithTable&amp;#039; : &amp;#039;#craftedFromTable&amp;#039;);&lt;br /&gt;
        var rows = [];&lt;br /&gt;
        &lt;br /&gt;
        $table.find(&amp;#039;tbody tr:visible&amp;#039;).each(function() {&lt;br /&gt;
            var $row = $(this);&lt;br /&gt;
            var $cells = $row.find(&amp;#039;td&amp;#039;);&lt;br /&gt;
            &lt;br /&gt;
            if ($cells.length &amp;gt;= 3) {&lt;br /&gt;
                rows.push({&lt;br /&gt;
                    item: $cells.eq(0).html(),&lt;br /&gt;
                    resources: $cells.eq(1).html(),&lt;br /&gt;
                    stations: $cells.eq(2).html(),&lt;br /&gt;
                    water: &amp;#039;N/A&amp;#039;,&lt;br /&gt;
                    craftTime: &amp;#039;N/A&amp;#039;,&lt;br /&gt;
                    schematic: &amp;#039;N/A&amp;#039;&lt;br /&gt;
                });&lt;br /&gt;
            }&lt;br /&gt;
        });&lt;br /&gt;
        &lt;br /&gt;
        return rows;&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    // Show loading popup&lt;br /&gt;
    function showLoadingPopup() {&lt;br /&gt;
        var loadingHtml = &amp;#039;&amp;lt;div class=&amp;quot;recipe-popup-overlay active&amp;quot;&amp;gt;&amp;#039; +&lt;br /&gt;
            &amp;#039;&amp;lt;div class=&amp;quot;recipe-popup&amp;quot;&amp;gt;&amp;#039; +&lt;br /&gt;
                &amp;#039;&amp;lt;div class=&amp;quot;popup-content&amp;quot; style=&amp;quot;text-align: center; padding: 60px;&amp;quot;&amp;gt;&amp;#039; +&lt;br /&gt;
                    &amp;#039;&amp;lt;div style=&amp;quot;font-size: 24px; color: #fce7c8; margin-bottom: 20px;&amp;quot;&amp;gt;Loading recipes...&amp;lt;/div&amp;gt;&amp;#039; +&lt;br /&gt;
                    &amp;#039;&amp;lt;div class=&amp;quot;loading-spinner&amp;quot;&amp;gt;⟳&amp;lt;/div&amp;gt;&amp;#039; +&lt;br /&gt;
                &amp;#039;&amp;lt;/div&amp;gt;&amp;#039; +&lt;br /&gt;
            &amp;#039;&amp;lt;/div&amp;gt;&amp;#039; +&lt;br /&gt;
        &amp;#039;&amp;lt;/div&amp;gt;&amp;#039;;&lt;br /&gt;
        &lt;br /&gt;
        $(&amp;#039;body&amp;#039;).append(loadingHtml);&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    // Display popup with data&lt;br /&gt;
    function displayPopup(title, rows, isLimited) {&lt;br /&gt;
        // Remove any existing popup&lt;br /&gt;
        $(&amp;#039;.recipe-popup-overlay&amp;#039;).remove();&lt;br /&gt;
        &lt;br /&gt;
        // Build table rows HTML&lt;br /&gt;
        var tableRowsHtml = &amp;#039;&amp;#039;;&lt;br /&gt;
        rows.forEach(function(row) {&lt;br /&gt;
            tableRowsHtml += &amp;#039;&amp;lt;tr&amp;gt;&amp;#039; +&lt;br /&gt;
                &amp;#039;&amp;lt;td&amp;gt;&amp;#039; + row.item + &amp;#039;&amp;lt;/td&amp;gt;&amp;#039; +&lt;br /&gt;
                &amp;#039;&amp;lt;td&amp;gt;&amp;#039; + row.resources + &amp;#039;&amp;lt;/td&amp;gt;&amp;#039; +&lt;br /&gt;
                &amp;#039;&amp;lt;td&amp;gt;&amp;#039; + row.stations + &amp;#039;&amp;lt;/td&amp;gt;&amp;#039; +&lt;br /&gt;
                &amp;#039;&amp;lt;td&amp;gt;&amp;#039; + row.water + &amp;#039;&amp;lt;/td&amp;gt;&amp;#039; +&lt;br /&gt;
                &amp;#039;&amp;lt;td&amp;gt;&amp;#039; + row.craftTime + &amp;#039;&amp;lt;/td&amp;gt;&amp;#039; +&lt;br /&gt;
                &amp;#039;&amp;lt;td&amp;gt;&amp;#039; + row.schematic + &amp;#039;&amp;lt;/td&amp;gt;&amp;#039; +&lt;br /&gt;
            &amp;#039;&amp;lt;/tr&amp;gt;&amp;#039;;&lt;br /&gt;
        });&lt;br /&gt;
        &lt;br /&gt;
        // Note if data is limited&lt;br /&gt;
        var limitedNote = isLimited ? &lt;br /&gt;
            &amp;#039;&amp;lt;div class=&amp;quot;popup-note&amp;quot;&amp;gt;Note: Showing only visible recipes. Full data requires server-side implementation.&amp;lt;/div&amp;gt;&amp;#039; : &lt;br /&gt;
            &amp;#039;&amp;#039;;&lt;br /&gt;
        &lt;br /&gt;
        // Build popup HTML&lt;br /&gt;
        var popupHtml = &amp;#039;&amp;lt;div class=&amp;quot;recipe-popup-overlay&amp;quot;&amp;gt;&amp;#039; +&lt;br /&gt;
            &amp;#039;&amp;lt;div class=&amp;quot;recipe-popup&amp;quot;&amp;gt;&amp;#039; +&lt;br /&gt;
                &amp;#039;&amp;lt;div class=&amp;quot;popup-header&amp;quot;&amp;gt;&amp;#039; +&lt;br /&gt;
                    &amp;#039;&amp;lt;h3 class=&amp;quot;popup-title&amp;quot;&amp;gt;&amp;#039; + title + &amp;#039;&amp;lt;/h3&amp;gt;&amp;#039; +&lt;br /&gt;
                    &amp;#039;&amp;lt;button class=&amp;quot;popup-close&amp;quot;&amp;gt;×&amp;lt;/button&amp;gt;&amp;#039; +&lt;br /&gt;
                &amp;#039;&amp;lt;/div&amp;gt;&amp;#039; +&lt;br /&gt;
                &amp;#039;&amp;lt;div class=&amp;quot;popup-content&amp;quot;&amp;gt;&amp;#039; +&lt;br /&gt;
                    limitedNote +&lt;br /&gt;
                    &amp;#039;&amp;lt;div class=&amp;quot;popup-search-container&amp;quot;&amp;gt;&amp;#039; +&lt;br /&gt;
                        &amp;#039;&amp;lt;input type=&amp;quot;text&amp;quot; class=&amp;quot;popup-search-input&amp;quot; placeholder=&amp;quot;Search recipes...&amp;quot; id=&amp;quot;popupSearchInput&amp;quot;&amp;gt;&amp;#039; +&lt;br /&gt;
                    &amp;#039;&amp;lt;/div&amp;gt;&amp;#039; +&lt;br /&gt;
                    &amp;#039;&amp;lt;div class=&amp;quot;popup-table-wrapper&amp;quot;&amp;gt;&amp;#039; +&lt;br /&gt;
                        &amp;#039;&amp;lt;table class=&amp;quot;infobox-dune-standard-table recipe-popup-table&amp;quot; id=&amp;quot;popupRecipeTable&amp;quot;&amp;gt;&amp;#039; +&lt;br /&gt;
                            &amp;#039;&amp;lt;thead&amp;gt;&amp;#039; +&lt;br /&gt;
                                &amp;#039;&amp;lt;tr class=&amp;quot;tr-dark&amp;quot;&amp;gt;&amp;#039; +&lt;br /&gt;
                                    &amp;#039;&amp;lt;th data-sort=&amp;quot;item&amp;quot;&amp;gt;Item Created&amp;lt;/th&amp;gt;&amp;#039; +&lt;br /&gt;
                                    &amp;#039;&amp;lt;th data-sort=&amp;quot;resources&amp;quot;&amp;gt;Resources Needed&amp;lt;/th&amp;gt;&amp;#039; +&lt;br /&gt;
                                    &amp;#039;&amp;lt;th data-sort=&amp;quot;stations&amp;quot;&amp;gt;Stations&amp;lt;/th&amp;gt;&amp;#039; +&lt;br /&gt;
                                    &amp;#039;&amp;lt;th data-sort=&amp;quot;water&amp;quot;&amp;gt;Water (mL)&amp;lt;/th&amp;gt;&amp;#039; +&lt;br /&gt;
                                    &amp;#039;&amp;lt;th data-sort=&amp;quot;time&amp;quot;&amp;gt;Craft Time&amp;lt;/th&amp;gt;&amp;#039; +&lt;br /&gt;
                                    &amp;#039;&amp;lt;th data-sort=&amp;quot;schematic&amp;quot;&amp;gt;Schematic&amp;lt;/th&amp;gt;&amp;#039; +&lt;br /&gt;
                                &amp;#039;&amp;lt;/tr&amp;gt;&amp;#039; +&lt;br /&gt;
                            &amp;#039;&amp;lt;/thead&amp;gt;&amp;#039; +&lt;br /&gt;
                            &amp;#039;&amp;lt;tbody&amp;gt;&amp;#039; + tableRowsHtml + &amp;#039;&amp;lt;/tbody&amp;gt;&amp;#039; +&lt;br /&gt;
                        &amp;#039;&amp;lt;/table&amp;gt;&amp;#039; +&lt;br /&gt;
                    &amp;#039;&amp;lt;/div&amp;gt;&amp;#039; +&lt;br /&gt;
                &amp;#039;&amp;lt;/div&amp;gt;&amp;#039; +&lt;br /&gt;
            &amp;#039;&amp;lt;/div&amp;gt;&amp;#039; +&lt;br /&gt;
        &amp;#039;&amp;lt;/div&amp;gt;&amp;#039;;&lt;br /&gt;
        &lt;br /&gt;
        // Add to page&lt;br /&gt;
        $(&amp;#039;body&amp;#039;).append(popupHtml);&lt;br /&gt;
        &lt;br /&gt;
        // Activate popup&lt;br /&gt;
        setTimeout(function() {&lt;br /&gt;
            $(&amp;#039;.recipe-popup-overlay&amp;#039;).addClass(&amp;#039;active&amp;#039;);&lt;br /&gt;
        }, 10);&lt;br /&gt;
        &lt;br /&gt;
        // Initialize popup functionality&lt;br /&gt;
        initPopupFunctionality();&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    // Initialize popup functionality (search and sort)&lt;br /&gt;
    function initPopupFunctionality() {&lt;br /&gt;
        // Search functionality&lt;br /&gt;
        $(&amp;#039;#popupSearchInput&amp;#039;).on(&amp;#039;input&amp;#039;, function() {&lt;br /&gt;
            var searchTerm = $(this).val().toLowerCase();&lt;br /&gt;
            &lt;br /&gt;
            $(&amp;#039;#popupRecipeTable tbody tr&amp;#039;).each(function() {&lt;br /&gt;
                var $row = $(this);&lt;br /&gt;
                var text = $row.text().toLowerCase();&lt;br /&gt;
                &lt;br /&gt;
                if (text.indexOf(searchTerm) &amp;gt; -1) {&lt;br /&gt;
                    $row.show();&lt;br /&gt;
                } else {&lt;br /&gt;
                    $row.hide();&lt;br /&gt;
                }&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
        &lt;br /&gt;
        // Sort functionality&lt;br /&gt;
        $(&amp;#039;#popupRecipeTable thead th&amp;#039;).on(&amp;#039;click&amp;#039;, function() {&lt;br /&gt;
            var $th = $(this);&lt;br /&gt;
            var sortKey = $th.data(&amp;#039;sort&amp;#039;);&lt;br /&gt;
            var $tbody = $(&amp;#039;#popupRecipeTable tbody&amp;#039;);&lt;br /&gt;
            var rows = $tbody.find(&amp;#039;tr&amp;#039;).toArray();&lt;br /&gt;
            &lt;br /&gt;
            // Determine sort direction&lt;br /&gt;
            var ascending = !$th.hasClass(&amp;#039;sort-desc&amp;#039;);&lt;br /&gt;
            &lt;br /&gt;
            // Remove sort classes from all headers&lt;br /&gt;
            $(&amp;#039;#popupRecipeTable thead th&amp;#039;).removeClass(&amp;#039;sort-asc sort-desc&amp;#039;);&lt;br /&gt;
            &lt;br /&gt;
            // Add appropriate class to clicked header&lt;br /&gt;
            $th.addClass(ascending ? &amp;#039;sort-asc&amp;#039; : &amp;#039;sort-desc&amp;#039;);&lt;br /&gt;
            &lt;br /&gt;
            // Sort rows&lt;br /&gt;
            rows.sort(function(a, b) {&lt;br /&gt;
                var aText = $(a).find(&amp;#039;td&amp;#039;).eq($th.index()).text().trim();&lt;br /&gt;
                var bText = $(b).find(&amp;#039;td&amp;#039;).eq($th.index()).text().trim();&lt;br /&gt;
                &lt;br /&gt;
                // Try to parse as number&lt;br /&gt;
                var aNum = parseFloat(aText);&lt;br /&gt;
                var bNum = parseFloat(bText);&lt;br /&gt;
                &lt;br /&gt;
                if (!isNaN(aNum) &amp;amp;&amp;amp; !isNaN(bNum)) {&lt;br /&gt;
                    return ascending ? aNum - bNum : bNum - aNum;&lt;br /&gt;
                }&lt;br /&gt;
                &lt;br /&gt;
                // Sort as text&lt;br /&gt;
                return ascending &lt;br /&gt;
                    ? aText.localeCompare(bText)&lt;br /&gt;
                    : bText.localeCompare(aText);&lt;br /&gt;
            });&lt;br /&gt;
            &lt;br /&gt;
            // Re-append sorted rows&lt;br /&gt;
            $tbody.empty();&lt;br /&gt;
            rows.forEach(function(row) {&lt;br /&gt;
                $tbody.append(row);&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    // Close recipe popup&lt;br /&gt;
    function closeRecipePopup() {&lt;br /&gt;
        $(&amp;#039;.recipe-popup-overlay&amp;#039;).removeClass(&amp;#039;active&amp;#039;);&lt;br /&gt;
        &lt;br /&gt;
        setTimeout(function() {&lt;br /&gt;
            $(&amp;#039;.recipe-popup-overlay&amp;#039;).remove();&lt;br /&gt;
        }, 300);&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    // Add required CSS for animations&lt;br /&gt;
    function addAnimationStyles() {&lt;br /&gt;
        if ($(&amp;#039;#resourcePageGadgetStyles&amp;#039;).length === 0) {&lt;br /&gt;
            var styles = &amp;#039;&amp;lt;style id=&amp;quot;resourcePageGadgetStyles&amp;quot;&amp;gt;&amp;#039; +&lt;br /&gt;
                &amp;#039;.loading-spinner { font-size: 48px; animation: spin 1s linear infinite; }&amp;#039; +&lt;br /&gt;
                &amp;#039;@keyframes spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }&amp;#039; +&lt;br /&gt;
                &amp;#039;.recipe-popup-table th.sort-asc::after { content: &amp;quot; ↑&amp;quot;; color: #fce7c8; }&amp;#039; +&lt;br /&gt;
                &amp;#039;.recipe-popup-table th.sort-desc::after { content: &amp;quot; ↓&amp;quot;; color: #fce7c8; }&amp;#039; +&lt;br /&gt;
                &amp;#039;.popup-note { background: rgba(252,231,200,.1); border: 1px solid rgba(252,231,200,.3); &amp;#039; +&lt;br /&gt;
                    &amp;#039;padding: 10px; margin-bottom: 15px; color: #E3BB7A; text-align: center; }&amp;#039; +&lt;br /&gt;
            &amp;#039;&amp;lt;/style&amp;gt;&amp;#039;;&lt;br /&gt;
            $(&amp;#039;head&amp;#039;).append(styles);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    // Initialize when DOM is ready&lt;br /&gt;
    $(init);&lt;br /&gt;
    &lt;br /&gt;
})(jQuery, mediaWiki);&lt;/div&gt;</summary>
		<author><name>Operator</name></author>
	</entry>
</feed>