summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--.github/PULL_REQUEST_TEMPLATE.md (renamed from .github/PULL_REQUEST_TEMPLATE.yml)0
-rw-r--r--assets/js/rss-feed-preview.js397
-rw-r--r--links.md4
-rw-r--r--sitemap.xsl2
4 files changed, 181 insertions, 222 deletions
diff --git a/.github/PULL_REQUEST_TEMPLATE.yml b/.github/PULL_REQUEST_TEMPLATE.md
index f595bc4..f595bc4 100644
--- a/.github/PULL_REQUEST_TEMPLATE.yml
+++ b/.github/PULL_REQUEST_TEMPLATE.md
diff --git a/assets/js/rss-feed-preview.js b/assets/js/rss-feed-preview.js
index 2929622..30af324 100644
--- a/assets/js/rss-feed-preview.js
+++ b/assets/js/rss-feed-preview.js
@@ -2,235 +2,196 @@
  * RSS/Atom Feed Preview for Links Table
  */
 
-(function() {
-    const existingPreviews = document.querySelectorAll('#rss-feed-preview');
-    existingPreviews.forEach(el => el.remove());
-  
-    const CORS_PROXY = 'https://cors-anywhere.mayx.eu.org/?';
-  
-    const createPreviewElement = () => {
-      const existingPreview = document.getElementById('rss-feed-preview');
-      if (existingPreview) {
-        return existingPreview;
-      }
-  
-      const previewEl = document.createElement('div');
-      previewEl.id = 'rss-feed-preview';
-      previewEl.style.cssText = `
-        position: fixed;
-        display: none;
-        width: 300px;
-        max-height: 400px;
-        overflow-y: auto;
-        background-color: white;
-        border: 1px solid #ccc;
-        border-radius: 5px;
-        padding: 10px;
-        box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
-        z-index: 1000;
-        font-size: 14px;
-        line-height: 1.4;
-      `;
-      document.body.appendChild(previewEl);
-      return previewEl;
-    };
-  
-    const parseRSS = (xmlText) => {
-      const parser = new DOMParser();
-      const xml = parser.parseFromString(xmlText, 'text/xml');
-  
-      const rssItems = xml.querySelectorAll('item');
-      if (rssItems.length > 0) {
-        return Array.from(rssItems).slice(0, 5).map(item => {
-          return {
-            title: item.querySelector('title')?.textContent || 'No title',
-            date: item.querySelector('pubDate')?.textContent || 'No date',
-          };
-        });
-      }
-  
-      const atomItems = xml.querySelectorAll('entry');
-      if (atomItems.length > 0) {
-        return Array.from(atomItems).slice(0, 5).map(item => {
-          return {
-            title: item.querySelector('title')?.textContent || 'No title',
-            date: item.querySelector('updated')?.textContent || 'No date',
-          };
-        });
-      }
-  
-      return null;
-    };
-  
-    const checkFeed = async (url) => {
-      try {
-        const response = await fetch(CORS_PROXY + url);
-        if (!response.ok) {
-          return null;
-        }
-  
-        const text = await response.text();
-        return parseRSS(text);
-      } catch (error) {
-        return null;
-      }
-    };
-  
-    const findFeedUrl = async (siteUrl, linkElement) => {
-      if (linkElement && linkElement.hasAttribute('data-feed')) {
-        const dataFeedUrl = linkElement.getAttribute('data-feed');
-        if (dataFeedUrl) {
-          const feedItems = await checkFeed(dataFeedUrl);
-          if (feedItems) {
-            return { url: dataFeedUrl, items: feedItems };
-          }
-        }
-      }
-  
-      return null;
-    };
-  
-    const escapeHTML = (str) => {
-      return String(str).replace(/[&<>"'/]/g, (c) => ({
+(function () {
+  if (window.rssFeedPreviewInitialized)
+    return;
+  window.rssFeedPreviewInitialized = true;
+
+  var CORS_PROXY = 'https://cors-anywhere.mayx.eu.org/?';
+
+  var $previewEl = $('<div>', {
+    id: 'rss-feed-preview'
+  }).css({
+    position: 'fixed',
+    display: 'none',
+    width: '300px',
+    maxHeight: '400px',
+    overflowY: 'auto',
+    backgroundColor: 'white',
+    border: '1px solid #ccc',
+    borderRadius: '5px',
+    padding: '10px',
+    fontSize: '14px',
+    lineHeight: '1.4',
+    zIndex: 1000,
+    boxShadow: '0 2px 10px rgba(0,0,0,0.1)'
+  });
+
+  $('body').append($previewEl);
+
+  function escapeHTML(str) {
+    return String(str).replace(/[&<>"']/g, function (c) {
+      return {
         '&': '&amp;',
         '<': '&lt;',
         '>': '&gt;',
         '"': '&quot;',
-        "'": '&#39;',
-        '/': '&#x2F;'
-      }[c]));
-    };
-
-    const renderFeedItems = (previewEl, items, siteName) => {
-      if (!items || items.length === 0) {
-        previewEl.innerHTML = '<p>No feed items found.</p>';
-        return;
-      }
-  
-      let html = `<h3>Latest from ${siteName}</h3><ul style="list-style: none; padding: 0; margin: 0;">`;
-  
-      items.forEach(item => {
-        const safeTitle = escapeHTML(item.title);
-        const safeDate = escapeHTML(new Date(item.date).toLocaleDateString());
-        html += `
-          <li style="margin-bottom: 10px; padding-bottom: 10px; border-bottom: 1px solid #eee;">
-            <div style="color: #24292e; font-weight: bold;">
-              ${safeTitle}
-            </div>
-            <div style="color: #586069; font-size: 12px; margin: 3px 0;">
-              ${safeDate}
-            </div>
-          </li>
-        `;
+        "'": '&#39;'
+      }[c];
+    });
+  }
+
+  function parseRSS(xmlText) {
+    var xml;
+    try {
+      xml = $.parseXML(xmlText);
+    } catch (e) {
+      return [];
+    }
+
+    var $xml = $(xml);
+    var $items = $xml.find('item');
+    if (!$items.length)
+      $items = $xml.find('entry');
+
+    var result = [];
+    $items.slice(0, 5).each(function () {
+      var $el = $(this);
+      result.push({
+        title: $el.find('title').text() || 'No title',
+        date: $el.find('pubDate, updated').text() || 'No date'
       });
-  
-      html += '</ul>';
-      previewEl.innerHTML = html;
-    };
-  
-    const positionPreview = (previewEl, event) => {
-      const viewportWidth = window.innerWidth;
-      const viewportHeight = window.innerHeight;
-  
-      let left = event.clientX + 20;
-      let top = event.clientY + 20;
-  
-      const rect = previewEl.getBoundingClientRect();
-  
-      if (left + rect.width > viewportWidth) {
-        left = event.clientX - rect.width - 20;
-      }
-  
-      if (top + rect.height > viewportHeight) {
-        top = event.clientY - rect.height - 20;
+    });
+
+    return result;
+  }
+
+  function checkFeed(url, callback) {
+    $.ajax({
+      url: CORS_PROXY + url,
+      type: 'GET',
+      dataType: 'text',
+      success: function (data) {
+        var items = parseRSS(data);
+        callback(items);
+      },
+      error: function () {
+        callback(null);
       }
-  
-      left = Math.max(10, left);
-      top = Math.max(10, top);
-  
-      previewEl.style.left = `${left}px`;
-      previewEl.style.top = `${top}px`;
-    };
-  
-    const initFeedPreview = () => {
-      const previewEl = createPreviewElement();
-  
-      const tableLinks = document.querySelectorAll('main table tbody tr td a');
-  
-      const feedCache = {};
-  
-      let currentLink = null;
-      let loadingTimeout = null;
-  
-      tableLinks.forEach(link => {
-        link.addEventListener('mouseenter', async (event) => {
-          currentLink = link;
-          const url = link.getAttribute('href');
-          const siteName = link.textContent;
-  
-          previewEl.innerHTML = '<p>Checking for RSS/Atom feed...</p>';
-          previewEl.style.display = 'block';
-          positionPreview(previewEl, event);
-  
-          if (loadingTimeout) {
-            clearTimeout(loadingTimeout);
+    });
+  }
+
+  function renderFeedItems(items, siteName) {
+    if (!items || !items.length) {
+      $previewEl.html('<p>No feed items found.</p>');
+      return;
+    }
+
+    var html = '<h3>Latest from ' + escapeHTML(siteName) + '</h3><ul style="list-style:none; padding:0; margin:0;">';
+    for (var i = 0; i < items.length; i++) {
+      var item = items[i];
+      var dateStr = new Date(item.date).toLocaleDateString();
+      html += '<li style="margin-bottom:10px; padding-bottom:10px; border-bottom:1px solid #eee;">' +
+        '<div style="color:#24292e; font-weight:bold;">' + escapeHTML(item.title) + '</div>' +
+        '<div style="color:#586069; font-size:12px; margin:3px 0;">' + escapeHTML(dateStr) + '</div>' +
+        '</li>';
+    }
+    html += '</ul>';
+    $previewEl.html(html);
+  }
+
+  function positionPreview(e) {
+    e = e || window.event;
+
+    var x = e.clientX;
+    var y = e.clientY;
+
+    var offsetWidth = $previewEl.outerWidth();
+    var offsetHeight = $previewEl.outerHeight();
+
+    var left = x + 20;
+    var top = y + 20;
+
+    if (left + offsetWidth > $(window).width()) {
+      left = x - offsetWidth - 20;
+    }
+    if (top + offsetHeight > $(window).height()) {
+      top = y - offsetHeight - 20;
+    }
+
+    $previewEl.css({
+      left: Math.max(10, left),
+      top: Math.max(10, top)
+    });
+  }
+
+
+  function init() {
+    var cache = {};
+    var currentLink = null;
+    var timeout = null;
+
+    $('main table tbody tr td a').each(function () {
+      var $link = $(this);
+
+      $link.on('mouseenter', function (e) {
+        currentLink = this;
+        var siteName = $link.text();
+        var url = $link.attr('data-feed');
+        if (!url)
+          return;
+
+        $previewEl.html('<p>Checking for RSS/Atom feed...</p>').show();
+        positionPreview(e);
+
+        if (timeout)
+          clearTimeout(timeout);
+        timeout = setTimeout(function () {
+          if (cache[url]) {
+            renderFeedItems(cache[url], siteName);
+            positionPreview(e);
+            return;
           }
-  
-          loadingTimeout = setTimeout(async () => {
-            if (feedCache[url]) {
-              renderFeedItems(previewEl, feedCache[url].items, siteName);
-              positionPreview(previewEl, event); // Reposition after content is loaded
-              return;
-            }
-  
-            const feedData = await findFeedUrl(url, link);
-  
-            if (currentLink === link) {
-              if (feedData) {
-                feedCache[url] = feedData;
-                renderFeedItems(previewEl, feedData.items, siteName);
-                positionPreview(previewEl, event); // Reposition after content is loaded
+
+          if (url) {
+            checkFeed(url, function (items) {
+              if (currentLink === $link[0] && items) {
+                cache[url] = items;
+                renderFeedItems(items, siteName);
+                positionPreview(e);
               } else {
-                previewEl.style.display = 'none';
+                $previewEl.hide();
               }
-            }
-          }, 300);
-        });
-  
-        link.addEventListener('mousemove', (event) => {
-          if (previewEl.style.display === 'block') {
-            window.requestAnimationFrame(() => {
-              positionPreview(previewEl, event);
             });
+          } else {
+            $previewEl.hide();
           }
-        });
-  
-        link.addEventListener('mouseleave', () => {
-          if (loadingTimeout) {
-            clearTimeout(loadingTimeout);
-            loadingTimeout = null;
-          }
-  
-          currentLink = null;
-          previewEl.style.display = 'none';
-        });
+        }, 300);
       });
-  
-      document.addEventListener('click', (event) => {
-        if (!previewEl.contains(event.target)) {
-          previewEl.style.display = 'none';
-        }
+
+      $link.on('mousemove', function (e) {
+        if ($previewEl.is(':visible'))
+          positionPreview(e);
       });
-    };
-  
-    if (!window.rssFeedPreviewInitialized) {
-      window.rssFeedPreviewInitialized = true;
-  
-      if (document.readyState === 'loading') {
-        document.addEventListener('DOMContentLoaded', initFeedPreview);
-      } else {
-        initFeedPreview();
+
+      $link.on('mouseleave', function () {
+        clearTimeout(timeout);
+        timeout = null;
+        currentLink = null;
+        $previewEl.hide();
+      });
+    });
+
+    $(document).on('click', function (e) {
+      if (!$(e.target).closest('#rss-feed-preview').length) {
+        $previewEl.hide();
       }
-    }
-  })();
-  
\ No newline at end of file
+    });
+  }
+
+  if (document.readyState === 'complete' || document.readyState === 'interactive') {
+    init();
+  } else {
+    $(document).ready(init);
+  }
+})();
diff --git a/links.md b/links.md
index 6a9c5d3..8d07260 100644
--- a/links.md
+++ b/links.md
@@ -29,6 +29,4 @@ tags: [links]
 头像:<https://avatars0.githubusercontent.com/u/17966333>   
 Logo:<https://mabbs.github.io/favicon.ico>
 
-<!--[if !IE]> -->
-<script src="/assets/js/rss-feed-preview.js"></script>
-<!-- <![endif]-->
\ No newline at end of file
+<script src="/assets/js/rss-feed-preview.js"></script>
\ No newline at end of file
diff --git a/sitemap.xsl b/sitemap.xsl
index 256704b..4485c3b 100644
--- a/sitemap.xsl
+++ b/sitemap.xsl
@@ -11,7 +11,7 @@ title: Sitemap
       <li>
         <a>
           <xsl:attribute name="href"><xsl:value-of select="sm:loc" /></xsl:attribute>
-            <xsl:value-of select="sm:loc" />
+          <xsl:value-of select="sm:loc" />
         </a>
       </li>
     </xsl:for-each>