1/* ===== Native Jasper Report Editor / Check tab (item cec0e7f4, F3) ===== 2 * 3 * validation-panel.js â ported from the legacy editor's 4 * `validation/jasper-validation.component.ts` (234 lines). The "Check" tab: 5 * runs the pure `validateReport` rule set (state/validation.js), groups the 6 * results into errors / warnings, renders each as a clickable row that selects 7 * and scrolls to the offending element, and drives the tab's badge counts. 8 */ 9 10(function (global) { 11 'use strict'; 12 13 const req = (typeof require === 'function'); 14 const NS = (!req && global.JasperEditor) ? global.JasperEditor : null; 15 const validationMod = req ? require('../state/validation.js') : NS.validation; 16 const { validateReport } = validationMod; 17 18 /** Split issues into error / warning groups (errors first). */ 19 function groupIssues(issues) { 20 return { 21 errors: (issues || []).filter((i) => i.severity === 'error'), 22 warnings: (issues || []).filter((i) => i.severity === 'warning'), 23 }; 24 } 25 26 /** Badge counts for the Check tab: {errors, warnings, total}. */ 27 function badgeCounts(issues) { 28 const g = groupIssues(issues); 29 return { errors: g.errors.length, warnings: g.warnings.length, total: (issues || []).length }; 30 } 31 32 function esc(s) { 33 return String(s == null ? '' : s).replace(/[&<>"']/g, (c) => ( 34 { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }[c])); 35 } 36 37 /** Render the Check tab (reference: jasper-validation.component â header 38 * with count pills, issue rows with mono icon / message / detail / where, 39 * and a Declare-$F quick fix for unknown-field warnings). `onSelect(path)` 40 * is called with the element path of a clicked issue. */ 41 function unknownFieldName(issue) { 42 const m = /^Unknown field \$F\{(\w+)\}/.exec(issue.message || ''); 43 return m ? m[1] : null; 44 } 45 46 function render(store, host, onSelect) { 47 const r = store && store.report(); 48 if (!host) return; 49 const issues = r ? validateReport(r) : []; 50 const { errors, warnings } = groupIssues(issues); 51 const pills = []; 52 if (errors.length) pills.push(`<span class="vp-pill err">${errors.length} error${errors.length === 1 ? '' : 's'}</span>`); 53 if (warnings.length) pills.push(`<span class="vp-pill warn">${warnings.length} warning${warnings.length === 1 ? '' : 's'}</span>`); 54 if (!issues.length) pills.push('<span class="vp-pill ok">all clear</span>'); 55 56 const rowsWithPaths = []; 57 const issueRow = (issue) => { 58 const gi = rowsWithPaths.push(issue) - 1; 59 const fieldName = unknownFieldName(issue); 60 const where = issue.path 61 ? `${issue.path.section || ''}${issue.path.groupName ? ' / ' + issue.path.groupName : ''} · #${(issue.path.indices || []).join('.')}` 62 : ''; 63 return `<li class="vp-issue vp-${esc(issue.severity)}" data-g="${gi}"> 64 <span class="vp-icon">${issue.severity === 'error' ? 'â' : '!'}</span> 65 <div> 66 <span class="vp-msg">${esc(issue.message)}</span> 67 ${issue.detail ? `<span class="vp-detail">${esc(issue.detail)}</span>` : ''} 68 ${where ? `<span class="vp-where">${esc(where)}</span>` : ''} 69 ${fieldName ? `<button type="button" class="vp-fix" data-field="${esc(fieldName)}" style="display:inline-block;margin-top:4px;padding:2px 8px;font-size:10px;font-family:inherit;background:#e8edff;color:#4a6cf7;border:1px solid #c3cdf9;border-radius:3px;cursor:pointer;line-height:1.4">Declare $F{${esc(fieldName)}}</button>` : ''} 70 </div> 71 </li>`; 72 }; 73 74 host.innerHTML = ` 75 <div class="vp-header"><span>Validation</span><span class="vp-counts">${pills.join('')}</span></div>` + 76 (issues.length 77 ? `<ul class="vp-list">${issues.map(issueRow).join('')}</ul>` 78 : '<div class="vp-empty">No problems detected.</div>'); 79 80 host.querySelectorAll('.vp-issue').forEach((li) => { 81 li.onclick = () => { 82 const issue = rowsWithPaths[Number(li.getAttribute('data-g'))]; 83 if (issue && issue.path) { 84 if (onSelect) onSelect(issue.path); 85 else if (store.select) store.select(issue.path); 86 } 87 }; 88 }); 89 host.querySelectorAll('.vp-fix').forEach((btn) => { 90 btn.onclick = (e) => { 91 e.stopPropagation(); 92 const name = btn.getAttribute('data-field'); 93 const rep = store.report(); 94 if (!rep || (rep.fields || []).some((f) => f.name === name)) return; 95 store.updateReport((cur) => Object.assign({}, cur, { 96 fields: [...(cur.fields || []), { name, class: 'java.lang.String' }], 97 })); 98 render(store, host, onSelect); 99 }; 100 }); 101 } 102 103 const api = { validateReport, groupIssues, badgeCounts, render }; 104 105 if (typeof module !== 'undefined' && module.exports) { 106 module.exports = api; 107 } else { 108 const NSg = (global.JasperEditor = global.JasperEditor || {}); 109 NSg.validationPanel = api; 110 } 111})(typeof self !== 'undefined' ? self : this);
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.