1/** 2 * Bluesky Async Loader 3 * Finds skeleton placeholders and replaces them with real content via AJAX. 4 */ 5(function () { 6 "use strict"; 7 8 if (typeof blueskyAsync === "undefined") { 9 return; 10 } 11 12 var ajaxUrl = blueskyAsync.ajaxUrl; 13 var nonce = blueskyAsync.nonce; 14 15 function loadElement(el) { 16 var type = el.getAttribute("data-bluesky-async"); 17 var paramsRaw = el.getAttribute("data-bluesky-params") || "{}"; 18 var action; 19 var body; 20 21 if (type === "posts") { 22 action = "bluesky_async_posts"; 23 } else if (type === "profile") { 24 action = "bluesky_async_profile"; 25 } else if (type === "auth") { 26 action = "bluesky_async_auth"; 27 } else { 28 return; 29 } 30 31 body = new FormData(); 32 body.append("action", action); 33 body.append("nonce", nonce); 34 35 if (type !== "auth") { 36 body.append("params", paramsRaw); 37 } else { 38 // For auth type, extract account_id from params if present 39 var params = JSON.parse(paramsRaw); 40 if (params.account_id) { 41 body.append("account_id", params.account_id); 42 } 43 } 44 45 fetch(ajaxUrl, { 46 method: "POST", 47 credentials: "same-origin", 48 body: body, 49 }) 50 .then(function (response) { 51 return response.json(); 52 }) 53 .then(function (data) { 54 if (!data.success) { 55 showError(el, type); 56 return; 57 } 58 59 if (type === "auth") { 60 handleAuth(el, data.data); 61 } else { 62 // Replace skeleton with server-rendered HTML. 63 // This HTML comes from our own PHP render methods 64 // (same trusted source as initial page render). 65 replaceWithServerHtml(el, data.data.html); 66 } 67 }) 68 .catch(function () { 69 showError(el, type); 70 }); 71 } 72 73 /** 74 * Replace a skeleton element with server-rendered HTML. 75 * The HTML originates from our own PHP rendering pipeline 76 * (BlueSky_Render_Front methods), the same code that produces 77 * the initial page markup â it is a trusted source. 78 */ 79 function replaceWithServerHtml(el, html) { 80 if (!html) return; 81 var range = document.createRange(); 82 range.selectNode(el); 83 var fragment = range.createContextualFragment(html); 84 el.parentNode.replaceChild(fragment, el); 85 } 86 87 function getAuthErrorMessage(error) { 88 if (!error || !error.code) { 89 return blueskyAsync.i18n.connectionFailed; 90 } 91 92 switch (error.code) { 93 case "MissingCredentials": 94 return blueskyAsync.i18n.missingCredentials; 95 case "NetworkError": 96 return ( 97 blueskyAsync.i18n.networkError + " " + 98 (error.message || "network error") + 99 "." 100 ); 101 case "RateLimitExceeded": 102 var msg = blueskyAsync.i18n.rateLimitExceeded; 103 if (error.ratelimit_reset) { 104 var resetDate = new Date( 105 parseInt(error.ratelimit_reset, 10) * 1000 106 ); 107 msg += 108 " " + blueskyAsync.i18n.rateLimitResetsAt + " " + 109 resetDate.toLocaleTimeString() + 110 "."; 111 } 112 return msg; 113 case "AuthFactorTokenRequired": 114 return blueskyAsync.i18n.authFactorRequired; 115 case "AccountTakedown": 116 return blueskyAsync.i18n.accountTakedown; 117 case "AuthenticationRequired": 118 return blueskyAsync.i18n.invalidCredentials; 119 default: 120 // Show the API error code and message for any other error 121 var detail = error.code; 122 if (error.message) { 123 detail += " \u2014 " + error.message; 124 } 125 if (error.status) { 126 detail += " (HTTP " + error.status + ")"; 127 } 128 return blueskyAsync.i18n.connectionFallback + " " + detail; 129 } 130 } 131 132 function handleAuth(el, data) { 133 el.classList.remove("bluesky-async-placeholder"); 134 135 // Clear existing content 136 while (el.firstChild) { 137 el.removeChild(el.firstChild); 138 } 139 140 var p = document.createElement("p"); 141 142 if (data.authenticated) { 143 el.className = 144 "description bluesky-connection-check notice-success"; 145 146 p.textContent = blueskyAsync.i18n.connectionSuccess; 147 p.appendChild(document.createElement("br")); 148 149 var logoutUrl = 150 el.getAttribute("data-bluesky-logout-url") || "#"; 151 var a = document.createElement("a"); 152 a.className = "bluesky-logout-link"; 153 a.href = logoutUrl; 154 a.textContent = blueskyAsync.i18n.logoutLink; 155 p.appendChild(a); 156 } else { 157 el.className = "description bluesky-connection-check notice-error"; 158 p.textContent = getAuthErrorMessage(data.error); 159 } 160 161 el.appendChild(p); 162 } 163 164 function showError(el, type) { 165 el.classList.remove("bluesky-async-placeholder"); 166 if (type === "auth") { 167 el.className = "description bluesky-connection-check notice-error"; 168 while (el.firstChild) { 169 el.removeChild(el.firstChild); 170 } 171 var p = document.createElement("p"); 172 p.textContent = blueskyAsync.i18n.connectionCheckFailed; 173 el.appendChild(p); 174 } else { 175 el.textContent = blueskyAsync.i18n.contentLoadFailed; 176 } 177 } 178 179 document.addEventListener("DOMContentLoaded", function () { 180 var elements = document.querySelectorAll("[data-bluesky-async]"); 181 for (var i = 0; i < elements.length; i++) { 182 loadElement(elements[i]); 183 } 184 }); 185})();
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.