PageSourceSearch

https://sol.vin/js/widgets/gist_widget.js

js sol.vin collected 2026-10-09 21:58:31 UTC 5,650 bytes, 172 lines download raw bytes

1window.GistWidget = (function() {
2  'use strict';
3
4  function getCache(key) {
5    if (window.ApiRateLimiter) {
6      return window.ApiRateLimiter.getCache(key);
7    }
8    try {
9      var data = localStorage.getItem(key);
10      if (!data) return null;
11      var parsed = JSON.parse(data);
12      if (parsed && parsed.timestamp && (Date.now() - parsed.timestamp < (60 * 60 * 1000))) {
13        return parsed.value;
14      }
15    } catch(e) {}
16    return null;
17  }
18
19  function setCache(key, value) {
20    if (window.ApiRateLimiter) {
21      window.ApiRateLimiter.setCache(key, value);
22      return;
23    }
24    try {
25      localStorage.setItem(key, JSON.stringify({
26        timestamp: Date.now(),
27        value: value
28      }));
29    } catch(e) {}
30  }
31
32  function clearCache(key) {
33    if (window.ApiRateLimiter) {
34      window.ApiRateLimiter.clearCache(key);
35      return;
36    }
37    try {
38      localStorage.removeItem(key);
39    } catch(e) {}
40  }
41
42  function renderLoading(element) {
43    if (!element) return;
44    var container = element.querySelector('.project-live-stats');
45    if (!container) {
46      container = document.createElement('span');
47      container.className = 'project-live-stats gist-live-stats';
48      element.appendChild(container);
49    }
50    container.innerHTML = '<span class="stat-chip stat-loading" title="Loading live stats..."><span class="stat-icon" style="-webkit-mask-image: url(\'/icons/hourglass.svg\'); mask-image: url(\'/icons/hourglass.svg\');"></span></span>';
51  }
52
53  function renderError(element, onRetry) {
54    if (!element) return;
55    var container = element.querySelector('.project-live-stats');
56    if (!container) {
57      container = document.createElement('span');
58      container.className = 'project-live-stats gist-live-stats';
59      element.appendChild(container);
60    }
61    container.innerHTML = '<span class="stat-chip stat-error" title="Data Couldn\'t Load (Right-click to retry)"><span class="stat-icon" style="-webkit-mask-image: url(\'/icons/xmark.svg\'); mask-image: url(\'/icons/xmark.svg\');"></span></span>';
62
63    var errChip = container.querySelector('.stat-error');
64    if (errChip && typeof onRetry === 'function') {
65      errChip.addEventListener('contextmenu', function(e) {
66        e.preventDefault();
67        e.stopPropagation();
68        onRetry();
69      });
70    }
71  }
72
73  function render(element, stats) {
74    if (!element || !stats) return;
75    var container = element.querySelector('.project-live-stats');
76    if (!container) {
77      container = document.createElement('span');
78      container.className = 'project-live-stats gist-live-stats';
79      element.appendChild(container);
80    }
81
82    function makeIcon(file) {
83      return '<span class="stat-icon" style="-webkit-mask-image: url(\'/icons/' + file + '\'); mask-image: url(\'/icons/' + file + '\');"></span>';
84    }
85
86    var html = '';
87    if (typeof stats.files === 'number') {
88      html += '<span class="stat-chip stat-files" title="Files">' + makeIcon('file-code.svg') + ' ' + stats.files + ' file' + (stats.files !== 1 ? 's' : '') + '</span>';
89    }
90    if (typeof stats.comments === 'number' && stats.comments > 0) {
91      html += '<span class="stat-chip stat-comments" title="Comments">' + makeIcon('comment.svg') + ' ' + stats.comments + '</span>';
92    }
93    if (typeof stats.forks === 'number' && stats.forks > 0) {
94      html += '<span class="stat-chip stat-forks" title="Forks">' + makeIcon('code-fork.svg') + ' ' + stats.forks + '</span>';
95    }
96    container.innerHTML = html;
97  }
98
99  function fetchGist(gistId, onSuccess, onError) {
100    var baseUrl = (window.ApiRateLimiter && window.ApiRateLimiter.getApiBaseUrl) ? window.ApiRateLimiter.getApiBaseUrl() : '';
101    var proxyUrl = baseUrl + '/api/proxy/gist?id=' + gistId;
102    var taskFn = function() {
103      return fetch(proxyUrl)
104      .then(function(res) {
105        if (!res.ok) throw new Error('API Proxy returned ' + res.status);
106        return res.json();
107      })
108      .then(function(data) {
109        return {
110          files: data.files || 1,
111          comments: data.comments || 0,
112          forks: data.forks || 0
113        };
114      });
115    };
116
117    if (window.ApiRateLimiter) {
118      window.ApiRateLimiter.enqueue(proxyUrl, taskFn, onSuccess, onError);
119    } else {
120      taskFn().then(onSuccess).catch(onError);
121    }
122  }
123
124  function initElement(el) {
125    var gistId = el.getAttribute('data-gist-id');
126    if (!gistId) return;
127
128    var cacheKey = 'solvin_gist_stats_v1_' + gistId;
129    var cached = getCache(cacheKey);
130    if (cached) {
131      render(el, cached);
132      return;
133    }
134
135    renderLoading(el);
136
137    var baseUrl = (window.ApiRateLimiter && window.ApiRateLimiter.getApiBaseUrl) ? window.ApiRateLimiter.getApiBaseUrl() : '';
138    var proxyUrl = baseUrl + '/api/proxy/gist?id=' + gistId;
139
140    function handleRetry() {
141      clearCache(cacheKey);
142      if (window.ApiRateLimiter) {
143        window.ApiRateLimiter.resetDomain(proxyUrl);
144      }
145
146      renderLoading(el);
147      fetchGist(gistId, function(stats) {
148        setCache(cacheKey, stats);
149        render(el, stats);
150      }, function(err) {
151        renderError(el, handleRetry);
152      });
153    }
154
155    fetchGist(gistId, function(stats) {
156      setCache(cacheKey, stats);
157      render(el, stats);
158    }, function(err) {
159      renderError(el, handleRetry);
160    });
161  }
162
163  function init() {
164    var elements = document.querySelectorAll('[data-gist-id]');
165    elements.forEach(function(el) {
166      if (el.classList.contains('fav-collection-item-chip') || (el.closest && el.closest('.fav-collection-item-chip'))) return;
167      initElement(el);
168    });
169  }
170
171  return { init: init, initElement: initElement };
172})();

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.