1(function(window, document, $) { 2 'use strict'; 3 4 if (!$) return; 5 6 var state = { 7 initialized: false, 8 beaconTimer: null, 9 beaconNode: null 10 }; 11 12 function isIOSDevice() { 13 var userAgent = window.navigator && window.navigator.userAgent ? window.navigator.userAgent : ''; 14 var platform = window.navigator && window.navigator.platform ? window.navigator.platform : ''; 15 var maxTouchPoints = window.navigator && typeof window.navigator.maxTouchPoints === 'number' ? window.navigator.maxTouchPoints : 0; 16 17 return /iPad|iPhone|iPod/.test(userAgent) || (platform === 'MacIntel' && maxTouchPoints > 1); 18 } 19 20 function formatLikeCount(count) { 21 var value = parseInt(count, 10) || 0; 22 return value.toLocaleString('en-US'); 23 } 24 25 function getLikeWidgetState($widget) { 26 return { 27 liked: $widget.hasClass('is-liked'), 28 count: parseInt($widget.find('.unwire-like-count').first().text().replace(/,/g, ''), 10) || 0 29 }; 30 } 31 32 function resolveRootScope($scope) { 33 return ($scope && $scope.length) ? $scope : $(document); 34 } 35 36 function resolveRefreshScope($widget) { 37 var $article = $widget.closest('.main-article'); 38 return $article.length ? $article : $(document); 39 } 40 41 function getCommentBeaconLines() { 42 var fallback = [ 43 'iOS ç¨å®¶æ³¨æ :', 44 'æä½ ð¬ ä¸ç§', 45 'é¸ã卿°åé éåã' 46 ]; 47 48 if (!window.unwire_like_settings || !$.isArray(window.unwire_like_settings.comment_beacon_lines)) { 49 return fallback; 50 } 51 52 var lines = $.map(window.unwire_like_settings.comment_beacon_lines, function(line) { 53 line = typeof line === 'string' ? $.trim(line) : ''; 54 return line ? line : null; 55 }); 56 57 return lines.length ? lines : fallback; 58 } 59 60 function getCommentBeacon() { 61 if (state.beaconNode) { 62 return state.beaconNode; 63 } 64 65 var beacon = document.createElement('div'); 66 var lines = getCommentBeaconLines(); 67 beacon.className = 'unwire-comment-beacon'; 68 beacon.setAttribute('aria-live', 'polite'); 69 beacon.setAttribute('aria-atomic', 'true'); 70 beacon.style.position = 'fixed'; 71 beacon.style.zIndex = '9999'; 72 beacon.style.maxWidth = 'min(19rem, calc(100vw - 1.5rem))'; 73 beacon.style.padding = '0.95rem 1rem 0.9rem'; 74 beacon.style.borderRadius = '16px'; 75 beacon.style.background = 'rgba(16, 18, 20, 0.94)'; 76 beacon.style.color = '#ffffff'; 77 beacon.style.fontSize = '16px'; 78 beacon.style.fontWeight = '700'; 79 beacon.style.lineHeight = '1.4'; 80 beacon.style.letterSpacing = '0.01em'; 81 beacon.style.boxShadow = '0 18px 36px rgba(0, 0, 0, 0.28)'; 82 beacon.style.border = '1px solid rgba(255,255,255,0.12)'; 83 beacon.style.opacity = '0'; 84 beacon.style.pointerEvents = 'none'; 85 beacon.style.transform = 'translate3d(-50%, -92%, 0) scale(0.96)'; 86 beacon.style.transition = 'opacity 180ms ease, transform 180ms ease'; 87 beacon.style.textAlign = 'left'; 88 beacon.style.display = 'none'; 89 beacon.innerHTML = $.map(lines, function(line) { 90 return '<span style="display:block;">' + $('<div>').text(line).html() + '</span>'; 91 }).join(''); 92 document.body.appendChild(beacon); 93 state.beaconNode = beacon; 94 95 return beacon; 96 } 97 98 function showCommentBeacon(target, event) { 99 if (!target || !target.getBoundingClientRect) return; 100 101 var beacon = getCommentBeacon(); 102 var rect = target.getBoundingClientRect(); 103 var viewportWidth = window.innerWidth || document.documentElement.clientWidth || 0; 104 var originalEvent = event && event.originalEvent ? event.originalEvent : event; 105 var pointX = 0; 106 var pointY = 0; 107 108 beacon.style.display = 'block'; 109 if (originalEvent && originalEvent.changedTouches && originalEvent.changedTouches.length) { 110 pointX = originalEvent.changedTouches[0].clientX; 111 pointY = originalEvent.changedTouches[0].clientY; 112 } else if (originalEvent && typeof originalEvent.clientX === 'number' && typeof originalEvent.clientY === 'number') { 113 pointX = originalEvent.clientX; 114 pointY = originalEvent.clientY; 115 } else { 116 pointX = rect.left + (rect.width / 2); 117 pointY = rect.top + Math.min(rect.height, 26); 118 } 119 120 var beaconRect = beacon.getBoundingClientRect(); 121 var left = pointX + 18; 122 var top = pointY - 92; 123 124 left = Math.max((beaconRect.width / 2) + 12, Math.min(viewportWidth - (beaconRect.width / 2) - 12, left)); 125 top = Math.max(20, top); 126 127 beacon.style.left = Math.round(left) + 'px'; 128 beacon.style.top = Math.round(top) + 'px'; 129 130 window.clearTimeout(state.beaconTimer); 131 window.requestAnimationFrame(function() { 132 beacon.style.opacity = '1'; 133 beacon.style.transform = 'translate3d(-50%, -100%, 0) scale(1)'; 134 }); 135 136 state.beaconTimer = window.setTimeout(function() { 137 beacon.style.opacity = '0'; 138 beacon.style.transform = 'translate3d(-50%, -92%, 0) scale(0.96)'; 139 window.setTimeout(function() { 140 beacon.style.display = 'none'; 141 }, 180); 142 }, 3000); 143 } 144 145 function applyLikeSummaryToPost(postId, summary, $scope) { 146 if (!postId || !summary) return; 147
148 var widgetSelector = '.unwire-like-widget[data-post-id="' + postId + '"]'; 149 var $widgets = ($scope && $scope.length) ? $scope.find(widgetSelector) : $(widgetSelector); 150 if (!$widgets.length && $scope && $scope.length) { 151 $widgets = $(widgetSelector); 152 } 153 154 $widgets.each(function() { 155 var $widget = $(this); 156 var liked = !!summary.liked; 157 var count = parseInt(summary.count, 10) || 0; 158 var $button = $widget.find('.unwire-like-button').first(); 159 var $label = $widget.find('.unwire-like-button-label').first(); 160 var $counts = $widget.find('.unwire-like-count'); 161 var $countLabel = $widget.find('.unwire-like-count-label').first(); 162 163 $widget.attr('data-loaded', '1'); 164 $widget.toggleClass('is-liked', liked).removeClass('is-busy'); 165 if ($widget.hasClass('unwire-like-widget-preview-card')) { 166 $widget.toggleClass('is-zero-count', count === 0); 167 } 168 $button.attr('aria-pressed', liked ? 'true' : 'false'); 169 if ($label.length) { 170 $label.text(liked ? unwire_like_settings.labels.liked : unwire_like_settings.labels.like); 171 } 172 if ($counts.length) { 173 $counts.text(formatLikeCount(count)); 174 } 175 if ($countLabel.length) { 176 $countLabel.text(unwire_like_settings.labels.count_suffix); 177 } 178 }); 179 } 180 181 function applyCommentSummaryToPost(postId, summary, $scope) { 182 if (!postId || !summary) return; 183 184 var commentCount = parseInt(summary.comment_count, 10) || 0; 185 var commentUrl = summary.comment_url || ''; 186 var commentRel = summary.comment_rel || 'nofollow noopener noreferrer external'; 187 var hasCommentUrl = !!summary.has_comment_url; 188 var isCommentEnabled = hasCommentUrl && commentCount > 0; 189 var linkSelector = '.single-post-preview-chat-dummy[data-post-id="' + postId + '"], .post-footer-comments-button[data-post-id="' + postId + '"], .homepage-latest-comment-link[data-post-id="' + postId + '"]'; 190 var $links = ($scope && $scope.length) ? $scope.find(linkSelector) : $(linkSelector); 191 if (!$links.length && $scope && $scope.length) { 192 $links = $(linkSelector); 193 } 194 195 $links.each(function() { 196 var $link = $(this); 197 var $count = $link.find('.single-post-preview-chat-dummy-count, .post-footer-comments-button-count, .homepage-latest-comment-count').first(); 198 199 $link.attr('data-comment-url', commentUrl); 200 $link.attr('data-has-comment-url', hasCommentUrl ? '1' : '0'); 201 202 if ($count.length) { 203 $count.text(formatLikeCount(commentCount)); 204 } 205 206 if (isCommentEnabled) { 207 $link.attr({ 208 href: commentUrl, 209 target: '_blank', 210 rel: commentRel 211 }).removeAttr('aria-disabled tabindex').css('pointer-events', ''); 212 } else { 213 $link.attr({ 214 href: '#', 215 'aria-disabled': 'true', 216 tabindex: '-1' 217 }).removeAttr('target rel').css('pointer-events', ''); 218 } 219 220 $link.prop('hidden', false).css('display', ''); 221 $link.toggleClass('is-zero-count', commentCount <= 0); 222 $link.toggleClass('is-disabled', !isCommentEnabled); 223 }); 224 } 225 226 function applyInitialCommentVisibility($scope) { 227 var $root = resolveRootScope($scope); 228 var linkSelector = '.single-post-preview-chat-dummy[data-post-id], .post-footer-comments-button[data-post-id], .homepage-latest-comment-link[data-post-id]'; 229 var $links = $root.find(linkSelector); 230 231 if (!$links.length && $root[0] !== document) { 232 $links = $(linkSelector); 233 } 234 235 $links.each(function() { 236 var $link = $(this); 237 var postId = parseInt($link.data('postId'), 10) || 0; 238 var commentCount = parseInt($link.find('.single-post-preview-chat-dummy-count, .post-footer-comments-button-count, .homepage-latest-comment-count').first().text().replace(/,/g, ''), 10) || 0; 239 var commentUrl = $link.attr('data-comment-url') || ''; 240 var hasCommentUrl = $link.attr('data-has-comment-url') === '1'; 241 242 applyCommentSummaryToPost(postId, { 243 comment_count: commentCount, 244 comment_url: commentUrl, 245 comment_rel: $link.attr('rel') || 'nofollow noopener noreferrer external', 246 has_comment_url: hasCommentUrl 247 }, $root); 248 }); 249 } 250 251 function refresh($scope) { 252 var $root = resolveRootScope($scope); 253 var ids = []; 254 255 $root.find('.unwire-like-widget').each(function() { 256 var $widget = $(this); 257 var postId = parseInt($widget.data('postId'), 10) || 0; 258 if (!postId || $widget.attr('data-loaded') === '1' || $widget.hasClass('is-busy')) return; 259 ids.push(postId); 260 $widget.addClass('is-busy'); 261 }); 262 263 ids = $.grep(ids, function(value, index) { 264 return $.inArray(value, ids) === index; 265 }); 266 267 if (!ids.length) return; 268 269 $.ajax({ 270 method: 'POST', 271 dataType: 'json', 272 url: ajax_object.ajax_url, 273 data: { 274 action: 'unwire_get_like_summary', 275 post_ids: ids, 276 nonce: unwire_like_settings.nonce 277 } 278 }).done(function(response) { 279 if (!response || !response.success || !response.data || !response.data.summaries) return; 280 281 $.each(response.data.summaries, function(postId, summary) { 282 applyLikeSummaryToPost(postId, summary, $root); 283 applyCommentSummaryToPost(postId, summary, $root); 284 }); 285 }).always(function() { 286 var busySelector = '.unwire-like-widget'; 287 var $busyWidgets = $root.find(busySelector); 288 if (!$busyWidgets.length && $root[0] !== document) { 289 $busyWidgets = $('.unwire-like-widget'); 290 } 291 292 $.each(ids, function(_, postId) { 293 $busyWidgets.filter('[data-post-id="' + postId + '"]').removeClass('is-busy'); 294 }); 295 }); 296 } 297 298 function bindEvents() { 299 $('body').on('click.unwire-like-disabled', '.single-post-preview-chat-dummy[aria-disabled="true"], .post-footer-comments-button[aria-disabled="true"], .homepage-latest-comment-link[aria-disabled="true"]', function(event) { 300 event.preventDefault(); 301 }); 302 303 $('body').on('click.unwire-comment-beacon', '.single-post-preview-chat-dummy, .post-footer-comments-button, .homepage-latest-comment-link', function(event) { 304 var href = this.getAttribute('href') || ''; 305 306 if (!isIOSDevice()) return; 307 if (this.getAttribute('aria-disabled') === 'true') return; 308 if (!href || href === '#') return; 309 310 event.preventDefault(); 311 showCommentBeacon(this, event); 312 }); 313 314 $('body').on('click.unwire-like-toggle', '.unwire-like-button', function() { 315 var $button = $(this); 316 var $widget = $button.closest('.unwire-like-widget'); 317 var postId = parseInt($widget.data('postId'), 10) || 0; 318 var currentState = getLikeWidgetState($widget); 319 var nextLiked = !currentState.liked; 320 var nextCount = currentState.count + (nextLiked ? 1 : -1); 321 var $refreshScope = resolveRefreshScope($widget); 322 323 if (!postId || $widget.hasClass('is-busy')) return; 324 325 nextCount = Math.max(0, nextCount); 326 $widget.addClass('is-busy'); 327 applyLikeSummaryToPost(postId, { 328 liked: nextLiked, 329 count: nextCount 330 }); 331 332 $.ajax({ 333 method: 'POST', 334 dataType: 'json', 335 url: ajax_object.ajax_url, 336 data: { 337 action: 'unwire_toggle_like', 338 post_id: postId, 339 liked: nextLiked ? 1 : 0, 340 nonce: unwire_like_settings.nonce 341 } 342 }).done(function(response) { 343 if (!response || !response.success || !response.data) { 344 applyLikeSummaryToPost(postId, currentState); 345 refresh($refreshScope); 346 return; 347 } 348 applyLikeSummaryToPost(postId, response.data); 349 }).fail(function() { 350 applyLikeSummaryToPost(postId, currentState); 351 refresh($refreshScope); 352 }).always(function() { 353 $widget.removeClass('is-busy'); 354 }); 355 }); 356 } 357
358 function init() { 359 if (state.initialized) return; 360 bindEvents(); 361 applyInitialCommentVisibility($(document)); 362 state.initialized = true; 363 } 364 365 window.UnwireLikeUI = { 366 init: init, 367 refresh: refresh 368 }; 369})(window, document, window.jQuery);
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.