1(function () { 2 'use strict'; 3 4 var config = window.KotobaReactions || {}; 5 6 function request(path, options) { 7 options = options || {}; 8 options.credentials = 'same-origin'; 9 options.headers = options.headers || {}; 10 options.headers.Accept = 'application/json'; 11 if (config.nonce) { 12 options.headers['X-WP-Nonce'] = config.nonce; 13 } 14 return window.fetch(config.restUrl + path, options).then(function (response) { 15 return response.json().catch(function () { return {}; }).then(function (body) { 16 if (!response.ok) { 17 throw new Error(body.message || config.errorMessage); 18 } 19 return body; 20 }); 21 }); 22 } 23 24 function updateWidget(widget, state) { 25 var buttons = widget.querySelectorAll('[data-reaction]'); 26 Array.prototype.forEach.call(buttons, function (button) { 27 var selected = button.getAttribute('data-reaction') === state.selected; 28 button.classList.toggle('is-selected', selected); 29 button.setAttribute('aria-pressed', selected ? 'true' : 'false'); 30 var count = button.querySelector('[data-count]'); 31 if (state.results_visible && state.counts && count) { 32 count.textContent = String(state.counts[button.getAttribute('data-reaction')] || 0); 33 count.hidden = false; 34 } else if (count) { 35 count.hidden = true; 36 } 37 }); 38 widget.classList.toggle('has-results', !!state.results_visible); 39 } 40 41 function setBusy(widget, busy) { 42 widget.classList.toggle('is-loading', busy); 43 Array.prototype.forEach.call(widget.querySelectorAll('button'), function (button) { 44 button.disabled = busy; 45 }); 46 } 47 48 function initWidget(widget) { 49 if (widget.getAttribute('data-initialized') === 'true') { 50 return; 51 } 52 widget.setAttribute('data-initialized', 'true'); 53 var postId = widget.getAttribute('data-post-id'); 54 var feedback = widget.querySelector('[data-feedback]'); 55 56 request('post/' + encodeURIComponent(postId)).then(function (state) { 57 updateWidget(widget, state); 58 }).catch(function () { 59 /* Le vote reste disponible si la lecture de l'état échoue. */ 60 }); 61 62 widget.addEventListener('click', function (event) { 63 var button = event.target.closest ? event.target.closest('[data-reaction]') : null; 64 if (!button || !widget.contains(button) || button.disabled) { 65 return; 66 } 67 68 setBusy(widget, true); 69 if (feedback) { 70 feedback.textContent = ''; 71 } 72 request('vote', { 73 method: 'POST', 74 headers: { 'Content-Type': 'application/json' }, 75 body: JSON.stringify({ post_id: Number(postId), reaction: button.getAttribute('data-reaction') }) 76 }).then(function (state) { 77 updateWidget(widget, state); 78 if (feedback) { 79 feedback.textContent = config.thanks || 'Merci pour votre réaction !'; 80 } 81 }).catch(function (error) { 82 if (feedback) { 83 feedback.textContent = error.message || config.errorMessage; 84 } 85 }).then(function () { 86 setBusy(widget, false); 87 }); 88 }); 89 } 90 91 function initAll(root) { 92 Array.prototype.forEach.call((root || document).querySelectorAll('[data-kr-widget]'), initWidget); 93 } 94 95 if (document.readyState === 'loading') { 96 document.addEventListener('DOMContentLoaded', function () { initAll(document); }); 97 } else { 98 initAll(document); 99 } 100 101 /* Certaines applications mobiles réinjectent le contenu sans recharger la page. */ 102 if (window.MutationObserver) { 103 new MutationObserver(function (mutations) { 104 mutations.forEach(function (mutation) { 105 Array.prototype.forEach.call(mutation.addedNodes || [], function (node) { 106 if (node.nodeType === 1) { 107 if (node.matches && node.matches('[data-kr-widget]')) { 108 initWidget(node); 109 } 110 initAll(node); 111 } 112 }); 113 }); 114 }).observe(document.documentElement, { childList: true, subtree: true }); 115 } 116}()); 117
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.