MediaWiki:Common.js: Difference between revisions

From The Seven Sages of Rome
No edit summary
No edit summary
 
(19 intermediate revisions by the same user not shown)
Line 1: Line 1:
/** Test **/
mw.loader.load('/index.php?title=MediaWiki:CopyEmbeddedStory.js&action=raw&ctype=text/javascript');
$(document).ready(function() {
mw.loader.load('/index.php?title=MediaWiki:CustomFiltered.js&action=raw&ctype=text/javascript');
   // Trigger modal when the button is clicked
 
  $('#copyEmbeddedStories').click(function() {
jQuery(document).ready(function() {
     $('#storyModal').modal('show');
   jQuery('#manuscripts-table').DataTable({
     pageLength: 25,
    lengthMenu: [10, 25, 50, 100],
    order: [[1, 'asc']]
   });
   });
});
$(document).ready(function () {
    // 1) Existing behavior: add .scrolled to #mw-navigation once page is not at the very top
    // 2) New behavior: show top tier when scrolling up, hide it when scrolling down
    // Requires:
    // - top tier has class .js-navbar-top
    // - second tier has class .js-navbar-main (for CSS top: var(--topbar-h))
    // - CSS uses body.nav-updown-hide-top / body.nav-updown-show-top to animate
    var $top = $('.js-navbar-top');
    var $body = $('body');
    var navbar = document.getElementById('mw-navigation');
    var lastY = window.scrollY || 0;
    var ticking = false;
    function setTopbarHeight() {
        if (!$top.length) return;
        var h = $top.outerHeight() || 0;
        document.body.style.setProperty('--topbar-h', h + 'px');
    }
    function applyTopbarState(showTop) {
        $body
            .toggleClass('nav-updown-show-top', showTop)
            .toggleClass('nav-updown-hide-top', !showTop);


  // Handle autocomplete for page names
        if (!showTop) {
  $('#page-name').on('input', function() {
            document.body.style.setProperty('--topbar-h', '0px');
    var query = $(this).val();
         } else {
    if (query.length > 2) {
            setTopbarHeight();
      $.ajax({
        url: mw.util.wikiScript('api'),
        data: {
          action: 'query',
          list: 'allpages',
          apprefix: query,
          format: 'json'
         },
        success: function(response) {
          var pages = response.query.allpages;
          var suggestions = pages.map(function(page) {
            return page.title;
          });
          // Here you can implement a way to show these suggestions to the user,
          // such as a custom autocomplete dropdown
         }
         }
      });
     }
     }
  });


  // Process the data when the "Process" button is clicked
    function updateScrolledClass(y) {
  $('#process').click(function() {
        if (!navbar) return;
    var targetPage = $('#page-name').val();
        if (y > 0) {
    if (targetPage) {
            navbar.classList.add('scrolled');
      copyEmbeddedStories(targetPage);
        } else {
            navbar.classList.remove('scrolled');
        }
     }
     }
    $('#storyModal').modal('hide');  // Close the modal
  });
});


// Function to copy embedded stories from the current page to the target page
     // Initial state
function copyEmbeddedStories(targetPage) {
     updateScrolledClass(lastY);
  var pageTitle = mw.config.get('wgPageName');  // Get the current page title
 
  // Step 1: Fetch the edit token
  $.ajax({
    url: mw.util.wikiScript('api'),
     data: {
      action: 'query',
      format: 'json',
      titles: pageTitle,
      meta: 'tokens',  // Request tokens for the current user
     },
    success: function(response) {
      var editToken = response.query.tokens.csrftoken; // Get the edit token
     
      if (!editToken) {
        console.error('Failed to retrieve edit token.');
        return;
      }


      // Step 2: Get the latest revision content of the current page
    if ($top.length) {
      $.ajax({
         applyTopbarState(lastY === 0);
        url: mw.util.wikiScript('api'),
    }
        data: {
          action: 'query',
          format: 'json',
          titles: pageTitle,
          prop: 'revisions',
          rvprop: 'content',  // Get only the content of the latest revision
          rvlimit: 1  // Only the latest revision
        },
         success: function(response) {
          var pages = response.query.pages;
          var latestContent = '';
          for (var pageId in pages) {
            var page = pages[pageId];
            if (page.revisions && page.revisions.length > 0) {
              latestContent = page.revisions[0]['*']; // Get the content of the latest revision
            }
          }


          // If no content was found, log and exit
    $(window).on('scroll', function () {
          if (!latestContent) {
        if (ticking) return;
            console.error('No content found in the latest revision.');
        ticking = true;
            return;
          }


          // Find all EmbeddedStory templates in the content
        window.requestAnimationFrame(function () {
          var stories = latestContent.match(/\{\{EmbeddedStory[^}]*\}\}/g); // Regex to match all EmbeddedStory templates
            var y = window.scrollY || 0;
          var targetContent = stories ? stories.join('\n') : '';
            var delta = y - lastY;


          // If no stories are found, log and exit
             updateScrolledClass(y);
          if (!targetContent) {
             console.error('No embedded stories found.');
            return;
          }


          // Step 3: Use the MediaWiki API to update the target page with the content
            // Only run the two-tier logic if the top tier exists
          $.ajax({
            if ($top.length) {
            url: mw.util.wikiScript('api'),
                // ignore tiny jitter to avoid flicker
            method: 'POST',
                if (Math.abs(delta) >= 4) {
            data: {
                    if (y <= 0) {
              action: 'edit',
                        applyTopbarState(true);
              title: targetPage,
                    } else if (delta > 0) {
              text: targetContent,
                        // scrolling down
              summary: 'Copying embedded stories',
                        applyTopbarState(false);
              token: editToken,  // Pass the correct edit token
                    } else {
              format: 'json'
                        // scrolling up
            },
                        applyTopbarState(true);
            success: function(response) {
                    }
              if (response.error) {
                }
                console.error('API Error:', response.error);
                alert('Failed to copy Embedded Stories. API Error: ' + response.error.info);
              } else {
                alert('Embedded Stories copied successfully!');
              }
            },
            error: function(xhr, status, error) {
              console.error('AJAX Error:', status, error);
              alert('An error occurred while copying Embedded Stories. Please try again.');
             }
             }
          });
 
        },
            lastY = y;
        error: function(xhr, status, error) {
            ticking = false;
          console.error('AJAX Error:', status, error);
        });
          alert('Failed to fetch the latest revision. Please try again.');
    });
 
    $(window).on('resize', function () {
        if ($top.length && $body.hasClass('nav-updown-show-top')) {
            setTopbarHeight();
        }
    });
 
    // Handle late layout/font changes
    setTimeout(function () {
        if ($top.length && $body.hasClass('nav-updown-show-top')) {
            setTopbarHeight();
         }
         }
      });
        $(".datatables-container").addClass("smw-loaded");
    },
    }, 250);
    error: function(xhr, status, error) {
 
      console.error('Failed to fetch edit token:', status, error);
});
      alert('Failed to fetch edit token. Please try again.');
    }
  });
}


/** Test End **/


function scrollToAnchor(anchorId) {
function scrollToAnchor(anchorId) {
Line 192: Line 160:
     } );
     } );
})
})
$(document).ready(function() {
    $('[data-toggle="tooltip"]').tooltip();
});
$(document).ready(function () {
$(document).ready(function () {
    $('#copyButton').on('click', function () {
  $('#tree-filter').on('input', function () {
        var targetPage = $("#targetPageInput").val().trim();
    const query = $(this).val().toLowerCase();
         var embeddedStories = $("#embeddedStoryTemplates").text();
 
    $('#motif-tree li').each(function () {
      const $li = $(this);
      const $link = $li.children('a');
      const text = $link.text().toLowerCase();
 
      const matches = text.includes(query);
 
      // Initially hide everything
      $li.data('match', matches).hide();
    });
 
    // Show matching items and their ancestors
    $('#motif-tree li').each(function () {
      const $li = $(this);
      if ($li.data('match')) {
        $li.show();
         $li.parentsUntil('#motif-tree', 'li').show();
      }
    });
 
    // If input is empty, show all
    if (query === '') {
      $('#motif-tree li').show();
    }
  });
});


         if (!targetPage) {
function toggleTreeNode(element) {
             alert("Please select a target page.");
    var childrenDiv = element.parentElement.nextElementSibling;
             return;
   
    if (childrenDiv && childrenDiv.classList.contains('smw-tree-children')) {
         if (childrenDiv.style.display === 'none') {
             childrenDiv.style.display = 'block';
            element.classList.add('expanded');
        } else {
            childrenDiv.style.display = 'none';
             element.classList.remove('expanded');
         }
         }
    }
}


         if (!embeddedStories) {
// Optional: Add expand/collapse all functionality
             alert("No EmbeddedStory templates found on the source page.");
function expandAllTreeNodes() {
             return;
    document.querySelectorAll('.smw-tree-toggle').forEach(function(toggle) {
        var childrenDiv = toggle.parentElement.nextElementSibling;
         if (childrenDiv && childrenDiv.classList.contains('smw-tree-children')) {
             childrenDiv.style.display = 'block';
             toggle.classList.add('expanded');
         }
         }
    });
}


         // Confirm action
function collapseAllTreeNodes() {
         if (!confirm("Are you sure you want to copy the EmbeddedStory templates to " + targetPage + "?")) {
    document.querySelectorAll('.smw-tree-toggle').forEach(function(toggle) {
             return;
         var childrenDiv = toggle.parentElement.nextElementSibling;
         if (childrenDiv && childrenDiv.classList.contains('smw-tree-children')) {
             childrenDiv.style.display = 'none';
            toggle.classList.remove('expanded');
         }
         }
    });
}
$(document).ready(function () {
  $('.collapsible-tree').each(function () {
    const $tree = $(this);
    const expandLevel = $tree.data('expand-level'); // 'all', 'none', or a number (1, 2, etc.)
    // Iterate each LI that contains a UL as immediate child
    $tree.find('ul li:has(> ul)').each(function () {
      const $parentLi = $(this);
      const $subUl = $parentLi.children('ul');
      const $toggleIcon = $('<i class="js-toggle-icon">+</i>');
      // Calculate the depth level of this item (1 = first level, 2 = second level, etc.)
      const depth = $parentLi.parents('ul').length;
      // Add class for styling and prepend toggle icon
      $parentLi.addClass('has-children').prepend($toggleIcon);
      // Determine if this item should be expanded based on expand-level
      let shouldExpand = false;
      if (expandLevel === 'all') {
        shouldExpand = true;
      } else if (expandLevel === 'none' || expandLevel === undefined) {
        shouldExpand = false;
      } else if (typeof expandLevel === 'number' || !isNaN(expandLevel)) {
        shouldExpand = depth <= parseInt(expandLevel);
      }
      // Set initial state
      if (shouldExpand) {
        $toggleIcon.text('−');
        $subUl.show();
      } else {
        $toggleIcon.text('+');
        $subUl.hide();
      }
      // Attach event handler to the toggle icon
      $toggleIcon.on('click', function (e) {
        e.stopPropagation();
        const isCollapsed = $(this).text() === '+';
        $(this).text(isCollapsed ? '−' : '+');
        $subUl.slideToggle(200);
      });
    });
    // After the initial expand-level setup, expand the path to the current page.
    // MediaWiki marks the current page as <a class="mw-selflink selflink">.
    const $selfLink = $tree.find('a.mw-selflink.selflink');
    if ($selfLink.length) {
      // Walk up through all ancestor LIs that have children (i.e. have a toggle icon)
      $selfLink.parents('li.has-children').each(function () {
        const $li = $(this);
        const $toggleIcon = $li.children('i.js-toggle-icon');
        const $subUl = $li.children('ul');
        // Force-expand regardless of what expand-level set
        $toggleIcon.text('−');
        $subUl.show();
      });
      // Also mark the selflink's direct LI as the active item for styling purposes
      $selfLink.closest('li').addClass('current-page');
    }
  });
});
// Copy permalink to clipboard
function copyPermalinkToClipboard() {
    var revisionId = mw.config.get('wgRevisionId');
    var pageTitle = mw.config.get('wgPageName');
    var permalink = mw.config.get('wgServer') + mw.config.get('wgScriptPath') + '/index.php?title=' + encodeURIComponent(pageTitle) + '&oldid=' + revisionId;
   
    navigator.clipboard.writeText(permalink).then(function() {
        mw.notify('Permalink copied to clipboard!', { type: 'success' });
    }).catch(function(err) {
        mw.notify('Failed to copy permalink', { type: 'error' });
    });
}


        // Use MediaWiki API to append templates to the target page
// Attach to elements with class 'copy-permalink'
        $.post(mw.util.wikiScript('api'), {
$(document).ready(function() {
            action: 'edit',
    $(document).on('click', '.copy-permalink', function(e) {
            title: targetPage,
        e.preventDefault();
            appendtext: "\n" + embeddedStories,
         copyPermalinkToClipboard();
            token: mw.user.tokens.get('csrfToken'),
            format: 'json'
        })
        .done(function (data) {
            if (data && data.edit && data.edit.result === 'Success') {
                alert("EmbeddedStory templates copied successfully to " + targetPage + "!");
            } else {
                alert("An error occurred: " + (data.error && data.error.info));
            }
        })
         .fail(function () {
            alert("An error occurred while trying to copy the EmbeddedStory templates.");
        });
     });
     });
});
});

Latest revision as of 15:12, 27 February 2026

mw.loader.load('/index.php?title=MediaWiki:CopyEmbeddedStory.js&action=raw&ctype=text/javascript');
mw.loader.load('/index.php?title=MediaWiki:CustomFiltered.js&action=raw&ctype=text/javascript');

jQuery(document).ready(function() {
  jQuery('#manuscripts-table').DataTable({
    pageLength: 25,
    lengthMenu: [10, 25, 50, 100],
    order: [[1, 'asc']]
  });
});

$(document).ready(function () {
    // 1) Existing behavior: add .scrolled to #mw-navigation once page is not at the very top
    // 2) New behavior: show top tier when scrolling up, hide it when scrolling down
    // Requires:
    // - top tier has class .js-navbar-top
    // - second tier has class .js-navbar-main (for CSS top: var(--topbar-h))
    // - CSS uses body.nav-updown-hide-top / body.nav-updown-show-top to animate

    var $top = $('.js-navbar-top');
    var $body = $('body');
    var navbar = document.getElementById('mw-navigation');

    var lastY = window.scrollY || 0;
    var ticking = false;

    function setTopbarHeight() {
        if (!$top.length) return;
        var h = $top.outerHeight() || 0;
        document.body.style.setProperty('--topbar-h', h + 'px');
    }

    function applyTopbarState(showTop) {
        $body
            .toggleClass('nav-updown-show-top', showTop)
            .toggleClass('nav-updown-hide-top', !showTop);

        if (!showTop) {
            document.body.style.setProperty('--topbar-h', '0px');
        } else {
            setTopbarHeight();
        }
    }

    function updateScrolledClass(y) {
        if (!navbar) return;
        if (y > 0) {
            navbar.classList.add('scrolled');
        } else {
            navbar.classList.remove('scrolled');
        }
    }

    // Initial state
    updateScrolledClass(lastY);

    if ($top.length) {
        applyTopbarState(lastY === 0);
    }

    $(window).on('scroll', function () {
        if (ticking) return;
        ticking = true;

        window.requestAnimationFrame(function () {
            var y = window.scrollY || 0;
            var delta = y - lastY;

            updateScrolledClass(y);

            // Only run the two-tier logic if the top tier exists
            if ($top.length) {
                // ignore tiny jitter to avoid flicker
                if (Math.abs(delta) >= 4) {
                    if (y <= 0) {
                        applyTopbarState(true);
                    } else if (delta > 0) {
                        // scrolling down
                        applyTopbarState(false);
                    } else {
                        // scrolling up
                        applyTopbarState(true);
                    }
                }
            }

            lastY = y;
            ticking = false;
        });
    });

    $(window).on('resize', function () {
        if ($top.length && $body.hasClass('nav-updown-show-top')) {
            setTopbarHeight();
        }
    });

    // Handle late layout/font changes
    setTimeout(function () {
        if ($top.length && $body.hasClass('nav-updown-show-top')) {
            setTopbarHeight();
        }
        $(".datatables-container").addClass("smw-loaded");
    }, 250);

});


function scrollToAnchor(anchorId) {
    const element = document.getElementById(anchorId);
    const navbarHeight = 50;
    if (element) {
        // Calculate the adjusted scroll position
        const elementPosition = element.getBoundingClientRect().top + window.pageYOffset;
        const offsetPosition = elementPosition - navbarHeight;

        // Scroll to the adjusted position
        window.scrollTo({
            top: offsetPosition,
            behavior: 'smooth'
        });
    }
}
function drilldownswitcher() {
    $('#drilldown-switch:contains("Show all filters")').length ? ($(".drilldown-filter-values:has(a)").css("display", "block"),
            $(".drilldown-values-toggle").each(function () {
                $("img").each(function () {
                    $(this).attr("src", $(this).attr("src").replace("right-arrow.png", "down-arrow.png"));
                });
            }),
            (document.getElementById("drilldown-switch").innerHTML = 'Hide all filters <i class="fa fa-minus"></i>'))
        : $('#drilldown-switch:contains("Hide all filters")').length &&
        ($(".drilldown-filter-values:has(a)").css("display", "none"),
            $(".drilldown-values-toggle").each(function () {
                $("img").each(function () {
                    $(this).attr("src", $(this).attr("src").replace("down-arrow.png", "right-arrow.png"));
                });
            }),
            (document.getElementById("drilldown-switch").innerHTML = 'Show all filters <i class="fa fa-plus"></i>'));
}
$(document).ready(function () {
    $(".drilldown-results").css({ "-webkit-filter": "blur(0)", "-moz-filter": "blur(0)", "-o-filter": "blur(0)", "-ms-filter": "blur(0)", filter: "blur(0)" }), $(".drilldown-filter-values:has(a)").css("display", "none");
    $('<br /><h3 class="drilldown-pre-header">1. Selected Filters</h3>').insertBefore("#drilldown-applied-filters"),
    $('<h3 class="drilldown-pre-filters">2. Available Filters</h3>').insertBefore("#drilldown-applicable-filters"),
    $('<h3 class="drilldown-post-filters">3. Filtered Results</h3>').insertAfter("#drilldown-applicable-filters"),
    $('<html><div class="drilldown-btn-wrapper"><a class="btn primary-btn" href="javascript:;" onclick="drilldownswitcher()" id="drilldown-switch">Show all filters <i class="fa fa-plus"></i></a></div></html>').insertBefore("#drilldown-filters");
    $(".drilldown-values-toggle").each(function () {
    	$("img").each(function () {
        	$(this).attr("src", $(this).attr("src").replace("down-arrow.png", "right-arrow.png"));
    	});
    });

    if( mw.storage.get( "wip-dismissed" ) === null || JSON.parse(mw.storage.get( "wip-dismissed" )) === false){
    	$( ".wip-alert" ).fadeIn( "slow", function() {});
    }
    
    $( "#close-wip" ).on( "click", function() {
	  mw.storage.set( "wip-dismissed", true );
	  $( ".wip-alert" ).fadeOut( "slow", function() {});
    } );
})

$(document).ready(function() {
    $('[data-toggle="tooltip"]').tooltip();
});

$(document).ready(function () {
  $('#tree-filter').on('input', function () {
    const query = $(this).val().toLowerCase();

    $('#motif-tree li').each(function () {
      const $li = $(this);
      const $link = $li.children('a');
      const text = $link.text().toLowerCase();

      const matches = text.includes(query);

      // Initially hide everything
      $li.data('match', matches).hide();
    });

    // Show matching items and their ancestors
    $('#motif-tree li').each(function () {
      const $li = $(this);
      if ($li.data('match')) {
        $li.show();
        $li.parentsUntil('#motif-tree', 'li').show();
      }
    });

    // If input is empty, show all
    if (query === '') {
      $('#motif-tree li').show();
    }
  });
});

function toggleTreeNode(element) {
    var childrenDiv = element.parentElement.nextElementSibling;
    
    if (childrenDiv && childrenDiv.classList.contains('smw-tree-children')) {
        if (childrenDiv.style.display === 'none') {
            childrenDiv.style.display = 'block';
            element.classList.add('expanded');
        } else {
            childrenDiv.style.display = 'none';
            element.classList.remove('expanded');
        }
    }
}

// Optional: Add expand/collapse all functionality
function expandAllTreeNodes() {
    document.querySelectorAll('.smw-tree-toggle').forEach(function(toggle) {
        var childrenDiv = toggle.parentElement.nextElementSibling;
        if (childrenDiv && childrenDiv.classList.contains('smw-tree-children')) {
            childrenDiv.style.display = 'block';
            toggle.classList.add('expanded');
        }
    });
}

function collapseAllTreeNodes() {
    document.querySelectorAll('.smw-tree-toggle').forEach(function(toggle) {
        var childrenDiv = toggle.parentElement.nextElementSibling;
        if (childrenDiv && childrenDiv.classList.contains('smw-tree-children')) {
            childrenDiv.style.display = 'none';
            toggle.classList.remove('expanded');
        }
    });
}

$(document).ready(function () {
  $('.collapsible-tree').each(function () {
    const $tree = $(this);
    const expandLevel = $tree.data('expand-level'); // 'all', 'none', or a number (1, 2, etc.)

    // Iterate each LI that contains a UL as immediate child
    $tree.find('ul li:has(> ul)').each(function () {
      const $parentLi = $(this);
      const $subUl = $parentLi.children('ul');
      const $toggleIcon = $('<i class="js-toggle-icon">+</i>');

      // Calculate the depth level of this item (1 = first level, 2 = second level, etc.)
      const depth = $parentLi.parents('ul').length;

      // Add class for styling and prepend toggle icon
      $parentLi.addClass('has-children').prepend($toggleIcon);

      // Determine if this item should be expanded based on expand-level
      let shouldExpand = false;

      if (expandLevel === 'all') {
        shouldExpand = true;
      } else if (expandLevel === 'none' || expandLevel === undefined) {
        shouldExpand = false;
      } else if (typeof expandLevel === 'number' || !isNaN(expandLevel)) {
        shouldExpand = depth <= parseInt(expandLevel);
      }

      // Set initial state
      if (shouldExpand) {
        $toggleIcon.text('−');
        $subUl.show();
      } else {
        $toggleIcon.text('+');
        $subUl.hide();
      }

      // Attach event handler to the toggle icon
      $toggleIcon.on('click', function (e) {
        e.stopPropagation();
        const isCollapsed = $(this).text() === '+';
        $(this).text(isCollapsed ? '−' : '+');
        $subUl.slideToggle(200);
      });
    });

    // After the initial expand-level setup, expand the path to the current page.
    // MediaWiki marks the current page as <a class="mw-selflink selflink">.
    const $selfLink = $tree.find('a.mw-selflink.selflink');
    if ($selfLink.length) {
      // Walk up through all ancestor LIs that have children (i.e. have a toggle icon)
      $selfLink.parents('li.has-children').each(function () {
        const $li = $(this);
        const $toggleIcon = $li.children('i.js-toggle-icon');
        const $subUl = $li.children('ul');

        // Force-expand regardless of what expand-level set
        $toggleIcon.text('−');
        $subUl.show();
      });

      // Also mark the selflink's direct LI as the active item for styling purposes
      $selfLink.closest('li').addClass('current-page');
    }
  });
});

// Copy permalink to clipboard
function copyPermalinkToClipboard() {
    var revisionId = mw.config.get('wgRevisionId');
    var pageTitle = mw.config.get('wgPageName');
    var permalink = mw.config.get('wgServer') + mw.config.get('wgScriptPath') + '/index.php?title=' + encodeURIComponent(pageTitle) + '&oldid=' + revisionId;
    
    navigator.clipboard.writeText(permalink).then(function() {
        mw.notify('Permalink copied to clipboard!', { type: 'success' });
    }).catch(function(err) {
        mw.notify('Failed to copy permalink', { type: 'error' });
    });
}

// Attach to elements with class 'copy-permalink'
$(document).ready(function() {
    $(document).on('click', '.copy-permalink', function(e) {
        e.preventDefault();
        copyPermalinkToClipboard();
    });
});