1/* 2 * ads-numbering.js 3 * ---------------- 4 * Utility to assign sequential numeric IDs to ad slots inserted in the DOM. 5 * 6 * Purpose: 7 * - Keep numbering logic outside of templates so it can be included via 8 * configuration and reused across pages. 9 * - Default target types: ['banner','roba','boton'] but extensible. 10 * 11 * Usage (recommended): include this file in your global assets and invoke 12 * window.assignAdNumbersFromConfig(...) after the page has created/inserted 13 * the ad slots (e.g. after web.html.twig has run or on DOMContentLoaded). 14 * 15 * The script is intentionally conservative: 16 * - It detects existing numbered IDs like 'roba1' and avoids collisions. 17 * - By default it scopes to a rootSelector (you can pass '.c-detail__body') 18 * to avoid numbering sidebar ads. 19 * - If you want a full renumbering ignoring existing numbers, pass 20 * { bumpExisting: true }. 21 * 22 * Author: generated by automation for ED-1344 tasks 23 * Date: 2026-05-28 24 */ 25 26(function (global) { 27 'use strict'; 28 29 // Helper to escape a string for RegExp 30 function escapeRegExp(str) { 31 return String(str).replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); 32 } 33 34 /** 35 * Assign sequential numeric suffixes to ad slots in DOM. 36 * 37 * Behavior: 38 * - Targets elements that either have attribute attr_type="{type}" OR have id equal to "{type}". 39 * - Preserves/considers existing numbered IDs of the form `${type}<number>` to avoid collisions. 40 * - Processes elements in DOM order (visual order). 41 * 42 * @param {Array<string>} types Array of ad types to number, e.g. ['banner','roba','boton'] 43 * @param {Object} opts Optional: 44 * - rootSelector: CSS selector to scope the operation (default: document) 45 * - idAttr: attribute used to hold type on created elements (default: 'attr_type') 46 * - bumpExisting: if true, will renumber existing numbered elements as well (default: false) 47 * 48 * @returns {Object} counters map { banner: 2, roba: 3, ... } 49 */ 50 function assignAdNumbersFromConfig(types, opts) { 51 types = Array.isArray(types) && types.length ? types : ['banner', 'roba', 'boton']; 52 opts = opts || {}; 53 var root = (opts.rootSelector && document.querySelector(opts.rootSelector)) || document; 54 var typeAttr = opts.idAttr || 'attr_type'; 55 var bumpExisting = !!opts.bumpExisting; 56 57 // Prepare counters and detect existing numbered ids 58 var counters = {}; 59 var maxExisting = {}; 60 61 types.forEach(function (t) { 62 counters[t] = 0; 63 maxExisting[t] = 0; 64 }); 65 66 // 1) Scan for existing ids matching type + digits and set maxExisting 67 types.forEach(function (t) { 68 var nodes = document.querySelectorAll('[id^="' + t + '"]'); 69 for (var i = 0; i < nodes.length; i++) { 70 var id = nodes[i].getAttribute('id'); 71 if (!id) continue; 72 var m = id.match(new RegExp('^' + escapeRegExp(t) + '(\\d+)$')); 73 if (m && m[1]) { 74 var n = parseInt(m[1], 10); 75 if (!isNaN(n) && n > maxExisting[t]) maxExisting[t] = n; 76 } 77 } 78 counters[t] = maxExisting[t] || 0; 79 }); 80 81 // 2) Build selector for attr_type / bare-id elements within rootSelector scope 82 var selectors = types.map(function (t) { 83 return '[' + typeAttr + '="' + t + '"], [id="' + t + '"]'; 84 }).join(', '); 85 86 // querySelectorAll returns nodes in document order 87 var scopedNodes = root.querySelectorAll(selectors); 88 89 // 3) Also collect [data-revenuemaker-ads] elements in the FULL document that 90 // match one of the types by id â these are static desktop slots (e.g. in 91 // <aside class="free-html">) which may live outside rootSelector. 92 var rmSelectors = types.map(function (t) { 93 return '[data-revenuemaker-ads][id="' + t + '"]'; 94 }).join(', '); 95 var globalRmNodes = document.querySelectorAll(rmSelectors); 96 97 // 4) Merge both lists preserving document order, deduplicating by reference. 98 var seen = []; 99 var adNodes = []; 100 function addNode(n) { 101 if (seen.indexOf(n) === -1) { seen.push(n); adNodes.push(n); } 102 } 103 104 // Walk the document in order: compare positions to merge correctly. 105 // Simple approach: collect all, sort by document position. 106 for (var s = 0; s < scopedNodes.length; s++) { addNode(scopedNodes[s]); } 107 for (var g = 0; g < globalRmNodes.length; g++) { addNode(globalRmNodes[g]); } 108 109 // Sort in document order using compareDocumentPosition 110 adNodes.sort(function (a, b) { 111 if (a === b) return 0; 112 var pos = a.compareDocumentPosition(b); 113 return (pos & Node.DOCUMENT_POSITION_FOLLOWING) ? -1 : 1; 114 }); 115 116 // Numbering grouped by the order of `types` provided. 117 // Esto asegura que las numeraciones se ciñan exclusivamente a los tipos 118 // que se han pasado en la llamada (p.ej. ['roba','banner','boton']), 119 // procesando primero todos los elementos del primer tipo, luego del 120 // segundo, etc., independientemente de su posición en el DOM.
121 types.forEach(function (t) { 122 for (var k = 0; k < adNodes.length; k++) { 123 var node = adNodes[k]; 124 // Determine node's logical type: prefer attr_type if present, else id 125 var ttype = node.getAttribute(typeAttr) || node.getAttribute('id'); 126 if (!ttype || ttype !== t) continue; 127 128 // If node already has id like 'type123' and not bumpExisting: skip 129 var existingId = node.getAttribute('id') || ''; 130 var numericMatch = existingId.match(new RegExp('^' + escapeRegExp(ttype) + '(\\d+)$')); 131 if (numericMatch && numericMatch[1] && !bumpExisting) { 132 var exNum = parseInt(numericMatch[1], 10); 133 if (!isNaN(exNum) && exNum > counters[ttype]) counters[ttype] = exNum; 134 continue; 135 } 136 137 // Assign next number for this type 138 counters[ttype] = (counters[ttype] || 0) + 1; 139 var newId = ttype + counters[ttype]; 140 node.setAttribute('id', newId); 141 } 142 }); 143 144 return counters; 145 } 146 147 // Expose to global for configuration to call 148 global.assignAdNumbersFromConfig = assignAdNumbersFromConfig; 149 150})(window); 151
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.