1import { 2 CheckboxControlValueAccessor, 3 DefaultValueAccessor, 4 FormsModule, 5 NgControlStatus, 6 NgModel 7} from "./chunk-IYVFIRIY.js"; 8import { 9 CommonModule, 10 Component, 11 EventEmitter, 12 Input, 13 NgForOf, 14 NgIf, 15 Output, 16 ViewChild, 17 setClassMetadata, 18 ɵsetClassDebugInfo, 19 ɵɵNgOnChangesFeature, 20 ɵɵadvance, 21 ɵɵclassProp, 22 ɵɵdefineComponent, 23 ɵɵelement, 24 ɵɵelementEnd, 25 ɵɵelementStart, 26 ɵɵgetCurrentView, 27 ɵɵlistener, 28 ɵɵloadQuery, 29 ɵɵnextContext, 30 ɵɵproperty, 31 ɵɵqueryRefresh, 32 ɵɵresetView, 33 ɵɵrestoreView, 34 ɵɵtemplate, 35 ɵɵtext, 36 ɵɵtextInterpolate, 37 ɵɵtextInterpolate1, 38 ɵɵtwoWayBindingSet, 39 ɵɵtwoWayListener, 40 ɵɵtwoWayProperty, 41 ɵɵviewQuery 42} from "./chunk-P2CEY5PN.js"; 43 44// src/main/webapp/app/shared/text-viewer/text-viewer.component.ts 45var _c0 = ["tvBody"]; 46function TextViewerComponent_button_5_Template(rf, ctx) { 47 if (rf & 1) { 48 const _r2 = \u0275\u0275getCurrentView(); 49 \u0275\u0275elementStart(0, "button", 20); 50 \u0275\u0275listener("click", function TextViewerComponent_button_5_Template_button_click_0_listener() { 51 \u0275\u0275restoreView(_r2); 52 const ctx_r2 = \u0275\u0275nextContext(); 53 return \u0275\u0275resetView(ctx_r2.clear()); 54 }); 55 \u0275\u0275element(1, "i", 21); 56 \u0275\u0275elementEnd(); 57 } 58} 59function TextViewerComponent_span_10_Template(rf, ctx) { 60 if (rf & 1) { 61 \u0275\u0275elementStart(0, "span", 11); 62 \u0275\u0275text(1); 63 \u0275\u0275elementEnd(); 64 } 65 if (rf & 2) { 66 const ctx_r2 = \u0275\u0275nextContext(); 67 \u0275\u0275advance(); 68 \u0275\u0275textInterpolate1("", ctx_r2.matchCount, " matches"); 69 } 70} 71function TextViewerComponent_div_20_Template(rf, ctx) { 72 if (rf & 1) { 73 \u0275\u0275elementStart(0, "div", 22)(1, "span", 23); 74 \u0275\u0275text(2); 75 \u0275\u0275elementEnd(); 76 \u0275\u0275elementStart(3, "span", 24); 77 \u0275\u0275text(4); 78 \u0275\u0275elementEnd()(); 79 } 80 if (rf & 2) { 81 const line_r4 = ctx.$implicit; 82 \u0275\u0275classProp("tv-match", line_r4.match); 83 \u0275\u0275advance(2); 84 \u0275\u0275textInterpolate(line_r4.number); 85 \u0275\u0275advance(2); 86 \u0275\u0275textInterpolate(line_r4.text); 87 } 88} 89function TextViewerComponent_div_21_Template(rf, ctx) { 90 if (rf & 1) { 91 \u0275\u0275elementStart(0, "div", 25); 92 \u0275\u0275text(1); 93 \u0275\u0275elementEnd(); 94 } 95 if (rf & 2) { 96 const ctx_r2 = \u0275\u0275nextContext(); 97 \u0275\u0275advance(); 98 \u0275\u0275textInterpolate1(" Showing the first ", ctx_r2.lines.length, " lines only \u2014 download the file to read all of it. "); 99 } 100} 101var MAX_RENDERED_LINES = 5e3; 102var STICK_TO_BOTTOM_SLACK_PX = 24; 103var TextViewerComponent = class _TextViewerComponent { 104 constructor() { 105 this.filename = "text.txt"; 106 this.wrap = false; 107 this.follow = false; 108 this.startLine = 1; 109 this.followChange = new EventEmitter(); 110 this.pendingScroll = false; 111 this.lastAppliedScrollTop = -1; 112 this.query = ""; 113 this.onlyMatches = false; 114 this.lines = []; 115 this.totalLines = 0; 116 this.matchCount = 0; 117 this.truncated = false; 118 } 119 ngOnChanges() { 120 this.apply(); 121 if (this.follow) { 122 this.pendingScroll = true; 123 } 124 } 125 ngAfterViewChecked() { 126 if (!this.pendingScroll || !this.follow || !this.tvBody) { 127 return; 128 } 129 this.pendingScroll = false; 130 const body = this.tvBody.nativeElement; 131 if (body.scrollHeight - body.scrollTop - body.clientHeight <= 1) { 132 return; 133 } 134 body.scrollTop = body.scrollHeight; 135 this.lastAppliedScrollTop = body.scrollTop; 136 } 137 onBodyScroll() { 138 if (!this.follow || !this.tvBody) { 139 return; 140 } 141 const body = this.tvBody.nativeElement; 142 if (body.scrollTop === this.lastAppliedScrollTop) { 143 return; 144 } 145 if (body.scrollHeight - body.scrollTop - body.clientHeight > STICK_TO_BOTTOM_SLACK_PX) { 146 this.follow = false; 147 this.followChange.emit(false); 148 } 149 } 150 trackLine(index, line) { 151 return line.number + ":" + line.text; 152 } 153 apply() { 154 const raw = (this.text || "").split(/\r?\n/); 155 this.totalLines = raw.length; 156 const needle = this.query.trim().toLowerCase(); 157 const collected = []; 158 let matches = 0; 159 for (let i = 0; i < raw.length; i++) { 160 const match = !!needle && raw[i].toLowerCase().includes(needle); 161 if (match) { 162 matches++; 163 } 164 if (this.onlyMatches && needle && !match) { 165 continue; 166 } 167 if (collected.length < MAX_RENDERED_LINES) { 168 collected.push({ number: this.startLine + i, text: raw[i], match }); 169 } 170 } 171 this.matchCount = matches; 172 this.truncated = collected.length >= MAX_RENDERED_LINES; 173 this.lines = collected; 174 } 175 clear() { 176 this.query = ""; 177 this.onlyMatches = false;
178 this.apply(); 179 } 180 copy() { 181 const textarea = document.createElement("textarea"); 182 textarea.style.position = "fixed"; 183 textarea.style.opacity = "0"; 184 textarea.value = this.text || ""; 185 document.body.appendChild(textarea); 186 textarea.select(); 187 document.execCommand("copy"); 188 document.body.removeChild(textarea); 189 } 190 download() { 191 const blob = new Blob([this.text || ""], { type: "text/plain;charset=utf-8" }); 192 const url = URL.createObjectURL(blob); 193 const link = document.createElement("a"); 194 link.href = url; 195 link.download = this.filename; 196 document.body.appendChild(link); 197 link.click(); 198 link.remove(); 199 URL.revokeObjectURL(url); 200 } 201 static { 202 this.\u0275fac = function TextViewerComponent_Factory(__ngFactoryType__) { 203 return new (__ngFactoryType__ || _TextViewerComponent)(); 204 }; 205 } 206 static { 207 this.\u0275cmp = /* @__PURE__ */ \u0275\u0275defineComponent({ type: _TextViewerComponent, selectors: [["text-viewer"]], viewQuery: function TextViewerComponent_Query(rf, ctx) { 208 if (rf & 1) { 209 \u0275\u0275viewQuery(_c0, 5); 210 } 211 if (rf & 2) { 212 let _t; 213 \u0275\u0275queryRefresh(_t = \u0275\u0275loadQuery()) && (ctx.tvBody = _t.first); 214 } 215 }, inputs: { text: "text", filename: "filename", wrap: "wrap", follow: "follow", startLine: "startLine" }, outputs: { followChange: "followChange" }, features: [\u0275\u0275NgOnChangesFeature], decls: 22, vars: 10, consts: [["tvBody", ""], [1, "tv"], [1, "tv-toolbar"], [1, "tv-search"], [1, "fa", "fa-search"], ["type", "text", "placeholder", "search", 1, "form-control", "form-control-sm", 3, "ngModelChange", "ngModel"], ["type", "button", "class", "btn btn-sm btn-link tv-clear", 3, "click", 4, "ngIf"], [1, "form-check", "tv-check"], ["type", "checkbox", "id", "tvOnlyMatches", 1, "form-check-input", 3, "ngModelChange", "ngModel"], ["for", "tvOnlyMatches", 1, "form-check-label"], ["class", "tv-stat", 4, "ngIf"], [1, "tv-stat"], [1, "tv-actions"], ["type", "button", "title", "Copy everything", 1, "btn", "btn-sm", "btn-outline-secondary", 3, "click"], [1, "fa", "fa-copy"], ["type", "button", "title", "Download as file", 1, "btn", "btn-sm", "btn-outline-secondary", 3, "click"], [1, "fa", "fa-download"], [1, "tv-body", 3, "scroll"], ["class", "tv-line", 3, "tv-match", 4, "ngFor", "ngForOf", "ngForTrackBy"], ["class", "tv-note", 4, "ngIf"], ["type", "button", 1, "btn", "btn-sm", "btn-link", "tv-clear", 3, "click"], [1, "fa", "fa-times"], [1, "tv-line"], [1, "tv-num"], [1, "tv-text"], [1, "tv-note"]], template: function TextViewerComponent_Template(rf, ctx) { 216 if (rf & 1) { 217 const _r1 = \u0275\u0275getCurrentView(); 218 \u0275\u0275elementStart(0, "div", 1)(1, "div", 2)(2, "div", 3); 219 \u0275\u0275element(3, "i", 4); 220 \u0275\u0275elementStart(4, "input", 5); 221 \u0275\u0275twoWayListener("ngModelChange", function TextViewerComponent_Template_input_ngModelChange_4_listener($event) { 222 \u0275\u0275restoreView(_r1); 223 \u0275\u0275twoWayBindingSet(ctx.query, $event) || (ctx.query = $event); 224 return \u0275\u0275resetView($event); 225 }); 226 \u0275\u0275listener("ngModelChange", function TextViewerComponent_Template_input_ngModelChange_4_listener() { 227 \u0275\u0275restoreView(_r1); 228 return \u0275\u0275resetView(ctx.apply()); 229 }); 230 \u0275\u0275elementEnd(); 231 \u0275\u0275template(5, TextViewerComponent_button_5_Template, 2, 0, "button", 6); 232 \u0275\u0275elementEnd(); 233 \u0275\u0275elementStart(6, "div", 7)(7, "input", 8); 234 \u0275\u0275twoWayListener("ngModelChange", function TextViewerComponent_Template_input_ngModelChange_7_listener($event) { 235 \u0275\u0275restoreView(_r1); 236 \u0275\u0275twoWayBindingSet(ctx.onlyMatches, $event) || (ctx.onlyMatches = $event); 237 return \u0275\u0275resetView($event); 238 }); 239 \u0275\u0275listener("ngModelChange", function TextViewerComponent_Template_input_ngModelChange_7_listener() { 240 \u0275\u0275restoreView(_r1);
vendor: 5,727 bytes, lines 241-299
241 return \u0275\u0275resetView(ctx.apply()); 242 }); 243 \u0275\u0275elementEnd(); 244 \u0275\u0275elementStart(8, "label", 9); 245 \u0275\u0275text(9, "only matches"); 246 \u0275\u0275elementEnd()(); 247 \u0275\u0275template(10, TextViewerComponent_span_10_Template, 2, 1, "span", 10); 248 \u0275\u0275elementStart(11, "span", 11); 249 \u0275\u0275text(12); 250 \u0275\u0275elementEnd(); 251 \u0275\u0275elementStart(13, "div", 12)(14, "button", 13); 252 \u0275\u0275listener("click", function TextViewerComponent_Template_button_click_14_listener() { 253 \u0275\u0275restoreView(_r1); 254 return \u0275\u0275resetView(ctx.copy()); 255 }); 256 \u0275\u0275element(15, "i", 14); 257 \u0275\u0275elementEnd(); 258 \u0275\u0275elementStart(16, "button", 15); 259 \u0275\u0275listener("click", function TextViewerComponent_Template_button_click_16_listener() { 260 \u0275\u0275restoreView(_r1); 261 return \u0275\u0275resetView(ctx.download()); 262 }); 263 \u0275\u0275element(17, "i", 16); 264 \u0275\u0275elementEnd()()(); 265 \u0275\u0275elementStart(18, "div", 17, 0); 266 \u0275\u0275listener("scroll", function TextViewerComponent_Template_div_scroll_18_listener() { 267 \u0275\u0275restoreView(_r1); 268 return \u0275\u0275resetView(ctx.onBodyScroll()); 269 }); 270 \u0275\u0275template(20, TextViewerComponent_div_20_Template, 5, 4, "div", 18); 271 \u0275\u0275elementEnd(); 272 \u0275\u0275template(21, TextViewerComponent_div_21_Template, 2, 1, "div", 19); 273 \u0275\u0275elementEnd(); 274 } 275 if (rf & 2) { 276 \u0275\u0275advance(4); 277 \u0275\u0275twoWayProperty("ngModel", ctx.query); 278 \u0275\u0275advance(); 279 \u0275\u0275property("ngIf", ctx.query); 280 \u0275\u0275advance(2); 281 \u0275\u0275twoWayProperty("ngModel", ctx.onlyMatches); 282 \u0275\u0275advance(3); 283 \u0275\u0275property("ngIf", ctx.query); 284 \u0275\u0275advance(2); 285 \u0275\u0275textInterpolate1("", ctx.totalLines, " lines"); 286 \u0275\u0275advance(6); 287 \u0275\u0275classProp("tv-wrap", ctx.wrap); 288 \u0275\u0275advance(2); 289 \u0275\u0275property("ngForOf", ctx.lines)("ngForTrackBy", ctx.trackLine); 290 \u0275\u0275advance(); 291 \u0275\u0275property("ngIf", ctx.truncated); 292 } 293 }, dependencies: [CommonModule, NgForOf, NgIf, FormsModule, DefaultValueAccessor, CheckboxControlValueAccessor, NgControlStatus, NgModel], styles: ["\n\n.tv[_ngcontent-%COMP%] {\n border: 1px solid #e3e7eb;\n border-radius: 8px;\n background: #ffffff;\n overflow: hidden;\n}\n.tv-toolbar[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n padding: 0.4rem 0.6rem;\n border-bottom: 1px solid #eceff2;\n background: #fbfcfd;\n}\n.tv-search[_ngcontent-%COMP%] {\n position: relative;\n display: flex;\n align-items: center;\n flex: 0 1 320px;\n}\n.tv-search[_ngcontent-%COMP%] > .fa-search[_ngcontent-%COMP%] {\n position: absolute;\n left: 0.55rem;\n color: #b6bec7;\n font-size: 0.75rem;\n}\n.tv-search[_ngcontent-%COMP%] > input[_ngcontent-%COMP%] {\n padding-left: 1.7rem;\n font-family: var(--bs-font-monospace);\n font-size: 0.78rem;\n}\n.tv-clear[_ngcontent-%COMP%] {\n position: absolute;\n right: 0;\n color: #8a94a2;\n text-decoration: none;\n}\n.tv-check[_ngcontent-%COMP%] {\n margin: 0;\n white-space: nowrap;\n}\n.tv-check[_ngcontent-%COMP%] .form-check-label[_ngcontent-%COMP%] {\n font-size: 0.78rem;\n color: #55606e;\n}\n.tv-stat[_ngcontent-%COMP%] {\n color: #8a94a2;\n font-size: 0.75rem;\n white-space: nowrap;\n}\n.tv-actions[_ngcontent-%COMP%] {\n display: flex;\n gap: 0.35rem;\n margin-left: auto;\n}\n.tv-body[_ngcontent-%COMP%] {\n max-height: 460px;\n overflow: auto;\n padding: 0.4rem 0;\n font-family: var(--bs-font-monospace);\n font-size: 0.73rem;\n line-height: 1.45;\n}\n.tv-line[_ngcontent-%COMP%] {\n display: flex;\n gap: 0.6rem;\n padding: 0 0.6rem;\n white-space: pre;\n}\n.tv-line.tv-match[_ngcontent-%COMP%] {\n background: #fff6d8;\n}\n.tv-num[_ngcontent-%COMP%] {\n flex: 0 0 3.5rem;\n text-align: right;\n color: #c3cad1;\n -webkit-user-select: none;\n user-select: none;\n}\n.tv-text[_ngcontent-%COMP%] {\n flex: 1 1 auto;\n color: #1c2430;\n}\n.tv-wrap[_ngcontent-%COMP%] .tv-line[_ngcontent-%COMP%] {\n white-space: pre-wrap;\n word-break: break-all;\n}\n.tv-note[_ngcontent-%COMP%] {\n padding: 0.4rem 0.6rem;\n border-top: 1px solid #eceff2;\n background: #fbfcfd;\n color: #8a94a2;\n font-size: 0.75rem;\n}\n/*# sourceMappingURL=text-viewer.component.css.map */"] }); 294 } 295}; 296(() => { 297 (typeof ngDevMode === "undefined" || ngDevMode) && setClassMetadata(TextViewerComponent, [{ 298 type: Component, 299 args: [{ standalone: true, selector: "text-viewer", imports: [CommonModule, FormsModule], template: '<div class="tv">\n <div class="tv-toolbar">\n <div class="tv-search">\n <i class="fa fa-search"></i>\n <input type="text" class="form-control form-control-sm" placeholder="search"\n [(ngModel)]="query" (ngModelChange)="apply()">\n <button type="button" class="btn btn-sm btn-link tv-clear" *ngIf="query" (click)="clear()">\n <i class="fa fa-times"></i>\n </button>\n </div>\n\n <div class="form-check tv-check">\n <input class="form-check-input" type="checkbox" id="tvOnlyMatches"\n [(ngModel)]="onlyMatches" (ngModelChange)="apply()">\n <label class="form-check-label" for="tvOnlyMatches">only matches</label>\n </div>
299\n\n <span class="tv-stat" *ngIf="query">{{ matchCount }} matches</span>\n <span class="tv-stat">{{ totalLines }} lines</span>\n\n <div class="tv-actions">\n <button type="button" class="btn btn-sm btn-outline-secondary" (click)="copy()" title="Copy everything">\n <i class="fa fa-copy"></i>\n </button>\n <button type="button" class="btn btn-sm btn-outline-secondary" (click)="download()" title="Download as file">\n <i class="fa fa-download"></i>\n </button>\n </div>\n </div>\n\n <div class="tv-body" #tvBody [class.tv-wrap]="wrap" (scroll)="onBodyScroll()">\n <div class="tv-line" *ngFor="let line of lines; trackBy: trackLine" [class.tv-match]="line.match">\n <span class="tv-num">{{ line.number }}</span>\n <span class="tv-text">{{ line.text }}</span>\n </div>\n </div>\n\n <div class="tv-note" *ngIf="truncated">\n Showing the first {{ lines.length }} lines only \u2014 download the file to read all of it.\n </div>\n</div>\n', styles: ["/* src/main/webapp/app/shared/text-viewer/text-viewer.component.css */\n.tv {\n border: 1px solid #e3e7eb;\n border-radius: 8px;\n background: #ffffff;\n overflow: hidden;\n}\n.tv-toolbar {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n padding: 0.4rem 0.6rem;\n border-bottom: 1px solid #eceff2;\n background: #fbfcfd;\n}\n.tv-search {\n position: relative;\n display: flex;\n align-items: center;\n flex: 0 1 320px;\n}\n.tv-search > .fa-search {\n position: absolute;\n left: 0.55rem;\n color: #b6bec7;\n font-size: 0.75rem;\n}\n.tv-search > input {\n padding-left: 1.7rem;\n font-family: var(--bs-font-monospace);\n font-size: 0.78rem;\n}\n.tv-clear {\n position: absolute;\n right: 0;\n color: #8a94a2;\n text-decoration: none;\n}\n.tv-check {\n margin: 0;\n white-space: nowrap;\n}\n.tv-check .form-check-label {\n font-size: 0.78rem;\n color: #55606e;\n}\n.tv-stat {\n color: #8a94a2;\n font-size: 0.75rem;\n white-space: nowrap;\n}\n.tv-actions {\n display: flex;\n gap: 0.35rem;\n margin-left: auto;\n}\n.tv-body {\n max-height: 460px;\n overflow: auto;\n padding: 0.4rem 0;\n font-family: var(--bs-font-monospace);\n font-size: 0.73rem;\n line-height: 1.45;\n}\n.tv-line {\n display: flex;\n gap: 0.6rem;\n padding: 0 0.6rem;\n white-space: pre;\n}\n.tv-line.tv-match {\n background: #fff6d8;\n}\n.tv-num {\n flex: 0 0 3.5rem;\n text-align: right;\n color: #c3cad1;\n -webkit-user-select: none;\n user-select: none;\n}\n.tv-text {\n flex: 1 1 auto;\n color: #1c2430;\n}\n.tv-wrap .tv-line {\n white-space: pre-wrap;\n word-break: break-all;\n}\n.tv-note {\n padding: 0.4rem 0.6rem;\n border-top: 1px solid #eceff2;\n background: #fbfcfd;\n color: #8a94a2;\n font-size: 0.75rem;\n}\n/*# sourceMappingURL=text-viewer.component.css.map */\n"] }] 300 }], null, { text: [{ 301 type: Input 302 }], filename: [{ 303 type: Input 304 }], wrap: [{ 305 type: Input 306 }], follow: [{ 307 type: Input 308 }], startLine: [{ 309 type: Input 310 }], followChange: [{ 311 type: Output 312 }], tvBody: [{ 313 type: ViewChild, 314 args: ["tvBody"] 315 }] }); 316})(); 317(() => { 318 (typeof ngDevMode === "undefined" || ngDevMode) && \u0275setClassDebugInfo(TextViewerComponent, { className: "TextViewerComponent", filePath: "src/main/webapp/app/shared/text-viewer/text-viewer.component.ts", lineNumber: 20 }); 319})(); 320 321export { 322 TextViewerComponent 323}; 324//# sourceMappingURL=chunk-MI5LJAWE.js.map
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.