1/** 2 * Created by edward on 31.05.17. 3 */ 4'use strict' 5 6// IIFE Immediately Invoked Function Expression is an anonymus function that is executed immediately 7;(function ($, api) { 8 /** 9 * load license information to core image elements 10 */ 11 api.load_licenses = function () { 12 var map = {} 13 var ids = [] 14 $('img').each(function (i, img) { 15 // note: 1. scans all img elements and looks for a wp-image-id css class 16 var id = api.get_image_id(img) 17 if (id) { 18 // always check caption 19 ids.push(id) 20 if (typeof map[id] === typeof undefined) { 21 map[id] = [] 22 } 23 map[id].push(img) 24 } 25 }) 26 27 // get_licenses runs immediately since it is an IIFE 28 // _got_licenses is the registered callback that runs for every result of the get_licenses calls 29 // since get_licenses batches ids of 10 30 31 // fix duplication problem by removing duplicats 32 const sanitizedIds = Array.from(new Set(ids)) 33 api.get_licenses(sanitizedIds).then(_got_licenses) 34 35 /** 36 * build dom from results 37 * @param result 38 * @private 39 */ 40 function _got_licenses(result) { 41 if (result.error) { 42 console.error(result) 43 return 44 } 45 46 if (typeof result.captions === typeof []) { 47 for (var id in result.captions) { 48 if (!result.captions.hasOwnProperty(id)) continue 49 // this loop processes all img that share the same id 50 for (var i in map[id]) { 51 if (!map[id].hasOwnProperty(i)) continue 52 53 var caption = result.captions[id] 54 if (caption.length > 0) { 55 var element = map[id][i] 56 process_image(element, caption) 57 } 58 } 59 } 60 } else { 61 console.error('captions was no array', result) 62 } 63 } 64 65 /** 66 * process image element with caption 67 * @param element 68 * @param caption 69 */ 70 function process_image(element, caption) { 71 var $img = $(element) 72 // jquery converts the data-attribute 'data-media-license-block-flag' to 'mediaLicenseBlockFlag' 73 if ($img.data('mediaLicenseBlockUseDataAttribute')) { 74 add_media_license_as_data_attribute(element, caption) 75 collect_block_data_attributes() 76 return 77 } 78 var $figure = $('<figure></figure>') 79 80 // check parent - 81 if ($img.parent('figure').length === 1) { 82 $figure = $img.parent() 83 } else if ( 84 $img.parent('a').length === 1 && 85 $img.parent().parent('figure').length === 1 86 ) { 87 $figure = $img.parent().parent() 88 } else { 89 $img.wrap($figure) 90 } 91 92 $figure.addClass('media-license__figure') 93 // â $figure now exists 94 95 // take over alignment 96 if ($img.hasClass('alignright')) { 97 $figure.addClass('alignright') 98 $img.removeClass('alignright') 99 } 100 if ($img.hasClass('alignleft')) { 101 $figure.addClass('alignleft') 102 $img.removeClass('alignleft') 103 } 104 if ($img.hasClass('aligncenter')) { 105 $figure.addClass('aligncenter') 106 $img.removeClass('aligncenter') 107 } 108 109 const $originalCaption = $figure.find('figcaption') 110 111 console.debug('ML', $originalCaption) 112 113 if ($figure.find('figcaption').length === 0) { 114 console.debug('ML', 'figcaption not found') 115 var $caption = $( 116 '<figcaption>' + caption + '</figcaption>' 117 ).addClass('wp-caption-text media-license__figcaption') 118 // image is wrapped with link 119 if ($img.parent('a').length === 1) { 120 $img.next('figure').append($caption) 121 } else { 122 $img.after($caption) 123 } 124 } else if ( 125 $originalCaption.text() !== $('<div>').html(caption).text() 126 ) { 127 console.debug( 128 'ML', 129 'figcaption found but not equal!', 130 $originalCaption.text(), 131 $('<div>').html(caption).text() 132 ) 133 134 const originalText = $originalCaption.text().trim() 135 const captionFullText = $('<div>') 136 .html(caption) 137 .text() 138 .trimStart() 139 140 if (captionFullText.startsWith(originalText)) { 141 // Case 3A: same caption, license was added â replace without wrapping 142 $originalCaption 143 .addClass('media-license__figcaption') 144 .html(caption) 145 } else { 146 // Case 3B: genuinely different captions â keep block caption, append only license info
147 const $captionDiv = $('<div>').html(caption) 148 // Strip the attachment caption: remove the caption span (plugin template) 149 // and any root-level text nodes (theme template) 150 $captionDiv.find('.media-license__caption').remove() 151 $captionDiv 152 .contents() 153 .filter(function () { 154 return this.nodeType === 3 155 }) 156 .remove() 157 const licenseHtml = $captionDiv.html() 158 159 $originalCaption 160 .addClass('media-license__figcaption') 161 .append(licenseHtml) 162 } 163 } 164 165 if ($figure.find('.media-license__local-figcaption').length > 0) { 166 $figure.addClass('has-local-caption') 167 } 168 if ($figure.find('.media-license__caption').length > 0) { 169 $figure.addClass('has-caption') 170 } 171 } 172 } 173 174 function add_media_license_as_data_attribute(element, caption) { 175 element.setAttribute('data-media-license-caption', caption) 176 } 177 178 function collect_block_data_attributes() { 179 const container = document.getElementById( 180 'media-license-footer-container' 181 ) 182 if (!container) return 183 184 const imgs = Array.from( 185 document.querySelectorAll('img[data-media-license-caption]') 186 ) 187 188 // Deduplicate by attachment id (wp-image-123) if possible, else by image URL 189 const seen = new Set() 190 const collectedItems = [] 191 192 imgs.forEach((img) => { 193 const id = MediaLicense_API.get_image_id(img) // uses your existing helper 194 const src = img.currentSrc || img.getAttribute('src') || '' 195 const key = id ? `id:${id}` : `src:${src}` 196 if (!src) return 197 if (seen.has(key)) return 198 seen.add(key) 199 200 const licenseHtml = ( 201 img.getAttribute('data-media-license-caption') || '' 202 ).trim() 203 if (!licenseHtml) return 204 205 collectedItems.push({ 206 src, 207 alt: img.getAttribute('alt') || '', 208 licenseHtml, 209 }) 210 }) 211 212 if (collectedItems.length === 0) { 213 container.innerHTML = '' 214 return 215 } 216 217 // Build footer HTML 218 const html = collectedItems 219 .map((item) => { 220 return ` 221 <div class="media-license-footer__entry"> 222 <img class="media-license-footer__entry__image" src="${escapeAttr( 223 item.src 224 )}" alt="${escapeAttr(item.alt)}"> 225 <div class="media-license-footer__entry__information"> 226 ${item.licenseHtml} 227 </div> 228 </div> 229 ` 230 }) 231 .join('') 232 233 container.innerHTML = html 234 } 235 236 // Small helper to avoid breaking attributes if URLs/alt contain quotes 237 function escapeAttr(str) { 238 return String(str) 239 .replaceAll('&', '&') 240 .replaceAll('"', '"') 241 .replaceAll('<', '<') 242 .replaceAll('>', '>') 243 } 244 245 /** 246 * get attachment id from wp-image-{id} class 247 * @param img_element 248 * @return {*} 249 */ 250 api.get_image_id = function (img_element) { 251 var matches = null 252 if ((matches = /wp-image-([0-9]+)/g.exec(img_element.className))) { 253 return parseInt(matches[1]) 254 } 255 return false 256 } 257 258 /** 259 * load captions for attachment ids 260 * @param attachment_ids 261 * @return {{then, trigger}} register a callback with then method. could be called several times. 262 */ 263 // note: calls captions() in classes/REST.php 264 api.get_licenses = function (attachment_ids) { 265 // this is also a immediately invoked function expression 266 var promise = (function () { 267 var _cbs = [] 268 269 function _then(cb) { 270 _cbs.push(cb) 271 } 272 273 function _trigger(result) { 274 for (var i = 0; i < _cbs.length; i++) { 275 _cbs[i](result) 276 } 277 } 278 279 return { 280 then: _then, 281 trigger: _trigger, 282 } 283 })() 284 285 while (attachment_ids.length) { 286 // get 10 attachment captions per call
287 var _ids = attachment_ids.splice(0, 10) 288 $.ajax({ 289 method: 'GET', 290 url: api.resturl, 291 data: { 292 ids: _ids, 293 }, 294 }).done(function (result) { 295 promise.trigger(result) 296 }) 297 } 298 299 return promise 300 } 301 302 if (api.autoload) { 303 // auto load license 304 $(function () { 305 api.load_licenses() 306 }) 307 } 308})(jQuery, MediaLicense_API)
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.