1if (!Element.prototype.matches) { 2 Element.prototype.matches = 3 Element.prototype.msMatchesSelector || 4 Element.prototype.webkitMatchesSelector; 5} 6 7if (!Element.prototype.closest) { 8 Element.prototype.closest = function (s) { 9 var el = this; 10 11 do { 12 if (el.matches(s)) return el; 13 el = el.parentElement || el.parentNode; 14 } while (el !== null && el.nodeType === 1); 15 return null; 16 }; 17} 18 19// Suppress "DotNetObjectReference already disposed" promise rejections during component teardown. 20function suppressDisposed(promise) { 21 if (promise && typeof promise.catch === 'function') { 22 promise.catch(function () { }); 23 } 24} 25window.addEventListener('unhandledrejection', function (e) { 26 if (e.reason && e.reason.message && e.reason.message.indexOf('DotNetObjectReference') !== -1) { 27 e.preventDefault(); 28 } 29}); 30 31var resolveCallbacks = []; 32var rejectCallbacks = []; 33var radzenRecognition; 34 35window.Radzen = { 36 isRTL: function (el) { 37 return el && getComputedStyle(el).direction == 'rtl'; 38 }, 39 throttle: function (callback, delay) { 40 var timeout = null; 41 return function () { 42 var args = arguments; 43 var ctx = this; 44 if (!timeout) { 45 timeout = setTimeout(function () { 46 callback.apply(ctx, args); 47 timeout = null; 48 }, delay); 49 } 50 }; 51 }, 52 downloadFile: async function (fileName, data, mimeType) { 53 const buffer = typeof data.arrayBuffer === 'function' ? await data.arrayBuffer() : data; 54 const blob = new Blob([buffer], { type: mimeType }); 55 const url = URL.createObjectURL(blob); 56 57 const a = document.createElement("a"); 58 a.href = url; 59 a.download = fileName; 60 a.click(); 61 62 URL.revokeObjectURL(url); 63 }, 64 mask: function (id, mask, pattern, characterPattern) { 65 var el = document.getElementById(id); 66 if (el) { 67 var format = function (value, mask, pattern, characterPattern) { 68 var chars = !characterPattern ? value.replace(new RegExp(pattern, "g"), "").split('') : value.match(new RegExp(characterPattern, "g")); 69 var count = 0; 70 71 var formatted = ''; 72 for (var i = 0; i < mask.length; i++) { 73 const c = mask[i]; 74 if (chars && chars[count]) { 75 if (c === '*' || c == chars[count]) { 76 formatted += chars[count]; 77 count++; 78 } else { 79 formatted += c; 80 } 81 } 82 } 83 return formatted; 84 } 85 86 if (window.safari !== undefined) { 87 el.onblur = function (e) { 88 el.dispatchEvent(new Event('change')); 89 }; 90 } 91 92 var start = el.selectionStart != el.value.length ? el.selectionStart : -1; 93 var end = el.selectionEnd != el.value.length ? el.selectionEnd : -1; 94 95 el.value = format(el.value, mask, pattern, characterPattern); 96 97 el.selectionStart = start != -1 ? start : el.selectionStart; 98 el.selectionEnd = end != -1 ? end : el.selectionEnd; 99 } 100 }, 101 addContextMenu: function (id, ref) { 102 var el = document.getElementById(id); 103 if (el) { 104 var handler = function (e) { 105 e.stopPropagation(); 106 e.preventDefault(); 107 try { 108 ref.invokeMethodAsync('RadzenComponent.RaiseContextMenu', 109 { 110 ClientX: e.clientX, 111 ClientY: e.clientY, 112 ScreenX: e.screenX, 113 ScreenY: e.screenY, 114 AltKey: e.altKey, 115 ShiftKey: e.shiftKey, 116 CtrlKey: e.ctrlKey, 117 MetaKey: e.metaKey, 118 Button: e.button, 119 Buttons: e.buttons, 120 }); 121 } catch { } 122 return false; 123 }; 124 Radzen[id + 'contextmenu'] = handler; 125 el.addEventListener('contextmenu', handler, false); 126 } 127 }, 128 addMouseEnter: function (id, ref) { 129 var el = document.getElementById(id); 130 if (el) { 131 var handler = function (e) { 132 try { suppressDisposed(ref.invokeMethodAsync('RadzenComponent.RaiseMouseEnter')); } catch { } 133 }; 134 Radzen[id + 'mouseenter'] = handler; 135 el.addEventListener('mouseenter', handler, false); 136 } 137 }, 138 addMouseLeave: function (id, ref) { 139 var el = document.getElementById(id); 140 if (el) { 141 var handler = function (e) { 142 try { suppressDisposed(ref.invokeMethodAsync('RadzenComponent.RaiseMouseLeave')); } catch { } 143 }; 144 Radzen[id + 'mouseleave'] = handler; 145 el.addEventListener('mouseleave', handler, false); 146 } 147 }, 148 removeContextMenu: function (id) { 149 var el = document.getElementById(id); 150 if (el && Radzen[id + 'contextmenu']) { 151 el.removeEventListener('contextmenu', Radzen[id + 'contextmenu']); 152 } 153 }, 154 removeMouseEnter: function (id) { 155 var el = document.getElementById(id); 156 if (el && Radzen[id + 'mouseenter']) { 157 el.removeEventListener('mouseenter', Radzen[id + 'mouseenter']); 158 } 159 }, 160 removeMouseLeave: function (id) { 161 var el = document.getElementById(id); 162 if (el && Radzen[id + 'mouseleave']) { 163 el.removeEventListener('mouseleave', Radzen[id + 'mouseleave']); 164 } 165 }, 166 adjustDataGridHeader: function (scrollableHeader, scrollableBody) { 167 if (scrollableHeader && scrollableBody) { 168 scrollableHeader.style.cssText = 169 scrollableBody.clientHeight < scrollableBody.scrollHeight 170 ? 'margin-left:0px;padding-right: ' + 171 (scrollableBody.offsetWidth - scrollableBody.clientWidth) + 172 'px' 173 : 'margin-left:0px;'; 174 } 175 }, 176 ganttSyncScroll: function (ganttId) { 177 if (!ganttId) { 178 return; 179 } 180 181 var root = document.getElementById(ganttId); 182 if (!root) { 183 return; 184 } 185 186 var grid = root.querySelector('.rz-data-grid-data'); 187 var timeline = root.querySelector('.rz-gantt-timeline-scroll'); 188 if (!grid || !timeline) { 189 return; 190 } 191 192 var header = root.querySelector('.rz-gantt-table thead'); 193 if (header) { 194 root.style.setProperty('--rz-gantt-header-height', header.getBoundingClientRect().height + 'px'); 195 } 196 197 // Measure timeline group header and set CSS variable so the grid's 198 // thead::before pseudo-row matches it. Also sync overall header height. 199 function syncHeaderHeights() { 200 var gridThead = grid.querySelector('thead'); 201 var timelineThead = timeline.querySelector('thead'); 202 if (!gridThead || !timelineThead) return; 203 204 var groupRow = timelineThead.querySelector('.rz-gantt-header-group-row'); 205 if (groupRow) { 206 root.style.setProperty('--rz-gantt-header-group-height', groupRow.offsetHeight + 'px'); 207 } else { 208 root.style.setProperty('--rz-gantt-header-group-height', '0px'); 209 } 210 211 var maxH = Math.max(gridThead.offsetHeight, timelineThead.offsetHeight); 212 root.style.setProperty('--rz-gantt-header-height', maxH + 'px'); 213 } 214 215 function runSyncAfterLayout() { 216 requestAnimationFrame(function () { 217 requestAnimationFrame(syncHeaderHeights); 218 }); 219 } 220 221 runSyncAfterLayout(); 222 223 var key = ganttId + '_ganttScrollSync'; 224 var state = Radzen[key]; 225 226 if (state && state.grid === grid && state.timeline === timeline) { 227 return; 228 } 229 230 if (state) { 231 if (state.grid && state.onGrid) { 232 state.grid.removeEventListener('scroll', state.onGrid); 233 } 234 if (state.timeline && state.onTimeline) { 235 state.timeline.removeEventListener('scroll', state.onTimeline); 236 } 237 if (state.grid && state.onGridWheel) { 238 state.grid.removeEventListener('wheel', state.onGridWheel); 239 } 240 } 241 242 var syncing = false;
243 var onGrid = function () { 244 if (syncing) { 245 return; 246 } 247 syncing = true; 248 timeline.scrollTop = grid.scrollTop; 249 syncing = false; 250 }; 251 var onTimeline = function () { 252 if (syncing) { 253 return; 254 } 255 syncing = true; 256 grid.scrollTop = timeline.scrollTop; 257 syncing = false; 258 }; 259 260 // The grid has overflow-y: hidden (no native vertical scrollbar). 261 // Forward vertical mouse-wheel events to the timeline so the user 262 // can still scroll vertically while hovering over the grid. 263 var onGridWheel = function (e) { 264 if (e.deltaY) { 265 timeline.scrollTop += e.deltaY; 266 e.preventDefault(); 267 } 268 }; 269 270 grid.addEventListener('scroll', onGrid); 271 timeline.addEventListener('scroll', onTimeline); 272 grid.addEventListener('wheel', onGridWheel, { passive: false }); 273 274 var resizeObserver = null; 275 if (typeof ResizeObserver !== 'undefined') { 276 resizeObserver = new ResizeObserver(runSyncAfterLayout); 277 resizeObserver.observe(root); 278 } 279 280 Radzen[key] = { 281 grid: grid, 282 timeline: timeline, 283 onGrid: onGrid, 284 onTimeline: onTimeline, 285 onGridWheel: onGridWheel, 286 resizeObserver: resizeObserver 287 }; 288 289 timeline.scrollTop = grid.scrollTop; 290 }, 291 ganttScrollToFirstEvent: function (ganttId) { 292 if (!ganttId) return false; 293 var root = document.getElementById(ganttId); 294 if (!root) return false; 295 var timeline = root.querySelector('.rz-gantt-timeline-scroll'); 296 if (!timeline) return false; 297 var events = timeline.querySelectorAll('.rz-event'); 298 if (!events.length) return false; 299 300 var timelineRect = timeline.getBoundingClientRect(); 301 var thead = timeline.querySelector('thead'); 302 var headerHeight = thead ? thead.offsetHeight : 0; 303 304 var bestTop = Infinity; 305 var bestLeft = Infinity; 306 for (var i = 0; i < events.length; i++) { 307 var rect = events[i].getBoundingClientRect(); 308 if (rect.width <= 0) continue; 309 var contentTop = rect.top - timelineRect.top + timeline.scrollTop; 310 var contentLeft = rect.left - timelineRect.left + timeline.scrollLeft; 311 if (contentTop < bestTop || (contentTop === bestTop && contentLeft < bestLeft)) { 312 bestTop = contentTop; 313 bestLeft = contentLeft; 314 } 315 } 316 if (bestTop === Infinity) return false; 317 318 timeline.scrollTop = Math.max(0, bestTop - headerHeight - 4); 319 timeline.scrollLeft = Math.max(0, bestLeft - 40); 320 return true; 321 }, 322 ganttSyncScrollDispose: function (ganttId) { 323 if (!ganttId) { 324 return; 325 } 326 327 var key = ganttId + '_ganttScrollSync'; 328 var state = Radzen[key]; 329 if (!state) { 330 return; 331 } 332 333 if (state.grid && state.onGrid) { 334 state.grid.removeEventListener('scroll', state.onGrid); 335 } 336 if (state.timeline && state.onTimeline) { 337 state.timeline.removeEventListener('scroll', state.onTimeline); 338 } 339 if (state.grid && state.onGridWheel) { 340 state.grid.removeEventListener('wheel', state.onGridWheel); 341 } 342 if (state.resizeObserver) { 343 state.resizeObserver.disconnect(); 344 } 345 346 delete Radzen[key]; 347 }, 348 ganttInitDragResize: function (containerId, dotnetRef, timelineRangeMs, allowDrag, allowResize, rowHeightPx) { 349 var key = containerId + '_ganttDragResize'; 350 351 if (Radzen[key]) { 352 Radzen[key].dotnetRef = dotnetRef; 353 Radzen[key].timelineRangeMs = timelineRangeMs; 354 Radzen[key].allowDrag = allowDrag; 355 Radzen[key].allowResize = allowResize; 356 Radzen[key].rowHeightPx = rowHeightPx || 36; 357 return; 358 } 359 360 var root = document.getElementById(containerId); 361 if (!root) return; 362 363 var container = root.querySelector('.rz-gantt-timeline-scroll'); 364 if (!container) return; 365 366 var resizeThreshold = 6; 367 var dragThreshold = 3; 368 var drag = null; 369 var justDragged = false; 370 371 function getConfig() { 372 return Radzen[key]; 373 } 374 375 function buildLinkPath(x1, x2, y1, y2, rh, linkType) { 376 var offset = 12; 377 var halfRow = rh * 0.5; 378 var exitRight = linkType === 0 || linkType === 2; 379 var enterRight = linkType === 2 || linkType === 3; 380 var exitDir = exitRight ? 1 : -1; 381 var enterDir = enterRight ? 1 : -1; 382 var exitX = x1 + offset * exitDir; 383 var enterX = x2 + offset * enterDir; 384 var canGoStraight = exitRight !== enterRight 385 ? (exitRight ? x2 - x1 > offset * 2 : x1 - x2 > offset * 2) 386 : (exitRight ? exitX < enterX : exitX > enterX); 387 388 if (canGoStraight && y1 !== y2) { 389 var midX = (exitX + enterX) / 2; 390 return 'M' + x1 + ',' + y1 + ' L' + midX + ',' + y1 + ' L' + midX + ',' + y2 + ' L' + x2 + ',' + y2; 391 } 392 var midY = y2 > y1 ? y1 + halfRow : (y2 < y1 ? y1 - halfRow : y1 + halfRow); 393 return 'M' + x1 + ',' + y1 + ' L' + exitX + ',' + y1 + ' L' + exitX + ',' + midY + ' L' + enterX + ',' + midY + ' L' + enterX + ',' + y2 + ' L' + x2 + ',' + y2; 394 } 395 396 function updateConnectedPaths() { 397 if (!drag) return; 398 var svg = container.querySelector('.rz-gantt-links'); 399 if (!svg) return; 400 401 var config = getConfig(); 402 var rh = config.rowHeightPx; 403 var svgWidth = svg.getBoundingClientRect().width; 404 var idx = drag.index; 405 406 var paths = svg.querySelectorAll('path[data-from-index="' + idx + '"], path[data-to-index="' + idx + '"]'); 407 for (var i = 0; i < paths.length; i++) { 408 var path = paths[i]; 409 var fromIdx = path.dataset.fromIndex; 410 var toIdx = path.dataset.toIndex; 411 var linkType = parseInt(path.dataset.linkType, 10) || 0; 412 413 var fromBar = container.querySelector('[data-index="' + fromIdx + '"]'); 414 var toBar = container.querySelector('[data-index="' + toIdx + '"]'); 415 if (!fromBar || !toBar) continue; 416 417 var fromRow = parseInt(fromBar.dataset.row, 10); 418 var toRow = parseInt(toBar.dataset.row, 10); 419 420 var fromLeft = parseFloat(fromBar.style.getPropertyValue('inset-inline-start')) || 0; 421 var fromWidth = parseFloat(fromBar.style.width) || 0; 422 var toLeft = parseFloat(toBar.style.getPropertyValue('inset-inline-start')) || 0; 423 var toWidth = parseFloat(toBar.style.width) || 0; 424 var fromIsMilestone = fromBar.classList.contains('rz-gantt-milestone'); 425 var toIsMilestone = toBar.classList.contains('rz-gantt-milestone'); 426 427 var x1, x2; 428 if (linkType === 1) { x1 = fromLeft; x2 = toLeft; } 429 else if (linkType === 2) { x1 = fromIsMilestone ? fromLeft : fromLeft + fromWidth; x2 = toIsMilestone ? toLeft : toLeft + toWidth; } 430 else if (linkType === 3) { x1 = fromLeft; x2 = toIsMilestone ? toLeft : toLeft + toWidth; } 431 else { x1 = fromIsMilestone ? fromLeft : fromLeft + fromWidth; x2 = toLeft; } 432 433 var x1px = (x1 / 100) * svgWidth; 434 var x2px = (x2 / 100) * svgWidth; 435 var y1 = (fromRow + 0.5) * rh; 436 var y2 = (toRow + 0.5) * rh; 437 438 path.setAttribute('d', buildLinkPath(x1px, x2px, y1, y2, rh, linkType)); 439 } 440 } 441 442 function onMouseDown(e) { 443 var config = getConfig(); 444 if (!config) return; 445 446 var bar = e.target.closest('.rz-gantt-bar, .rz-gantt-milestone'); 447 if (!bar || e.button !== 0 || !bar.dataset.index) return; 448 449 var isMilestone = bar.classList.contains('rz-gantt-milestone'); 450 var barRect = bar.getBoundingClientRect(); 451 var offsetX = e.clientX - barRect.left; 452 453 var mode; 454 if (isMilestone) { 455 if (!config.allowDrag) return; 456 mode = 'move'; 457 } else if (config.allowResize && offsetX <= resizeThreshold) { 458 mode = 'resize-start'; 459 } else if (config.allowResize && barRect.width - offsetX <= resizeThreshold) { 460 mode = 'resize-end'; 461 } else if (config.allowDrag) { 462 mode = 'move'; 463 } else { 464 return; 465 } 466 467 e.preventDefault(); 468 469 var containerEl = bar.closest('.rz-gantt-row-container'); 470 var containerWidth = containerEl ? containerEl.getBoundingClientRect().width : 1; 471 472 drag = { 473 bar: bar, 474 mode: mode, 475 startClientX: e.clientX, 476 containerWidth: containerWidth, 477 originalLeft: parseFloat(bar.style.getPropertyValue('inset-inline-start')) || 0, 478 originalWidth: parseFloat(bar.style.width) || 0, 479 offsetStart: parseFloat(bar.dataset.offsetStart) || 0, 480 offsetEnd: parseFloat(bar.dataset.offsetEnd) || 0, 481 index: parseInt(bar.dataset.index, 10), 482 isMilestone: isMilestone, 483 hasMoved: false 484 }; 485 486 document.addEventListener('mousemove', onMouseMove); 487 document.addEventListener('mouseup', onMouseUp); 488 } 489 490 function onMouseMove(e) { 491 if (!drag) return; 492 493 var deltaX = e.clientX - drag.startClientX; 494 if (!drag.hasMoved && Math.abs(deltaX) < dragThreshold) return; 495 drag.hasMoved = true; 496 497 var percentDelta = (deltaX / drag.containerWidth) * 100; 498 499 if (drag.mode === 'move') { 500 drag.bar.style.setProperty('inset-inline-start', (drag.originalLeft + percentDelta) + '%'); 501 } else if (drag.mode === 'resize-start') { 502 var newWidth = drag.originalWidth - percentDelta; 503 if (newWidth > 0.1) { 504 drag.bar.style.setProperty('inset-inline-start', (drag.originalLeft + percentDelta) + '%'); 505 drag.bar.style.width = newWidth + '%'; 506 } 507 } else if (drag.mode === 'resize-end') { 508 var newWidth = drag.originalWidth + percentDelta; 509 if (newWidth > 0.1) { 510 drag.bar.style.width = newWidth + '%'; 511 } 512 } 513 514 drag.bar.style.zIndex = '10'; 515 drag.bar.style.opacity = '0.85'; 516 document.body.style.cursor = drag.mode === 'move' ? 'grabbing' : 'ew-resize'; 517 518 updateConnectedPaths(); 519 } 520 521 function onMouseUp(e) { 522 if (!drag) return; 523 524 document.removeEventListener('mousemove', onMouseMove); 525 document.removeEventListener('mouseup', onMouseUp); 526 527 drag.bar.style.zIndex = ''; 528 drag.bar.style.opacity = ''; 529 document.body.style.cursor = ''; 530 531 if (drag.hasMoved) { 532 justDragged = true; 533 534 var deltaX = e.clientX - drag.startClientX; 535 var percentDelta = (deltaX / drag.containerWidth) * 100; 536 var config = getConfig(); 537 var msPerPercent = config.timelineRangeMs / 100; 538 var deltaMs = percentDelta * msPerPercent; 539 540 var newStartMs, newEndMs; 541 if (drag.mode === 'move') { 542 newStartMs = drag.offsetStart + deltaMs; 543 newEndMs = drag.offsetEnd + deltaMs; 544 } else if (drag.mode === 'resize-start') { 545 newStartMs = drag.offsetStart + deltaMs; 546 newEndMs = drag.offsetEnd; 547 } else { 548 newStartMs = drag.offsetStart; 549 newEndMs = drag.offsetEnd + deltaMs; 550 } 551 552 var eventType = drag.mode === 'move' ? 'move' : 'resize'; 553 try { suppressDisposed(config.dotnetRef.invokeMethodAsync('OnGanttBarInteractionEnd', drag.index, eventType, newStartMs, newEndMs)); } catch { } 554 } 555 556 drag = null; 557 } 558 559 function onMouseMoveHover(e) { 560 if (drag) return; 561 var config = getConfig(); 562 if (!config) return; 563 564 var bar = e.target.closest('.rz-gantt-bar, .rz-gantt-milestone'); 565 if (!bar || !bar.dataset.index) return; 566 567 if (bar.classList.contains('rz-gantt-milestone')) { 568 bar.style.cursor = config.allowDrag ? 'grab' : ''; 569 return; 570 } 571 572 var barRect = bar.getBoundingClientRect(); 573 var offsetX = e.clientX - barRect.left; 574 575 if (config.allowResize && (offsetX <= resizeThreshold || barRect.width - offsetX <= resizeThreshold)) { 576 bar.style.cursor = 'ew-resize'; 577 } else if (config.allowDrag) { 578 bar.style.cursor = 'grab'; 579 } 580 } 581 582 function onClickCapture(e) { 583 if (justDragged) { 584 e.stopPropagation(); 585 e.preventDefault(); 586 justDragged = false;
587 } 588 } 589 590 container.addEventListener('mousedown', onMouseDown); 591 container.addEventListener('mousemove', onMouseMoveHover); 592 container.addEventListener('click', onClickCapture, true); 593 594 Radzen[key] = { 595 container: container, 596 dotnetRef: dotnetRef, 597 timelineRangeMs: timelineRangeMs, 598 allowDrag: allowDrag, 599 allowResize: allowResize, 600 rowHeightPx: rowHeightPx || 36, 601 onMouseDown: onMouseDown, 602 onMouseMoveHover: onMouseMoveHover, 603 onClickCapture: onClickCapture 604 }; 605 }, 606 ganttDisposeDragResize: function (containerId) { 607 var key = containerId + '_ganttDragResize'; 608 var config = Radzen[key]; 609 if (!config) return; 610 611 config.container.removeEventListener('mousedown', config.onMouseDown); 612 config.container.removeEventListener('mousemove', config.onMouseMoveHover); 613 config.container.removeEventListener('click', config.onClickCapture, true); 614 delete Radzen[key]; 615 }, 616 preventDefaultAndStopPropagation: function (e) { 617 e.preventDefault(); 618 e.stopPropagation(); 619 }, 620 preventArrows: function (el) { 621 var preventDefault = function (e) { 622 if (e.keyCode === 38 || e.keyCode === 40) { 623 e.preventDefault(); 624 return false; 625 } 626 }; 627 if (el) { 628 el.addEventListener('keydown', preventDefault, false); 629 } 630 }, 631 selectTab: function (id, index) { 632 var el = document.getElementById(id); 633 if (el && el.parentNode && el.parentNode.previousElementSibling) { 634 var tablist = el.parentNode.previousElementSibling; 635 var count = el.parentNode.children.length; 636 for (var i = 0; i < count; i++) { 637 var content = el.parentNode.children[i]; 638 if (content) { 639 content.style.display = i == index ? '' : 'none'; 640 content.setAttribute('aria-hidden', i == index ? 'false' : 'true'); 641 } 642 var header = tablist.children[i]; 643 if (header) { 644 var btn = header.querySelector('[role="tab"]') || header; 645 if (i == index) { 646 header.classList.add('rz-tabview-selected'); 647 header.classList.add('rz-state-focused'); 648 btn.setAttribute('aria-selected', 'true'); 649 } 650 else { 651 header.classList.remove('rz-tabview-selected'); 652 header.classList.remove('rz-state-focused'); 653 btn.setAttribute('aria-selected', 'false'); 654 } 655 } 656 } 657 if (tablist.getAttribute && tablist.getAttribute('role') === 'tablist') { 658 var activeBtn = tablist.children[index] && (tablist.children[index].querySelector('[role="tab"]') || tablist.children[index]); 659 if (activeBtn && activeBtn.id) { 660 tablist.setAttribute('aria-activedescendant', activeBtn.id); 661 } 662 } 663 } 664 }, 665 createAccordion: function (el, multiple) { 666 function getItems() { 667 var headers = []; 668 var expanders = []; 669 for (var i = 0; i < el.children.length; i++) { 670 var child = el.children[i]; 671 if (child.classList.contains('rz-accordion-header')) { 672 headers.push(child); 673 } else if (child.classList.contains('rz-expander')) { 674 expanders.push(child); 675 } 676 } 677 return { headers: headers, expanders: expanders }; 678 } 679 680 function toggleItem(index, expanded) { 681 var items = getItems(); 682 if (index < 0 || index >= items.headers.length) return; 683 684 if (!multiple) { 685 for (var i = 0; i < items.headers.length; i++) { 686 if (i !== index) { 687 var btn = items.headers[i].querySelector('button'); 688 var icon = items.headers[i].querySelector('.rz-accordion-toggle-icon'); 689 if (btn) btn.setAttribute('aria-expanded', 'false'); 690 if (icon) { 691 icon.classList.remove('rz-state-expanded'); 692 icon.classList.add('rz-state-collapsed'); 693 } 694 items.expanders[i].classList.remove('rz-state-expanded'); 695 items.expanders[i].classList.add('rz-state-collapsed'); 696 items.expanders[i].setAttribute('aria-hidden', 'true'); 697 } 698 } 699 } 700 701 var button = items.headers[index].querySelector('button'); 702 var toggleIcon = items.headers[index].querySelector('.rz-accordion-toggle-icon'); 703 if (button) button.setAttribute('aria-expanded', expanded ? 'true' : 'false'); 704 if (toggleIcon) { 705 toggleIcon.classList.remove(expanded ? 'rz-state-collapsed' : 'rz-state-expanded'); 706 toggleIcon.classList.add(expanded ? 'rz-state-expanded' : 'rz-state-collapsed'); 707 } 708 items.expanders[index].classList.remove(expanded ? 'rz-state-collapsed' : 'rz-state-expanded'); 709 items.expanders[index].classList.add(expanded ? 'rz-state-expanded' : 'rz-state-collapsed');
710 items.expanders[index].setAttribute('aria-hidden', expanded ? 'false' : 'true'); 711 } 712 713 function onKeyDown(e) { 714 var key = e.code || e.key; 715 if (key !== 'ArrowUp' && key !== 'ArrowDown' && key !== 'Home' && key !== 'End') { 716 return; 717 } 718 var target = e.target; 719 if (target && target.closest && target.closest('.rz-accordion-header')) { 720 e.preventDefault(); 721 } 722 } 723 724 el.addEventListener('keydown', onKeyDown); 725 726 return { 727 toggle: function (index, expanded) { toggleItem(index, expanded); }, 728 setMultiple: function (value) { multiple = value; }, 729 dispose: function () { el.removeEventListener('keydown', onKeyDown); } 730 }; 731 }, 732 loadGoogleMaps: function (defaultView, apiKey, resolve, reject, language) { 733 resolveCallbacks.push(resolve); 734 rejectCallbacks.push(reject); 735 736 if (defaultView['rz_map_init']) { 737 return; 738 } 739 740 defaultView['rz_map_init'] = function () { 741 for (var i = 0; i < resolveCallbacks.length; i++) { 742 resolveCallbacks[i](defaultView.google); 743 } 744 }; 745 746 var document = defaultView.document; 747 var script = document.createElement('script'); 748 749 script.src = 750 'https://maps.googleapis.com/maps/api/js?' + 751 (language ? 'language=' + language + '&' : '') + 752 (apiKey ? 'key=' + apiKey + '&' : '') + 753 'callback=rz_map_init&libraries=marker'; 754 755 script.async = true; 756 script.defer = true; 757 script.onerror = function (err) { 758 for (var i = 0; i < rejectCallbacks.length; i++) { 759 rejectCallbacks[i](err); 760 } 761 }; 762 763 document.body.appendChild(script); 764 }, 765 createMap: function (wrapper, ref, id, apiKey, mapId, zoom, center, markers, options, fitBoundsToMarkersOnUpdate, language) { 766 var api = function () { 767 var defaultView = document.defaultView; 768 769 return new Promise(function (resolve, reject) { 770 if (defaultView.google && defaultView.google.maps) { 771 return resolve(defaultView.google); 772 } 773 774 Radzen.loadGoogleMaps(defaultView, apiKey, resolve, reject, language); 775 }); 776 }; 777 778 api().then(function (google) { 779 Radzen[id] = ref; 780 Radzen[id].google = google; 781 782 Radzen[id].instance = new google.maps.Map(wrapper, { 783 center: center, 784 zoom: zoom, 785 mapId: mapId 786 }); 787 788 Radzen[id].instance.addListener('click', function (e) { 789 try { Radzen[id].invokeMethodAsync('RadzenGoogleMap.OnMapClick', { 790 Position: {Lat: e.latLng.lat(), Lng: e.latLng.lng()} 791 }); } catch { } 792 }); 793 794 Radzen.updateMap(id, apiKey, zoom, center, markers, options, fitBoundsToMarkersOnUpdate, language); 795 }); 796 797 return { 798 dispose: function () { 799 if (Radzen[id] && Radzen[id].instance) { 800 delete Radzen[id].instance; 801 } 802 } 803 }; 804 }, 805 updateMap: function (id, apiKey, zoom, center, markers, options, fitBoundsToMarkersOnUpdate, language) { 806 var api = function () { 807 var defaultView = document.defaultView; 808 809 return new Promise(function (resolve, reject) { 810 if (defaultView.google && defaultView.google.maps) { 811 return resolve(defaultView.google); 812 } 813 814 Radzen.loadGoogleMaps(defaultView, apiKey, resolve, reject, language); 815 }); 816 }; 817 api().then(function (google) { 818 let markerBounds = new google.maps.LatLngBounds(); 819 820 if (Radzen[id] && Radzen[id].instance) { 821 if (Radzen[id].instance.markers && Radzen[id].instance.markers.length) { 822 for (var i = 0; i < Radzen[id].instance.markers.length; i++) { 823 Radzen[id].instance.markers[i].setMap(null); 824 } 825 } 826 827 if (markers) { 828 Radzen[id].instance.markers = []; 829 830 markers.forEach(function (m) { 831 var content; 832 833 if (m.label) { 834 content = document.createElement('span'); 835 content.innerHTML = m.label; 836 } 837 838 var marker = new this.google.maps.marker.AdvancedMarkerElement({ 839 position: m.position, 840 title: m.title, 841 content: content 842 }); 843 844 marker.addListener('click', function (e) { 845 try { Radzen[id].invokeMethodAsync('RadzenGoogleMap.OnMarkerClick', { 846 Title: marker.title, 847 Label: marker.content.innerText, 848 Position: marker.position 849 }); } catch { } 850 }); 851 852 marker.setMap(Radzen[id].instance); 853 854 Radzen[id].instance.markers.push(marker); 855 856 markerBounds.extend(marker.position); 857 }); 858 } 859 860 if (zoom) { 861 Radzen[id].instance.setZoom(zoom); 862 } 863 864 if (center) { 865 Radzen[id].instance.setCenter(center); 866 } 867 868 if (options) { 869 Radzen[id].instance.setOptions(options); 870 } 871 872 if (markers && fitBoundsToMarkersOnUpdate) { 873 Radzen[id].instance.fitBounds(markerBounds); 874 } 875 } 876 }); 877 }, 878 focusSecurityCode: function (el) { 879 if (!el) return; 880 var firstInput = el.querySelector('.rz-security-code-input'); 881 if (firstInput) { 882 setTimeout(function () { firstInput.focus() }, 500); 883 } 884 }, 885 createSecurityCode: function (id, ref, el, isNumber) { 886 if (!el || !ref) return { dispose: function() {} }; 887 888 var hidden = el.querySelector('input[type="hidden"]'); 889 890 Radzen[id] = {}; 891 892 Radzen[id].inputs = [...el.querySelectorAll('.rz-security-code-input')]; 893 894 var isAndroid = navigator.userAgent.match(/Android/i); 895 896 Radzen[id].paste = function (e) { 897 if (e.clipboardData) { 898 var value = e.clipboardData.getData('text'); 899 900 if (value) { 901 for (var i = 0; i < Math.min(value.length, Radzen[id].inputs.length); i++) { 902 if (isNumber && isNaN(+value[i])) { 903 continue; 904 } 905 Radzen[id].inputs[i].value = value[i]; 906 } 907 908 var code = Radzen[id].inputs.map(i => i.value).join('').trim(); 909 hidden.value = code; 910 911 try { suppressDisposed(ref.invokeMethodAsync('RadzenSecurityCode.OnValueChange', code)); } catch { } 912 913 Radzen[id].inputs[Radzen[id].inputs.length - 1].focus(); 914 } 915 916 e.preventDefault(); 917 } 918 } 919 Radzen[id].keyPress = function (e) { 920 var keyCode = e.data ? e.data.charCodeAt(0) : e.which; 921 var ch = e.data || String.fromCharCode(e.which); 922 923 if (e.metaKey || 924 e.ctrlKey || 925 keyCode == 9 || 926 keyCode == 8 || 927 keyCode == 13 928 ) { 929 return; 930 } 931 932 if (isNumber && (keyCode < 48 || keyCode > 57)) { 933 e.preventDefault(); 934 return; 935 } 936 937 // Android-specific: prevent default to avoid double input 938 if (isAndroid && e.type === 'textInput') { 939 e.preventDefault(); 940 } 941 942 if (e.currentTarget.value == ch) { 943 return; 944 } 945 946 e.currentTarget.value = ch; 947 948 var value = Radzen[id].inputs.map(i => i.value).join('').trim(); 949 hidden.value = value; 950 951 try { suppressDisposed(ref.invokeMethodAsync('RadzenSecurityCode.OnValueChange', value)); } catch { } 952 953 var index = Radzen[id].inputs.indexOf(e.currentTarget); 954 if (index < Radzen[id].inputs.length - 1) { 955 Radzen[id].inputs[index + 1].focus(); 956 } 957 } 958 959 Radzen[id].keyDown = function (e) { 960 var keyCode = e.which || e.keyCode; 961 if (keyCode == 8) { 962 e.currentTarget.value = ''; 963 964 var value = Radzen[id].inputs.map(i => i.value).join('').trim(); 965 hidden.value = value; 966 967 try { suppressDisposed(ref.invokeMethodAsync('RadzenSecurityCode.OnValueChange', value)); } catch { } 968 969 var index = Radzen[id].inputs.indexOf(e.currentTarget); 970 if (index > 0) { 971 Radzen[id].inputs[index - 1].focus(); 972 } 973 } 974 } 975 976 for (var i = 0; i < Radzen[id].inputs.length; i++) { 977 Radzen[id].inputs[i].addEventListener(isAndroid ? 'textInput' : 'keypress', Radzen[id].keyPress); 978 Radzen[id].inputs[i].addEventListener('keydown', Radzen[id].keyDown); 979 Radzen[id].inputs[i].addEventListener('paste', Radzen[id].paste); 980 } 981 982 return { 983 dispose: function () { 984 if (!Radzen[id]) return; 985 986 var inputs = el.getElementsByTagName('input'); 987 988 if (Radzen[id].keyPress && Radzen[id].keyDown && Radzen[id].paste) { 989 for (var i = 0; i < inputs.length; i++) { 990 inputs[i].removeEventListener(isAndroid ? 'textInput' : 'keypress', Radzen[id].keyPress); 991 inputs[i].removeEventListener('keydown', Radzen[id].keyDown); 992 inputs[i].removeEventListener('paste', Radzen[id].paste); 993 } 994 delete Radzen[id].keyPress; 995 delete Radzen[id].keyDown; 996 delete Radzen[id].paste; 997 } 998 999 Radzen[id] = null; 1000 } 1001 }; 1002 }, 1003 createSlider: function ( 1004 id, 1005 slider, 1006 parent, 1007 range, 1008 minHandle, 1009 maxHandle, 1010 min, 1011 max, 1012 value, 1013 step, 1014 isVertical 1015 ) { 1016 Radzen[id] = {}; 1017 Radzen[id].mouseMoveHandler = function (e) { 1018 e.preventDefault(); 1019 1020 var handle = slider.isMin ? minHandle : maxHandle; 1021 1022 if (!slider.canChange) return; 1023 1024 var offsetX = 1025 e.targetTouches && e.targetTouches[0] 1026 ? e.targetTouches[0].pageX - e.target.getBoundingClientRect().left 1027 : e.pageX - handle.getBoundingClientRect().left; 1028 1029 var offsetY = 1030 e.targetTouches && e.targetTouches[0] 1031 ? e.targetTouches[0].pageY - e.target.getBoundingClientRect().top 1032 : e.pageY - handle.getBoundingClientRect().top; 1033 1034 var percent = isVertical ? (parent.offsetHeight - handle.offsetTop - offsetY) / parent.offsetHeight 1035 : (Radzen.isRTL(handle) ? parent.offsetWidth - handle.offsetLeft - offsetX : handle.offsetLeft + offsetX) / parent.offsetWidth; 1036 1037 if (percent > 1) { 1038 percent = 1; 1039 } else if (percent < 0) { 1040 percent = 0; 1041 } 1042 1043 var newValue = percent * (max - min) + min; 1044 1045 if ( 1046 slider.canChange && 1047 newValue >= min && 1048 newValue <= max 1049 ) { 1050 try { slider.invokeMethodAsync( 1051 'RadzenSlider.OnValueChange', 1052 newValue, 1053 !!slider.isMin 1054 ); } catch { } 1055 } 1056 }; 1057 1058 Radzen[id].mouseDownHandler = function (e) { 1059 if (parent.classList.contains('rz-state-disabled')) return; 1060 1061 document.addEventListener('mousemove', Radzen[id].mouseMoveHandler); 1062 document.addEventListener('touchmove', Radzen[id].mouseMoveHandler, { 1063 passive: false, capture: true 1064 }); 1065 1066 document.addEventListener('mouseup', Radzen[id].mouseUpHandler); 1067 document.addEventListener('touchend', Radzen[id].mouseUpHandler, { 1068 passive: true 1069 }); 1070 1071 if (minHandle == e.target || maxHandle == e.target) { 1072 slider.canChange = true; 1073 slider.isMin = minHandle == e.target; 1074 } else { 1075 1076 var offsetX = 1077 e.targetTouches && e.targetTouches[0] 1078 ? e.targetTouches[0].pageX - e.target.getBoundingClientRect().left 1079 : e.offsetX; 1080 1081 var percent = offsetX / parent.offsetWidth; 1082 1083 var newValue = percent * (max - min) + min; 1084 var oldValue = range ? value[slider.isMin ? 0 : 1] : value; 1085 if (newValue >= min && newValue <= max && newValue != oldValue) { 1086 try { slider.invokeMethodAsync( 1087 'RadzenSlider.OnValueChange', 1088 newValue, 1089 !!slider.isMin 1090 ); } catch { } 1091 } 1092 } 1093 }; 1094 1095 Radzen[id].mouseUpHandler = function (e) { 1096 slider.canChange = false;
1097 document.removeEventListener('mousemove', Radzen[id].mouseMoveHandler); 1098 document.removeEventListener('touchmove', Radzen[id].mouseMoveHandler, { 1099 passive: false, capture: true 1100 }); 1101 document.removeEventListener('mouseup', Radzen[id].mouseUpHandler); 1102 document.removeEventListener('touchend', Radzen[id].mouseUpHandler, { 1103 passive: true 1104 }); 1105 }; 1106 1107 parent.addEventListener('mousedown', Radzen[id].mouseDownHandler); 1108 parent.addEventListener('touchstart', Radzen[id].mouseDownHandler, { 1109 passive: true 1110 }); 1111 1112 return { dispose: function() { 1113 if (!Radzen[id]) return; 1114 1115 if (Radzen[id].mouseMoveHandler) { 1116 document.removeEventListener('mousemove', Radzen[id].mouseMoveHandler); 1117 document.removeEventListener('touchmove', Radzen[id].mouseMoveHandler); 1118 delete Radzen[id].mouseMoveHandler; 1119 } 1120 if (Radzen[id].mouseUpHandler) { 1121 document.removeEventListener('mouseup', Radzen[id].mouseUpHandler); 1122 document.removeEventListener('touchend', Radzen[id].mouseUpHandler); 1123 delete Radzen[id].mouseUpHandler; 1124 } 1125 if (Radzen[id].mouseDownHandler) { 1126 parent.removeEventListener('mousedown', Radzen[id].mouseDownHandler); 1127 parent.removeEventListener('touchstart', Radzen[id].mouseDownHandler); 1128 delete Radzen[id].mouseDownHandler; 1129 } 1130 1131 Radzen[id] = null; 1132 }}; 1133 }, 1134 prepareDrag: function (el) { 1135 if (el) { 1136 el.ondragover = function (e) { e.preventDefault(); }; 1137 el.ondragstart = function (e) { e.dataTransfer.setData('', e.target.id); }; 1138 } 1139 }, 1140 focusElement: function (elementId, onlyIfFocusNotMoved) { 1141 var el = document.getElementById(elementId); 1142 if (!el) return; 1143 if (onlyIfFocusNotMoved) { 1144 var ae = document.activeElement; 1145 if (ae && ae != document.body && ae != el && !ae.closest('.rz-lookup-panel, .rz-dropdown-panel, .rz-multiselect-panel')) { 1146 return; 1147 } 1148 } 1149 el.focus(); 1150 }, 1151 focusNext: function (container, reverse) { 1152 if (!container) return; 1153 var selector = 'a[href]:not([disabled]):not([tabindex="-1"]), button:not([disabled]):not([tabindex="-1"]), input:not([disabled]):not([type="hidden"]):not([tabindex="-1"]), select:not([disabled]):not([tabindex="-1"]), textarea:not([disabled]):not([tabindex="-1"]), [tabindex]:not([tabindex="-1"]):not([disabled])'; 1154 var candidates = Array.from(document.querySelectorAll(selector)).filter(function (el) { 1155 return (el.offsetWidth > 0 || el.offsetHeight > 0) && el !== container && !container.contains(el); 1156 }); 1157 if (reverse) { 1158 for (var i = candidates.length - 1; i >= 0; i--) { 1159 if (container.compareDocumentPosition(candidates[i]) & Node.DOCUMENT_POSITION_PRECEDING) { 1160 candidates[i].focus(); 1161 return; 1162 } 1163 } 1164 } else { 1165 for (var i = 0; i < candidates.length; i++) { 1166 if (container.compareDocumentPosition(candidates[i]) & Node.DOCUMENT_POSITION_FOLLOWING) { 1167 candidates[i].focus(); 1168 return; 1169 } 1170 } 1171 } 1172 }, 1173 scrollCarouselItem: function (el, duration) { 1174 var container = el.parentElement; 1175 var target = el.offsetLeft; 1176 if (duration == null || duration < 0) { 1177 container.scroll(target, 0); 1178 return; 1179 } 1180 if (duration === 0) { 1181 container.style.scrollBehavior = 'auto'; 1182 container.scroll(target, 0); 1183 container.style.scrollBehavior = ''; 1184 return; 1185 } 1186 container.style.scrollBehavior = 'auto'; 1187 container.style.scrollSnapType = 'none'; 1188 var start = container.scrollLeft; 1189 var distance = target - start; 1190 var startTime = null; 1191 function step(timestamp) { 1192 if (!startTime) startTime = timestamp; 1193 var elapsed = timestamp - startTime; 1194 var progress = Math.min(elapsed / duration, 1); 1195 var ease = progress < 0.5 ? 2 * progress * progress : 1 - Math.pow(-2 * progress + 2, 2) / 2; 1196 container.scrollLeft = start + distance * ease; 1197 if (elapsed < duration) { 1198 requestAnimationFrame(step); 1199 } else { 1200 container.style.scrollBehavior = ''; 1201 container.style.scrollSnapType = ''; 1202 } 1203 } 1204 requestAnimationFrame(step); 1205 }, 1206 createCarousel: function (container, ref) { 1207 var scrollTimeout = null; 1208 function handler() { 1209 if (scrollTimeout) clearTimeout(scrollTimeout); 1210 scrollTimeout = setTimeout(function () { 1211 var children = container.children; 1212 if (!children.length) return; 1213 var itemWidth = children[0].offsetWidth; 1214 if (itemWidth === 0) return; 1215 var index = Math.round(container.scrollLeft / itemWidth); 1216 if (index < 0) index = 0; 1217 if (index >= children.length) index = children.length - 1; 1218 try { ref.invokeMethodAsync('RadzenCarousel.OnScroll', index); } catch { } 1219 }, 100); 1220 } 1221 container.addEventListener('scroll', handler, { passive: true }); 1222 return { dispose: function () { container.removeEventListener('scroll', handler); } }; 1223 }, 1224 scrollIntoViewIfNeeded: function (ref, selector) { 1225 var el = selector ? ref.getElementsByClassName(selector)[0] : ref; 1226 if (el && el.scrollIntoViewIfNeeded) { 1227 el.scrollIntoViewIfNeeded(); 1228 } else if (el && el.scrollIntoView) { 1229 el.scrollIntoView(); 1230 } 1231 }, 1232 scrollIntoViewIfNeededById: function (id) { 1233 var el = document.getElementById(id); 1234 if (el) { 1235 Radzen.scrollIntoViewIfNeeded(el); 1236 } 1237 }, 1238 focusPanelMenuItem: function (menu, activeId) { 1239 if (!menu) return; 1240 var focused = menu.querySelectorAll('.rz-navigation-item.rz-state-focused'); 1241 for (var i = 0; i < focused.length; i++) { 1242 focused[i].classList.remove('rz-state-focused'); 1243 } 1244 if (activeId) { 1245 menu.setAttribute('aria-activedescendant', activeId); 1246 var el = document.getElementById(activeId); 1247 if (el) { 1248 el.classList.add('rz-state-focused'); 1249 Radzen.scrollIntoViewIfNeeded(el); 1250 } 1251 } else { 1252 menu.removeAttribute('aria-activedescendant'); 1253 } 1254 }, 1255 updateActiveDescendant: function (ul, li, index) { 1256 if (!ul) return; 1257 // The popup is appended to document.body when opened, so ul.closest('[role="combobox"]') 1258 // fails once the dropdown is open. Fall back to a reverse lookup via aria-controls. 1259 // There can be more than one combobox referencing the same listbox (the trigger and a 1260 // filter input inside the popup). aria-activedescendant must be set only on the element 1261 // that currently has DOM focus (the filter input while filtering, otherwise the trigger), 1262 // so a non-focused combobox never carries a stale active-descendant. 1263 var comboboxes = []; 1264 var ancestor = ul.closest('[role="combobox"]'); 1265 if (ancestor) { 1266 comboboxes.push(ancestor); 1267 } 1268 if (ul.id && window.CSS && CSS.escape) { 1269 var escapedId = CSS.escape(ul.id); 1270 var matches = document.querySelectorAll( 1271 '[aria-controls="' + escapedId + '"][role="combobox"]' 1272 ); 1273 for (var i = 0; i < matches.length; i++) { 1274 if (comboboxes.indexOf(matches[i]) === -1) { 1275 comboboxes.push(matches[i]); 1276 } 1277 } 1278 } 1279 1280 var focused = null; 1281 for (var f = 0; f < comboboxes.length; f++) { 1282 if (comboboxes[f] === document.activeElement) { 1283 focused = comboboxes[f]; 1284 break; 1285 } 1286 } 1287 if (!focused && comboboxes.length) { 1288 focused = comboboxes[0]; 1289 } 1290 1291 for (var c = 0; c < comboboxes.length; c++) {
1292 if (comboboxes[c] !== focused) { 1293 comboboxes[c].removeAttribute('aria-activedescendant'); 1294 } 1295 } 1296 1297 if (li && focused) { 1298 var itemId = ul.id + '-' + index; 1299 li.id = itemId; 1300 focused.setAttribute('aria-activedescendant', itemId); 1301 } else if (focused) { 1302 focused.removeAttribute('aria-activedescendant'); 1303 } 1304 }, 1305 selectListItem: function (input, ul, index) { 1306 if (!ul) return; 1307 1308 var childNodes = ul.getElementsByTagName('LI'); 1309 1310 var highlighted = ul.querySelectorAll('.rz-state-highlight'); 1311 if (highlighted.length) { 1312 for (var i = 0; i < highlighted.length; i++) { 1313 highlighted[i].classList.remove('rz-state-highlight'); 1314 } 1315 } 1316 1317 ul.nextSelectedIndex = index; 1318 1319 if ( 1320 ul.nextSelectedIndex >= 0 && 1321 ul.nextSelectedIndex <= childNodes.length - 1 1322 ) { 1323 childNodes[ul.nextSelectedIndex].classList.add('rz-state-highlight'); 1324 childNodes[ul.nextSelectedIndex].scrollIntoView({block:'nearest'}); 1325 Radzen.updateActiveDescendant(ul, childNodes[ul.nextSelectedIndex], ul.nextSelectedIndex); 1326 } else { 1327 Radzen.updateActiveDescendant(ul, null, -1); 1328 } 1329 }, 1330 focusListItem: function (input, ul, isDown, startIndex) { 1331 if (!ul) return; 1332 var childNodes = ul.getElementsByTagName('LI'); 1333 1334 if (!childNodes || childNodes.length == 0) return; 1335 1336 if (startIndex == undefined || startIndex == null) { 1337 startIndex = -1; 1338 } 1339 1340 ul.nextSelectedIndex = startIndex; 1341 if (isDown) { 1342 while (ul.nextSelectedIndex < childNodes.length - 1) { 1343 ul.nextSelectedIndex++; 1344 if (!childNodes[ul.nextSelectedIndex].classList.contains('rz-state-disabled')) 1345 break; 1346 } 1347 } else { 1348 while (ul.nextSelectedIndex >= 0) { 1349 ul.nextSelectedIndex--; 1350 if (!childNodes[ul.nextSelectedIndex] || !childNodes[ul.nextSelectedIndex].classList.contains('rz-state-disabled')) 1351 break; 1352 } 1353 } 1354 1355 var highlighted = ul.querySelectorAll('.rz-state-highlight'); 1356 if (highlighted.length) { 1357 for (var i = 0; i < highlighted.length; i++) { 1358 highlighted[i].classList.remove('rz-state-highlight'); 1359 } 1360 } 1361 1362 if ( 1363 ul.nextSelectedIndex >= 0 && 1364 ul.nextSelectedIndex <= childNodes.length - 1 1365 ) { 1366 childNodes[ul.nextSelectedIndex].classList.add('rz-state-highlight'); 1367 Radzen.scrollIntoViewIfNeeded(childNodes[ul.nextSelectedIndex]); 1368 Radzen.updateActiveDescendant(ul, childNodes[ul.nextSelectedIndex], ul.nextSelectedIndex); 1369 } else { 1370 Radzen.updateActiveDescendant(ul, null, -1); 1371 } 1372 1373 return ul.nextSelectedIndex; 1374 }, 1375 focusVirtualListItem: function (ul, absoluteIndex, totalCount) { 1376 if (!ul) return; 1377 1378 var childNodes = ul.getElementsByTagName('LI'); 1379 if (!childNodes || childNodes.length == 0) return; 1380 1381 var itemHeight = childNodes[0].offsetHeight; 1382 if (itemHeight <= 0) return; 1383 1384 var wrapper = ul.parentElement; 1385 if (!wrapper) return; 1386 1387 // Scroll to make the item at absoluteIndex visible 1388 if (absoluteIndex >= 0 && absoluteIndex < totalCount) { 1389 var targetTop = absoluteIndex * itemHeight; 1390 var targetBottom = targetTop + itemHeight; 1391 var viewTop = wrapper.scrollTop; 1392 var viewBottom = viewTop + wrapper.clientHeight; 1393 1394 if (targetBottom > viewBottom) { 1395 wrapper.scrollTop = targetBottom - wrapper.clientHeight; 1396 } else if (targetTop < viewTop) { 1397 wrapper.scrollTop = targetTop; 1398 } 1399 } 1400 1401 // Highlight the correct item after scroll 1402 function highlightItem() { 1403 var lis = ul.getElementsByTagName('LI'); 1404 if (!lis || lis.length == 0) return; 1405 1406 var highlighted = ul.querySelectorAll('.rz-state-highlight'); 1407 for (var i = 0; i < highlighted.length; i++) { 1408 highlighted[i].classList.remove('rz-state-highlight'); 1409 } 1410 1411 // Determine the start index of rendered items from the top spacer 1412 var startIndex = 0; 1413 var spacer = ul.firstElementChild; 1414 if (spacer && spacer.tagName !== 'LI' && spacer.style && spacer.style.height) { 1415 startIndex = Math.round(parseFloat(spacer.style.height) / itemHeight); 1416 } 1417 1418 var relativeIndex = absoluteIndex - startIndex; 1419 if (relativeIndex >= 0 && relativeIndex < lis.length) { 1420 lis[relativeIndex].classList.add('rz-state-highlight'); 1421 lis[relativeIndex].scrollIntoView({ block: 'nearest' }); 1422 Radzen.updateActiveDescendant(ul, lis[relativeIndex], absoluteIndex); 1423 } else { 1424 Radzen.updateActiveDescendant(ul, null, -1); 1425 } 1426 } 1427 1428 // Use MutationObserver to wait for Virtualize to re-render after scroll 1429 var observer = new MutationObserver(function () { 1430 observer.disconnect(); 1431 highlightItem(); 1432 }); 1433 observer.observe(ul, { childList: true, subtree: true }); 1434 1435 // Also highlight immediately in case no DOM change is needed 1436 highlightItem(); 1437 1438 // Disconnect observer after a timeout to avoid memory leaks 1439 setTimeout(function () { observer.disconnect(); }, 500); 1440 }, 1441 clearFocusedHeaderCell: function (gridId) { 1442 var grid = document.getElementById(gridId); 1443 if (!grid) return; 1444 1445 var table = grid.querySelector('.rz-grid-table'); 1446 var thead = table.getElementsByTagName("thead")[0]; 1447 var highlightedCells = thead.querySelectorAll('.rz-state-focused'); 1448 if (highlightedCells.length) { 1449 for (var i = 0; i < highlightedCells.length; i++) { 1450 highlightedCells[i].classList.remove('rz-state-focused'); 1451 } 1452 } 1453 }, 1454 focusTableRow: function (gridId, key, rowIndex, cellIndex, isVirtual) { 1455 var grid = document.getElementById(gridId); 1456 if (!grid) return; 1457 1458 var table = grid.querySelector('.rz-grid-table'); 1459 var tbody = table.tBodies[0]; 1460 var thead = table.tHead; 1461 1462 var rows = (cellIndex != null && thead && thead.rows && thead.rows.length ? [...thead.rows] : []).c
1462oncat(tbody && tbody.rows && tbody.rows.length ? [...tbody.rows] : []); 1463 1464 if (isVirtual && (key == 'ArrowUp' || key == 'ArrowDown' || key == 'PageUp' || key == 'PageDown' || key == 'Home' || key == 'End')) { 1465 if (rowIndex == 0 && (key == 'End' || key == 'PageDown')) { 1466 var highlightedCells = thead.querySelectorAll('.rz-state-focused'); 1467 if (highlightedCells.length) { 1468 for (var i = 0; i < highlightedCells.length; i++) { 1469 highlightedCells[i].classList.remove('rz-state-focused'); 1470 } 1471 } 1472 } 1473 if (key == 'PageUp' || key == 'PageDown') { 1474 var rowHeight = rows[rows.length - 1] ? rows[rows.length - 1].offsetHeight : 40; 1475 var factor = 10; 1476 table.parentNode.scrollTop = table.parentNode.scrollTop + (factor * (key == 'PageDown' ? rowHeight : -rowHeight)); 1477 } 1478 else if (key == 'Home' || key == 'End') { 1479 table.parentNode.scrollTop = key == 'Home' ? 0 : table.parentNode.scrollHeight; 1480 } 1481 } 1482 1483 table.nextSelectedIndex = rowIndex || 0; 1484 table.nextSelectedCellIndex = cellIndex || 0; 1485 1486 if (key == 'ArrowDown') { 1487 while (table.nextSelectedIndex < rows.length - 1) { 1488 table.nextSelectedIndex++; 1489 if (!rows[table.nextSelectedIndex] || !rows[table.nextSelectedIndex].classList.contains('rz-state-disabled')) 1490 break; 1491 } 1492 } else if (key == 'ArrowUp') { 1493 while (table.nextSelectedIndex > 0) { 1494 table.nextSelectedIndex--; 1495 if (!rows[table.nextSelectedIndex] || !rows[table.nextSelectedIndex].classList.contains('rz-state-disabled')) 1496 break; 1497 } 1498 } else if (key == 'ArrowRight') { 1499 while (table.nextSelectedCellIndex < rows[table.nextSelectedIndex].cells.length - 1) { 1500 table.nextSelectedCellIndex++; 1501 if (!rows[table.nextSelectedIndex] || !rows[table.nextSelectedIndex].cells[table.nextSelectedCellIndex] || !rows[table.nextSelectedIndex].cells[table.nextSelectedCellIndex].classList.contains('rz-state-disabled')) 1502 break; 1503 } 1504 } else if (key == 'ArrowLeft') { 1505 while (table.nextSelectedCellIndex > 0) { 1506 table.nextSelectedCellIndex--; 1507 if (!rows[table.nextSelectedIndex] || !rows[table.nextSelectedIndex].cells[table.nextSelectedCellIndex] || !rows[table.nextSelectedIndex].cells[table.nextSelectedCellIndex].classList.contains('rz-state-disabled')) 1508 break; 1509 } 1510 } else if (isVirtual && (key == 'PageDown' || key == 'End')) { 1511 table.nextSelectedIndex = rows.length - 1; 1512 } else if (isVirtual && (key == 'PageUp' || key == 'Home')) { 1513 table.nextSelectedIndex = 1; 1514 } else if (!isVirtual && (key == 'PageDown' || key == 'PageUp' || key == 'Home' || key == 'End')) { 1515 var firstDataIndex = thead && thead.rows && thead.rows.length && cellIndex != null ? thead.rows.length : 1; 1516 if (firstDataIndex > rows.length - 1) { 1517 firstDataIndex = rows.length - 1; 1518 } 1519 if (key == 'Home') { 1520 table.nextSelectedIndex = firstDataIndex; 1521 } else if (key == 'End') { 1522 table.nextSelectedIndex = rows.length - 1; 1523 } else { 1524 var pageFactor = 10; 1525 table.nextSelectedIndex = table.nextSelectedIndex + (key == 'PageDown' ? pageFactor : -pageFactor); 1526 if (table.nextSelectedIndex > rows.length - 1) { 1527 table.nextSelectedIndex = rows.length - 1; 1528 } 1529 if (table.nextSelectedIndex < firstDataIndex) { 1530 table.nextSelectedIndex = firstDataIndex; 1531 } 1532 } 1533 } 1534 1535 if (isVirtual && (key == 'ArrowDown' || key == 'ArrowUp')) { 1536 var minIndex = cellIndex != null ? 0 : 1; 1537 if (key == 'ArrowDown' && table.nextSelectedIndex >= rows.length - 1) { 1538 var rh = rows[rows.length - 1] ? rows[rows.length - 1].offsetHeight : 40; 1539 table.parentNode.scrollTop += rh; 1540 table.nextSelectedIndex = rows.length - 1; 1541 } else if (key == 'ArrowUp' && table.nextSelectedIndex <= minIndex) { 1542 var rh = rows[rows.length - 1] ? rows[rows.length - 1].offsetHeight : 40; 1543 table.parentNode.scrollTop -= rh; 1544 table.nextSelectedIndex = minIndex; 1545 } 1546 } 1547 1548 var activeId = gridId + '-active-item';
1549 var setActiveDescendant = function (el) { 1550 var prev = document.getElementById(activeId); 1551 if (prev && prev !== el) { 1552 prev.removeAttribute('id'); 1553 } 1554 if (el && el.id !== activeId) { el.id = activeId; } 1555 if (el) { 1556 grid.setAttribute('aria-activedescendant', activeId); 1557 } 1558 }; 1559 1560 if (key == 'ArrowLeft' || key == 'ArrowRight' || (key == 'ArrowUp' && cellIndex != null && table.nextSelectedIndex == 0 && table.parentNode.scrollTop == 0)) { 1561 var highlightedCells = rows[table.nextSelectedIndex].querySelectorAll('.rz-state-focused'); 1562 if (highlightedCells.length) { 1563 for (var i = 0; i < highlightedCells.length; i++) { 1564 highlightedCells[i].classList.remove('rz-state-focused'); 1565 } 1566 } 1567 1568 if ( 1569 table.nextSelectedCellIndex >= 0 && 1570 table.nextSelectedCellIndex <= rows[table.nextSelectedIndex].cells.length - 1 1571 ) { 1572 var cell = rows[table.nextSelectedIndex].cells[table.nextSelectedCellIndex]; 1573 1574 if (!cell.classList.contains('rz-state-focused')) { 1575 cell.classList.add('rz-state-focused'); 1576 if (!isVirtual && table.parentElement.scrollWidth > table.parentElement.clientWidth) { 1577 Radzen.scrollIntoViewIfNeeded(cell); 1578 } 1579 }
1580 setActiveDescendant(cell); 1581 } 1582 } else if (key == 'ArrowDown' || key == 'ArrowUp' || (!isVirtual && (key == 'PageDown' || key == 'PageUp' || key == 'Home' || key == 'End'))) { 1583 var highlighted = table.querySelectorAll('.rz-state-focused'); 1584 if (highlighted.length) { 1585 for (var i = 0; i < highlighted.length; i++) { 1586 highlighted[i].classList.remove('rz-state-focused'); 1587 } 1588 } 1589 1590 if (table.nextSelectedIndex >= 0 && 1591 table.nextSelectedIndex <= rows.length - 1 1592 ) { 1593 var row = rows[table.nextSelectedIndex]; 1594 1595 if (!row.classList.contains('rz-state-focused')) { 1596 row.classList.add('rz-state-focused'); 1597 if (!isVirtual && table.parentElement.scrollHeight > table.parentElement.clientHeight) { 1598 Radzen.scrollIntoViewIfNeeded(row); 1599 } 1600 } 1601 setActiveDescendant(row); 1602 } 1603 } 1604 1605 return [table.nextSelectedIndex, table.nextSelectedCellIndex]; 1606 }, 1607 uploadInputChange: function (e, url, auto, multiple, clear, parameterName, method = 'POST', stream = false) { 1608 if (auto) { 1609 Radzen.upload(e.target, url, multiple, clear, parameterName, method, stream); 1610 e.target.value = ''; 1611 } else { 1612 Radzen.uploadChange(e.target); 1613 } 1614 }, 1615 uploads: function (uploadComponent, id) { 1616 if (!Radzen.uploadComponents) { 1617 Radzen.uploadComponents = {}; 1618 } 1619 Radzen.uploadComponents[id] = uploadComponent; 1620 }, 1621 uploadChange: function (fileInput) { 1622 var files = []; 1623 for (var i = 0; i < fileInput.files.length; i++) { 1624 var file = fileInput.files[i]; 1625 files.push({ 1626 Name: file.name, 1627 Size: file.size, 1628 Url: URL.createObjectURL(file) 1629 }); 1630 } 1631 1632 var uploadComponent = 1633 Radzen.uploadComponents && Radzen.uploadComponents[fileInput.id]; 1634 if (uploadComponent) { 1635 if (uploadComponent.localFiles) { 1636 // Clear any previously created preview URL(s) 1637 for (var i = 0; i < uploadComponent.localFiles.length; i++) { 1638 var file = uploadComponent.localFiles[i]; 1639 if (file.Url) { 1640 URL.revokeObjectURL(file.Url); 1641 } 1642 } 1643 } 1644 1645 uploadComponent.files = Array.from(fileInput.files); 1646 uploadComponent.localFiles = files; 1647 try { suppressDisposed(uploadComponent.invokeMethodAsync('RadzenUpload.OnChange', files)); } catch { } 1648 } 1649 1650 for (var i = 0; i < fileInput.files.length; i++) { 1651 var file = fileInput.files[i]; 1652 if (file.Url) { 1653 URL.revokeObjectURL(file.Url); 1654 } 1655 } 1656 }, 1657 removeFileFromUpload: function (ref, name, id) { 1658 var uploadComponent = (Radzen.uploadComponents && Radzen.uploadComponents[ref]) ?? Radzen.uploadComponents[id]; 1659 if (!uploadComponent) return; 1660 if (!uploadComponent.files) return; 1661 var file = uploadComponent.files.find(function (f) { return f.name == name; }) 1662 if (!file) { return; } 1663 var localFile = uploadComponent.localFiles.find(function (f) { return f.Name == name; }); 1664 if (localFile) { 1665 URL.revokeObjectURL(localFile.Url); 1666 var localIndex = uploadComponent.localFiles.indexOf(localFile); 1667 if (localIndex != -1) { 1668 uploadComponent.localFiles.splice(localIndex, 1); 1669 } 1670 } 1671 var index = uploadComponent.files.indexOf(file) 1672 if (index != -1) { 1673 uploadComponent.files.splice(index, 1); 1674 } 1675 var fileInput = document.getElementById(id).querySelector('input[type="file"]'); 1676 if (fileInput && uploadComponent.files.length == 0) { 1677 fileInput.value = ''; 1678 } 1679 }, 1680 removeFileFromFileInput: function (fileInput) { 1681 fileInput.value = ''; 1682 }, 1683 upload: function (fileInput, url, multiple, clear, parameterName, method = 'POST', stream = false) { 1684 var uploadComponent = Radzen.uploadComponents && Radzen.uploadComponents[fileInput.id]; 1685 if (!uploadComponent) { return; } 1686 if (!uploadComponent.files || clear) { 1687 uploadComponent.files = Array.from(fileInput.files); 1688 } 1689 1690 function asFormData() { 1691 var data = new FormData(); 1692 var files = []; 1693 for (var i = 0; i < uploadComponent.files.length; i++) { 1694 var file = uploadComponent.files[i]; 1695 data.append(parameterName || (multiple ? 'files' : 'file'), file, file.name); 1696 files.push({Name: file.name, Size: file.size}); 1697 } 1698 return {data, files} 1699 } 1700 1701 function asStream() { 1702 if (uploadComponent.files.length > 0) { 1703 var file = uploadComponent.files[0]; 1704 return {data: file, files: [{Name: file.name, Size: file.size}]}; 1705 } 1706 return {data: null, files: []} 1707 } 1708 1709 var cancelled = false;
1710 var {data, files} = stream ? asStream() : asFormData(); 1711 1712 var xhr = new XMLHttpRequest(); 1713 xhr.withCredentials = true; 1714 xhr.upload.onprogress = function (e) { 1715 if (e.lengthComputable) { 1716 var uploadComponent = 1717 Radzen.uploadComponents && Radzen.uploadComponents[fileInput.id]; 1718 if (uploadComponent) { 1719 var progress = parseInt((e.loaded / e.total) * 100); 1720 try { uploadComponent.invokeMethodAsync( 1721 'RadzenUpload.OnProgress', 1722 progress, 1723 e.loaded, 1724 e.total, 1725 files, 1726 cancelled 1727 ).then(function (cancel) { 1728 if (cancel) { 1729 cancelled = true; 1730 xhr.abort(); 1731 } 1732 }); } catch { } 1733 } 1734 } 1735 }; 1736 xhr.onreadystatechange = function (e) { 1737 if (xhr.readyState === XMLHttpRequest.DONE) { 1738 var status = xhr.status; 1739 var uploadComponent = 1740 Radzen.uploadComponents && Radzen.uploadComponents[fileInput.id]; 1741 if (uploadComponent) { 1742 if (status === 0 || (status >= 200 && status < 400)) { 1743 try { uploadComponent.invokeMethodAsync( 1744 'RadzenUpload.OnComplete', 1745 xhr.responseText, 1746 cancelled 1747 ); } catch { } 1748 } else { 1749 try { uploadComponent.invokeMethodAsync( 1750 'RadzenUpload.OnError', 1751 xhr.responseText 1752 ); } catch { } 1753 } 1754 } 1755 } 1756 }; 1757 try { uploadComponent.invokeMethodAsync('GetHeaders').then(function (headers) { 1758 xhr.open(method, url, true); 1759 for (var name in headers) { 1760 xhr.setRequestHeader(name, headers[name]); 1761 } 1762 xhr.send(data); 1763 }); } catch { } 1764 }, 1765 getCookie: function (name) { 1766 var value = '; ' + decodeURIComponent(document.cookie); 1767 var parts = value.split('; ' + name + '='); 1768 if (parts.length == 2) return parts.pop().split(';').shift(); 1769 }, 1770 getCulture: function () { 1771 var cultureCookie = Radzen.getCookie('.AspNetCore.Culture'); 1772 var uiCulture = cultureCookie 1773 ? cultureCookie.split('|').pop().split('=').pop() 1774 : null; 1775 return uiCulture || 'en-US'; 1776 }, 1777 numericOnPaste: function (e, min, max, locale = navigator.language) { 1778 if (!e.clipboardData) return; 1779 1780 let value = e.clipboardData.getData("text"); 1781 if (!value) { 1782 e.preventDefault(); 1783 return; 1784 } 1785 1786 value = String(value).trim(); 1787 1788 const parts = new Intl.NumberFormat(locale).formatToParts(1234567.89); 1789 1790 let group = ","; 1791 let decimal = "."; 1792 1793 for (const p of parts) { 1794 if (p.type === "group") group = p.value; 1795 if (p.type === "decimal") decimal = p.value; 1796 } 1797 1798 value = value.replace(/[\u00A0\u202F]/g, " "); 1799 1800 if (group) { 1801 const escapedGroup = group.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); 1802 value = value.replace(new RegExp(escapedGroup, "g"), ""); 1803 } 1804 1805 if (group === " ") { 1806 value = value.replace(/ /g, ""); 1807 } 1808 1809 if (decimal !== ".") { 1810 const escapedDecimal = decimal.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); 1811 value = value.replace(new RegExp(escapedDecimal, "g"), "."); 1812 } 1813 1814 if (!/^[+-]?(\d+(\.\d*)?|\.\d+)$/.test(value)) { 1815 e.preventDefault(); 1816 return; 1817 } 1818 1819 const numericValue = Number(value); 1820 1821 if (!Number.isFinite(numericValue)) { 1822 e.preventDefault(); 1823 return; 1824 } 1825 1826 if (min != null && numericValue < min) { 1827 e.preventDefault(); 1828 return; 1829 } 1830 1831 if (max != null && numericValue > max) { 1832 e.preventDefault(); 1833 return; 1834 } 1835 }, 1836 numericOnInput: function (e, min, max, isNullable) { 1837 var value = e.target.value; 1838 1839 if (!isNullable && value == '' && min != null) { 1840 e.target.value = min; 1841 } 1842 1843 if (value && !isNaN(+value)) { 1844 var numericValue = +value; 1845 if (min != null && !isNaN(+min) && numericValue < min) { 1846 e.target.value = min; 1847 } 1848 if (max != null && !isNaN(+max) && numericValue > max) { 1849 e.target.value = max; 1850 } 1851 } 1852 }, 1853 numericKeyPress: function (e, isInteger, decimalSeparator) { 1854 if ( 1855 e.metaKey || 1856 e.ctrlKey || 1857 e.keyCode == 9 || 1858 e.keyCode == 8 || 1859 e.keyCode == 13 1860 ) { 1861 return; 1862 } 1863 1864 if (e.code === 'NumpadDecimal' && !isInteger) { 1865 var cursorPosition = e.target.selectionEnd; 1866 e.target.value = [e.target.value.slice(0, e.target.selectionStart), decimalSeparator, e.target.value.slice(e.target.selectionEnd)].join(''); 1867 e.target.selectionStart = ++cursorPosition; 1868 e.target.selectionEnd = cursorPosition; 1869 e.preventDefault(); 1870 return; 1871 } 1872 1873 var ch = e.key; 1874 1875 if (/\p{Nd}/u.test(ch) || ch === '-' || (!isInteger && ch === decimalSeparator)) { 1876 return; 1877 } 1878 1879 e.preventDefault(); 1880 }, 1881 openContextMenu: function (x,y,id, instance, callback) { 1882 Radzen.closePopup(id); 1883 1884 var invoker = document.activeElement; 1885 if (invoker && invoker !== document.body) { 1886 Radzen[id + 'contextMenuInvoker'] = invoker; 1887 } 1888 1889 Radzen.openPopup(null, id, false, null, x, y, instance, callback); 1890 1891 requestAnimationFrame(function () { 1892 var popup = document.getElementById(id); 1893 if (popup) { 1894 var menu = popup.querySelector('.rz-menu'); 1895 if (menu) { 1896 menu.focus(); 1897 } 1898 } 1899 }); 1900 }, 1901 restoreContextMenuFocus: function (id) { 1902 var invoker = Radzen[id + 'contextMenuInvoker']; 1903 Radzen[id + 'contextMenuInvoker'] = null; 1904 if (invoker && document.body.contains(invoker) && typeof invoker.focus === 'function') { 1905 invoker.focus(); 1906 } 1907 }, 1908 openTooltip: function (target, id, delay, duration, position, closeTooltipOnDocumentClick, instance, callback, clientX, clientY) { 1909 Radzen.closeTooltip(id); 1910 1911 if (clientX != null && clientY != null) { 1912 position = null; 1913 disableSmartPosition = true; 1914 } 1915 else { 1916 disableSmartPosition = false;
1917 } 1918 1919 if (target) { 1920 target.setAttribute('aria-describedby', id); 1921 Radzen[id + 'target'] = target; 1922 } 1923 1924 if (delay) { 1925 Radzen[id + 'delay'] = setTimeout(Radzen.openPopup, delay, target, id, false, position, clientX, clientY, instance, callback, closeTooltipOnDocumentClick, false, disableSmartPosition); 1926 } else { 1927 Radzen.openPopup(target, id, false, position, clientX, clientY, instance, callback, closeTooltipOnDocumentClick, false, disableSmartPosition); 1928 } 1929 1930 if (duration) { 1931 Radzen[id + 'duration'] = setTimeout(Radzen.closePopup, duration, id, instance, callback); 1932 } 1933 1934 // WCAG 1.4.13 (Content on Hover or Focus): the tooltip stays visible as long as 1935 // the pointer is over it, so the user can move onto and read/interact with it. 1936 var tooltipPopup = document.getElementById(id); 1937 if (tooltipPopup) { 1938 Radzen[id + 'tooltipEnter'] = function () { 1939 if (Radzen[id + 'duration']) { 1940 clearTimeout(Radzen[id + 'duration']); 1941 Radzen[id + 'duration'] = null; 1942 } 1943 }; 1944 Radzen[id + 'tooltipLeave'] = function () { 1945 if (duration) { 1946 Radzen[id + 'duration'] = setTimeout(Radzen.closePopup, duration, id, instance, callback); 1947 } 1948 }; 1949 tooltipPopup.addEventListener('mouseenter', Radzen[id + 'tooltipEnter']); 1950 tooltipPopup.addEventListener('mouseleave', Radzen[id + 'tooltipLeave']); 1951 } 1952 1953 // WAI-ARIA APG Tooltip pattern: Escape dismisses the tooltip. 1954 Radzen[id + 'esc'] = function (e) { 1955 if (e.key === 'Escape' || e.keyCode === 27) { 1956 Radzen.closeTooltip(id); 1957 if (instance && callback) { 1958 try { suppressDisposed(instance.invokeMethodAsync(callback, null)); } catch (ex) { } 1959 } 1960 } 1961 }; 1962 document.addEventListener('keydown', Radzen[id + 'esc']); 1963 }, 1964 closeTooltip(id) { 1965 Radzen.activeElement = null; 1966 1967 var target = Radzen[id + 'target']; 1968 if (target) { 1969 target.removeAttribute('aria-describedby'); 1970 Radzen[id + 'target'] = null; 1971 } 1972 1973 if (Radzen[id + 'esc']) { 1974 document.removeEventListener('keydown', Radzen[id + 'esc']); 1975 Radzen[id + 'esc'] = null; 1976 } 1977 1978 var tooltipPopup = document.getElementById(id); 1979 if (tooltipPopup) { 1980 if (Radzen[id + 'tooltipEnter']) { 1981 tooltipPopup.removeEventListener('mouseenter', Radzen[id + 'tooltipEnter']); 1982 Radzen[id + 'tooltipEnter'] = null; 1983 } 1984 if (Radzen[id + 'tooltipLeave']) { 1985 tooltipPopup.removeEventListener('mouseleave', Radzen[id + 'tooltipLeave']); 1986 Radzen[id + 'tooltipLeave'] = null; 1987 } 1988 } 1989 1990 Radzen.closePopup(id); 1991 1992 if (Radzen[id + 'delay']) { 1993 clearTimeout(Radzen[id + 'delay']); 1994 } 1995 1996 if (Radzen[id + 'duration']) { 1997 clearTimeout(Radzen[id + 'duration']); 1998 } 1999 }, 2000 createDatePicker(el, popupId, instance, callback) { 2001 if(!el) return { dispose: function() {} }; 2002 var handler = function (e, condition) { 2003 if (condition) { 2004 Radzen.togglePopup(e.currentTarget.parentNode, popupId, false, instance, callback, true, false); 2005 } 2006 }; 2007 2008 var input = el.querySelector('.rz-inputtext'); 2009 var button = el.querySelector('.rz-datepicker-trigger'); 2010 if (button) { 2011 button.onclick = function (e) { 2012 handler(e, !e.currentTarget.classList.contains('rz-state-disabled') && (input ? !input.classList.contains('rz-readonly') : true)); 2013 }; 2014 } 2015 2016 if (input) { 2017 input.onclick = function (e) { 2018 handler(e, e.currentTarget.classList.contains('rz-input-trigger') && !e.currentTarget.classList.contains('rz-readonly')); 2019 }; 2020 } 2021 2022 return { 2023 dispose: function () { 2024 if (button) { 2025 button.onclick = null; 2026 } 2027 if (input) { 2028 input.onclick = null; 2029 } 2030 } 2031 }; 2032 }, 2033 findPopup: function (id) { 2034 var popups = []; 2035 for (var i = 0; i < document.body.children.length; i++) { 2036 if (document.body.children[i].id == id) { 2037 popups.push(document.body.children[i]); 2038 } 2039 } 2040 return popups; 2041 }, 2042 repositionPopup: function (parent, id) { 2043 var popup = document.getElementById(id); 2044 if (!popup) return; 2045 2046 var rect = popup.getBoundingClientRect(); 2047 var parentRect = parent ? parent.getBoundingClientRect() : { top: 0, bottom: 0, left: 0, right: 0, width: 0, height: 0 }; 2048 2049 if (/Edge/.test(navigator.userAgent)) { 2050 var scrollTop = document.body.scrollTop; 2051 } else { 2052 var scrollTop = document.documentElement.scrollTop; 2053 } 2054 2055 var top = parentRect.bottom + scrollTop; 2056 2057 if (top + rect.height > window.innerHeight + scrollTop && parentRect.top > rect.height) { 2058 top = parentRect.top - rect.height + scrollTop; 2059 } 2060 2061 popup.style.top = top + 'px'; 2062 }, 2063 setPopupAriaExpanded: function (parent, id, expanded) { 2064 if (!parent || !id) return; 2065 var control = null; 2066 if (parent.getAttribute && parent.getAttribute('aria-controls') === id) { 2067 control = parent; 2068 } else if (parent.querySelector) { 2069 control = parent.querySelector('[aria-controls="' + (window.CSS && CSS.escape ? CSS.escape(id) : id) + '"]'); 2070 } 2071 if (!control && parent.getAttribute && parent.getAttribute('role') === 'combobox') { 2072 control = parent; 2073 } 2074 if (control) { 2075 control.setAttribute('aria-expanded', expanded ? 'true' : 'false'); 2076 } 2077 }, 2078 openPopup: function (parent, id, syncWidth, position, x, y, instance, callback, closeOnDocumentClick = true, autoFocusFirstElement = false, disableSmartPosition = false) { 2079 var popup = document.getElementById(id); 2080 if (!popup || popup && popup.style.display == 'block' && popup.classList.contains('rz-autocomplete-panel')) return; 2081 2082 Radzen.activeElement = document.activeElement; 2083 2084 var parentRect = parent ? parent.getBoundingClientRect() : { top: y || 0, bottom: 0, left: x || 0, right: 0, width: 0, height: 0 }; 2085 2086 if (/Edge/.test(navigator.userAgent)) { 2087 var scrollLeft = document.body.scrollLeft; 2088 var scrollTop = document.body.scrollTop; 2089 } else { 2090 var scrollLeft = document.documentElement.scrollLeft; 2091 var scrollTop = document.documentElement.scrollTop; 2092 } 2093 2094 var top = y ? y : parentRect.bottom; 2095 var left = x ? x : parentRect.left; 2096 2097 if (syncWidth) { 2098 popup.style.width = parentRect.width + 'px'; 2099 if (!popup.style.minWidth) { 2100 popup.minWidth = true; 2101 popup.style.minWidth = parentRect.width + 'px'; 2102 } 2103 } 2104 2105 if (window.chrome) { 2106 var closestFrozenCell = popup.closest('.rz-frozen-cell'); 2107 if (closestFrozenCell) { 2108 Radzen[id + 'FZL'] = { cell: closestFrozenCell, left: closestFrozenCell.style.left }; 2109 closestFrozenCell.style.left = ''; 2110 } 2111 } 2112 2113 popup.style.display = 'block'; 2114 popup.style.visibility = 'hidden'; 2115 popup.onanimationend = null; 2116 popup.onanimationcancel = null; 2117 popup.classList.remove("rz-close");
2118 Radzen.setPopupAriaExpanded(parent, id, true); 2119 2120 var rect = popup.getBoundingClientRect(); 2121 rect.width = x ? rect.width + 20 : rect.width; 2122 rect.height = y ? rect.height + 20 : rect.height; 2123 2124 var isRTL = Radzen.isRTL(popup); 2125 2126 if (isRTL && parent && (!position || position == 'bottom' || position == 'top')) { 2127 left = parentRect.right - rect.width; 2128 } 2129 2130 var smartPosition = !position || position == 'bottom'; 2131 2132 if (smartPosition && top + rect.height > window.innerHeight && parentRect.top > rect.height) { 2133 if (disableSmartPosition !== true) { 2134 top = parentRect.top - rect.height; 2135 } 2136 } 2137 2138 if (smartPosition && left + rect.width > window.innerWidth && window.innerWidth > rect.width) { 2139 left = window.innerWidth - rect.width; 2140 } 2141 2142 if (smartPosition && isRTL && left < 0 && window.innerWidth > rect.width) { 2143 left = 0; 2144 } 2145 2146 if (position && !(disableSmartPosition === true && x != null && y != null)) { 2147 var tooltipPlacement = function (side) { 2148 switch (side) { 2149 case 'left': return { left: parentRect.left - rect.width - 5, top: parentRect.top }; 2150 case 'right': return { left: parentRect.right + 10, top: parentRect.top }; 2151 case 'top': return { left: isRTL ? parentRect.right - rect.width : parentRect.left, top: parentRect.top - rect.height + 5 }; 2152 default: return { left: isRTL ? parentRect.right - rect.width : parentRect.left, top: parentRect.bottom + 20 }; 2153 } 2154 }; 2155 2156 var tooltipFits = function (p) { 2157 return p.left >= 0 && p.top >= 0 && 2158 p.left + rect.width <= window.innerWidth && 2159 p.top + rect.height <= window.innerHeight; 2160 }; 2161 2162 var fallbackOrder = { 2163 left: ['left', 'right', 'top', 'bottom'], 2164 right: ['right', 'left', 'top', 'bottom'], 2165 top: ['top', 'bottom', 'right', 'left'], 2166 bottom: ['bottom', 'top', 'right', 'left'] 2167 }[position] || [position]; 2168 2169 var resolvedPosition = null; 2170 var placement = null; 2171 2172 for (var pi = 0; pi < fallbackOrder.length; pi++) { 2173 var candidate = tooltipPlacement(fallbackOrder[pi]); 2174 if (tooltipFits(candidate)) { 2175 resolvedPosition = fallbackOrder[pi]; 2176 placement = candidate; 2177 break; 2178 } 2179 } 2180 2181 if (!placement) { 2182 resolvedPosition = position; 2183 placement = tooltipPlacement(position); 2184 placement.left = Math.max(0, Math.min(placement.left, window.innerWidth - rect.width)); 2185 placement.top = Math.max(0, Math.min(placement.top, window.innerHeight - rect.height)); 2186 } 2187 2188 left = placement.left; 2189 top = placement.top; 2190 2191 if (resolvedPosition != position) { 2192 var tooltipContent = popup.children[0]; 2193 var previousClassName = 'rz-' + position + '-tooltip-content'; 2194 if (tooltipContent && tooltipContent.classList.contains(previousClassName)) { 2195 tooltipContent.classList.remove(previousClassName); 2196 tooltipContent.classList.add('rz-' + resolvedPosition + '-tooltip-content'); 2197 } 2198 position = resolvedPosition; 2199 if (instance && callback) { 2200 try { suppressDisposed(instance.invokeMethodAsync(callback, position)); } catch { } 2201 } 2202 } 2203 } 2204 2205 if (disableSmartPosition && x != null && y != null) { 2206 left = x + 10; 2207 top = y + 10; 2208 var tooltipContent = popup.children[0]; 2209 var tooltipContentClassName = 'rz-bottom-tooltip-content'; 2210 if (tooltipContent.classList.contains(tooltipContentClassName)) { 2211 tooltipContent.classList.remove(tooltipContentClassName); 2212 } 2213 2214 if (left + rect.width > window.innerWidth && window.innerWidth > rect.width) { 2215 top = parentRect.top - rect.height; 2216 } 2217 2218 if (left + rect.width > window.innerWidth && window.innerWidth > rect.width) { 2219 left = window.innerWidth - rect.width; 2220 } 2221 } 2222 2223 popup.style.zIndex = 2000; 2224 popup.style.left = left + scrollLeft + 'px'; 2225 popup.style.top = top + scrollTop + 'px'; 2226 2227 if (!popup.classList.contains('rz-overlaypanel')) { 2228 popup.classList.add('rz-popup'); 2229 } 2230 2231 Radzen[id] = function (e) { 2232 var lastPopup = Radzen.popups && Radzen.popups[Radzen.popups.length - 1]; 2233 var currentPopup = lastPopup != null && document.getElementById(lastPopup.id) || popup; 2234 2235 if (lastPopup) { 2236 currentPopup.instance = lastPopup.instance; 2237 currentPopup.callback = lastPopup.callback; 2238 currentPopup.parent = lastPopup.parent; 2239 } 2240 2241 if(e.type == 'contextmenu' || !e.target || !closeOnDocumentClick) return; 2242 if (!/Android/i.test(navigator.userAgent) && 2243 !['input', 'textarea'].includes(document.activeElement ? document.activeElement.tagName.toLowerCase() : '') && e.type == 'resize') { 2244 Radzen.closePopup(currentPopup.id, currentPopup.instance, currentPopup.callback, e); 2245 return; 2246 } 2247 2248 var closestLink = e.target.closest && (e.target.closest('.rz-link') || e.target.closest('.rz-navigation-item-link')); 2249 if (e.type == 'resize' && !/Android/i.test(navigator.userAgent) && 2250 !['input', 'textarea'].includes(document.activeElement ? document.activeElement.tagName.toLowerCase() : '')) { 2251 if (closestLink && closestLink.closest && closestLink.closest('a') && e.button == 0) { 2252 closestLink.closest('a').click(); 2253 Radzen.closeAllPopups(); 2254 } else { 2255 Radzen.closeAllPopups(); 2256 } 2257 } 2258 if (currentPopup.parent) { 2259 if (e.type == 'mousedown' && !currentPopup.parent.contains(e.target) && !currentPopup.contains(e.target)) { 2260 Radzen.closePopup(currentPopup.id, currentPopup.instance, currentPopup.callback, e); 2261 } 2262 } else { 2263 if (e.target.nodeType && !currentPopup.contains(e.target)) { 2264 Radzen.closePopup(currentPopup.id, currentPopup.instance, currentPopup.callback, e); 2265 } 2266 } 2267 }; 2268 2269 if (!Radzen.popups) { 2270 Radzen.popups = []; 2271 } 2272 2273 Radzen.popups.push({ id, instance, callback, parent }); 2274 2275 if (popup.parentNode && popup.parentNode !== document.body) { 2276 popup.__radzenHome = popup.parentNode; 2277 } 2278
2279 document.body.appendChild(popup); 2280 2281 if (!position) { 2282 var popupRect = popup.getBoundingClientRect(); 2283 // Clamp into the viewport. If the popup is smaller than the viewport, shift it 2284 // so its right/bottom edge fits. If it is larger than the viewport, pin the 2285 // top/left corner to the viewport origin so content is at least reachable 2286 // (instead of leaving it positioned off-screen at the anchor). 2287 if (popupRect.right > window.innerWidth) { 2288 popup.style.left = Math.max(scrollLeft, window.innerWidth - popupRect.width + scrollLeft) + 'px'; 2289 } 2290 if (popupRect.bottom > window.innerHeight) { 2291 popup.style.top = Math.max(scrollTop, window.innerHeight - popupRect.height + scrollTop) + 'px'; 2292 } 2293 } 2294 2295 popup.style.visibility = ''; 2296 popup.classList.add("rz-open"); 2297 2298 document.removeEventListener('mousedown', Radzen[id]); 2299 document.addEventListener('mousedown', Radzen[id]); 2300 window.removeEventListener('resize', Radzen[id]); 2301 window.addEventListener('resize', Radzen[id]); 2302 2303 if (window.visualViewport && parent && 2304 (popup.classList.contains('rz-dropdown-panel') || popup.classList.contains('rz-multiselect-panel'))) { 2305 var itemsWrapper = popup.querySelector('.rz-dropdown-items-wrapper, .rz-multiselect-items-wrapper'); 2306 if (itemsWrapper) { 2307 popup.__originalWrapperMaxHeight = itemsWrapper.style.maxHeight; 2308 popup.__originalPopupTop = popup.style.top; 2309 popup.__viewportResizeHandler = function () { 2310 if (popup.style.display !== 'block') return; 2311 var vv = window.visualViewport; 2312 var viewportTop = vv.offsetTop; 2313 var viewportBottom = viewportTop + vv.height; 2314 var pRect = parent.getBoundingClientRect(); 2315 var popRect = popup.getBoundingClientRect(); 2316 if (popRect.top >= viewportTop - 1 && popRect.bottom <= viewportBottom + 1) { 2317 itemsWrapper.style.maxHeight = popup.__originalWrapperMaxHeight; 2318 popup.style.top = popup.__originalPopupTop; 2319 return; 2320 } 2321 var spaceBelow = viewportBottom - pRect.bottom - 5; 2322 var spaceAbove = pRect.top - viewportTop - 5; 2323 var sTop = /Edge/.test(navigator.userAgent) ? document.body.scrollTop : document.documentElement.scrollTop; 2324 if (spaceBelow >= spaceAbove) { 2325 popup.style.top = (pRect.bottom + sTop) + 'px'; 2326 itemsWrapper.style.maxHeight = Math.max(60, spaceBelow) + 'px'; 2327 } else { 2328 itemsWrapper.style.maxHeight = Math.max(60, spaceAbove) + 'px'; 2329 var newHeight = popup.getBoundingClientRect().height; 2330 popup.style.top = (pRect.top - newHeight + sTop) + 'px'; 2331 } 2332 }; 2333 window.visualViewport.addEventListener('resize', popup.__viewportResizeHandler); 2334 } 2335 } 2336 2337 var p = parent; 2338 while (p && p != document.body) { 2339 if (p.scrollWidth > p.clientWidth || p.scrollHeight > p.clientHeight) { 2340 p.removeEventListener('scroll', Radzen.closeAllPopups); 2341 p.addEventListener('scroll', Radzen.closeAllPopups); 2342 } 2343 p = p.parentElement; 2344 } 2345 2346 if (!parent) { 2347 document.removeEventListener('contextmenu', Radzen[id]); 2348 document.addEventListener('contextmenu', Radzen[id]); 2349 } 2350 2351 if (autoFocusFirstElement) { 2352 setTimeout(function () { 2353 popup.removeEventListener('keydown', Radzen.focusTrap); 2354 popup.addEventListener('keydown', Radzen.focusTrap); 2355 2356 var focusable = Radzen.getFocusableElements(popup); 2357 var firstFocusable = focusable[0]; 2358 if (firstFocusable) { 2359 firstFocusable.focus(); 2360 } 2361 }, 200); 2362 } 2363 2364 if (popup.__escapeHandler) { 2365 popup.removeEventListener('keydown', popup.__escapeHandler, true); 2366 } 2367 popup.__escapeHandler = function (e) { 2368 if (e.key === 'Escape' || e.key === 'Esc') { 2369 var menu = popup.querySelector('.rz-menu[role="menu"]'); 2370 if (menu && menu.querySelector('.rz-navigation-item-active')) { 2371 return; 2372 } 2373 Radzen.closePopup(id, instance, callback, e); 2374 } 2375 if (e.key === 'Tab' && parent && (popup.classList.contains('rz-dropdown-panel') || popup.classList.contains('rz-multiselect-panel'))) { 2376 e.preventDefault(); 2377 } 2378 if (e.key === 'Tab' && !e.shiftKey) { 2379 var timepicker = popup.querySelector('.rz-timepicker'); 2380 if (timepicker) { 2381 var focusable = Radzen.getFocusableElements(timepicker);
2382 var last = focusable[focusable.length - 1]; 2383 if (last && document.activeElement === last) { 2384 Radzen.closePopup(id, instance, callback, e); 2385 } 2386 } 2387 } 2388 }; 2389 popup.addEventListener('keydown', popup.__escapeHandler, true); 2390 }, 2391 closeAllPopups: function (e, id) { 2392 if (!Radzen.popups) return; 2393 var el = e && e.target || id && documentElement.getElementById(id); 2394 var popups = Radzen.popups; 2395 for (var i = 0; i < popups.length; i++) { 2396 var p = popups[i]; 2397 2398 var closestPopup = el && el.closest && (el.closest('.rz-popup') || el.closest('.rz-overlaypanel')); 2399 if (closestPopup && closestPopup != p) { 2400 return; 2401 } 2402 2403 Radzen.closePopup(p.id, p.instance, p.callback, e); 2404 } 2405 Radzen.popups = []; 2406 }, 2407 closePopup: function (id, instance, callback, e, preventFocusRestore) { 2408 var popup = document.getElementById(id); 2409 if (!popup) return; 2410 var popupInfo = (Radzen.popups || []).find(function (p) { return p.id === id; }); 2411 if (popupInfo && popupInfo.parent) { 2412 Radzen.setPopupAriaExpanded(popupInfo.parent, id, false); 2413 var combobox = popupInfo.parent.closest('[role="combobox"]'); 2414 if (combobox) { 2415 combobox.removeAttribute('aria-activedescendant'); 2416 } 2417 } 2418 if (popup.style.display == 'none') { 2419 var popups = Radzen.findPopup(id); 2420 if (popups.length > 1) { 2421 for (var i = 0; i < popups.length; i++) { 2422 if (popups[i].style.display == 'none') { 2423 popups[i].parentNode.removeChild(popups[i]); 2424 } else { 2425 popup = popups[i]; 2426 } 2427 } 2428 } else if (popups.length == 1 && popups[0].style.display != 'none') { 2429 popup = popups[0]; 2430 } else { 2431 return; 2432 } 2433 } 2434 2435 if (popup) { 2436 if (popup.minWidth) { 2437 popup.style.minWidth = ''; 2438 } 2439 2440 if (window.chrome && Radzen[id + 'FZL']) { 2441 Radzen[id + 'FZL'].cell.style.left = Radzen[id + 'FZL'].left; 2442 Radzen[id + 'FZL'] = null; 2443 } 2444 2445 var hidePopup = function () { 2446 popup.style.display = 'none'; 2447 popup.onanimationend = null; 2448 popup.onanimationcancel = null; 2449 } 2450 popup.onanimationend = hidePopup; 2451 popup.onanimationcancel = hidePopup; 2452 popup.classList.add("rz-close"); 2453 popup.classList.remove("rz-open"); 2454 var closeAnimationRunning = popup.getAnimations 2455 ? popup.getAnimations().some(function (a) { return a.animationName == 'rz-close'; }) 2456 : getComputedStyle(popup).animationName.indexOf('rz-close') != -1; 2457 if (!closeAnimationRunning) { 2458 hidePopup(); 2459 } 2460 } 2461 if (popup && popup.__escapeHandler) { 2462 popup.removeEventListener('keydown', popup.__escapeHandler, true); 2463 delete popup.__escapeHandler; 2464 } 2465 if (popup && popup.__viewportResizeHandler) { 2466 if (window.visualViewport) { 2467 window.visualViewport.removeEventListener('resize', popup.__viewportResizeHandler); 2468 } 2469 var wrapperToReset = popup.querySelector('.rz-dropdown-items-wrapper, .rz-multiselect-items-wrapper'); 2470 if (wrapperToReset && popup.__originalWrapperMaxHeight !== undefined) { 2471 wrapperToReset.style.maxHeight = popup.__originalWrapperMaxHeight; 2472 } 2473 delete popup.__viewportResizeHandler; 2474 delete popup.__originalWrapperMaxHeight; 2475 delete popup.__originalPopupTop; 2476 } 2477 document.removeEventListener('mousedown', Radzen[id]); 2478 window.removeEventListener('resize', Radzen[id]); 2479 Radzen[id] = null; 2480 2481 if (instance && callback) { 2482 if (callback.includes('RadzenTooltip')) { 2483 try { suppressDisposed(instance.invokeMethodAsync(callback, null)); } catch { } 2484 } else { 2485 try { suppressDisposed(instance.invokeMethodAsync(callback)); } catch { } 2486 } 2487 } 2488 Radzen.popups = (Radzen.popups || []).filter(function (obj) { 2489 return obj.id !== id; 2490 }); 2491 2492 if (!preventFocusRestore && 2493 (Radzen.activeElement && Radzen.activeElement == document.activeElement || 2494 Radzen.activeElement && document.activeElement == document.body || 2495 Radzen.activeElement && popup && popup.contains(document.activeElement) || 2496 Radzen.activeElement && document.activeElement && 2497 (document.activeElement.classList.contains('rz-dropdown-filter') || 2498 document.activeElement.classList.contains('rz-lookup-search-input') || 2499 document.activeElement.classList.contains('rz-multiselect-filter-container') || 2500 document.activeElement.closest('.rz-multiselect-filter-container') !== null))) { 2501 setTimeout(function () { 2502 if (e && e.target && e.target.tabIndex != -1) { 2503 Radzen.activeElement = e.target; 2504 } 2505 if (Radzen.activeElement && (document.activeElement == null || document.activeElement == document.body || popup && popup.contains(document.activeElement))) { 2506 Radzen.activeElement.focus(); 2507 } 2508 Radzen.activeElement = null; 2509 }, 100); 2510 } 2511 }, 2512 popupOpened: function (id) { 2513 var popup = document.getElementById(id); 2514 if (popup) { 2515 return popup.style.display != 'none'; 2516 } 2517 return false;
2518 }, 2519 togglePopup: function (parent, id, syncWidth, instance, callback, closeOnDocumentClick = true, autoFocusFirstElement = false) { 2520 var popup = document.getElementById(id); 2521 if (!popup) return; 2522 if (popup.style.display == 'block') { 2523 Radzen.closePopup(id, instance, callback); 2524 } else { 2525 Radzen.openPopup(parent, id, syncWidth, null, null, null, instance, callback, closeOnDocumentClick, autoFocusFirstElement); 2526 } 2527 }, 2528 destroyPopup: function (id) { 2529 var popup = document.getElementById(id); 2530 if (popup) { 2531 if (popup.__escapeHandler) { 2532 popup.removeEventListener('keydown', popup.__escapeHandler, true); 2533 delete popup.__escapeHandler; 2534 } 2535 if (popup.__viewportResizeHandler) { 2536 if (window.visualViewport) { 2537 window.visualViewport.removeEventListener('resize', popup.__viewportResizeHandler); 2538 } 2539 delete popup.__viewportResizeHandler; 2540 delete popup.__originalWrapperMaxHeight; 2541 delete popup.__originalPopupTop; 2542 } 2543 if (popup.__radzenHome && popup.__radzenHome.isConnected) { 2544 popup.__radzenHome.appendChild(popup); 2545 } else if (popup.parentNode === document.body) { 2546 document.body.removeChild(popup); 2547 } 2548 delete popup.__radzenHome; 2549 } 2550 document.removeEventListener('mousedown', Radzen[id]); 2551 document.removeEventListener('contextmenu', Radzen[id]); 2552 window.removeEventListener('resize', Radzen[id]); 2553 Radzen[id] = null; 2554 Radzen.popups = (Radzen.popups || []).filter(function (obj) { 2555 return obj.id !== id; 2556 }); 2557 }, 2558 scrollDataGrid: function (e) { 2559 var scrollLeft = 2560 (e.target.scrollLeft ? '-' + e.target.scrollLeft : 0) + 'px'; 2561 2562 e.target.previousElementSibling.style.marginLeft = scrollLeft; 2563 e.target.previousElementSibling.firstElementChild.style.paddingRight = 2564 e.target.clientHeight < e.target.scrollHeight ? (e.target.offsetWidth - e.target.clientWidth) + 'px' : '0px'; 2565 2566 if (e.target.nextElementSibling) { 2567 e.target.nextElementSibling.style.marginLeft = scrollLeft; 2568 e.target.nextElementSibling.firstElementChild.style.paddingRight = 2569 e.target.clientHeight < e.target.scrollHeight ? (e.target.offsetWidth - e.target.clientWidth) + 'px' : '0px'; 2570 } 2571 2572 for (var i = 0; i < document.body.children.length; i++) { 2573 if (document.body.children[i].classList.contains('rz-overlaypanel')) { 2574 document.body.children[i].style.display = 'none'; 2575 } 2576 } 2577 }, 2578 focusFirstFocusableElement: function (el) { 2579 var focusable = Radzen.getFocusableElements(el); 2580 if (!focusable || !focusable.length) return; 2581 2582 var first = focusable[0]; 2583 2584 if (first.classList.contains('rz-html-editor-content')) { 2585 var sel = window.getSelection(); 2586 var range = document.createRange(); 2587 range.setStart(first, 0); 2588 range.setEnd(first, 0); 2589 sel.removeAllRanges(); 2590 sel.addRange(range); 2591 first.focus(); 2592 } else { 2593 first.focus(); 2594 } 2595 }, 2596 openSideDialog: function (options, dialogService) { 2597 if (dialogService) { 2598 Radzen.sideDialogService = dialogService; 2599 } 2600 if (!Radzen.sideDialogInvokerElement) { 2601 var invoker = document.activeElement; 2602 if (invoker && invoker !== document.body && !invoker.closest('.rz-dialog-side')) { 2603 Radzen.sideDialogInvokerElement = invoker; 2604 } 2605 } 2606 var sideDialog = document.querySelector('.rz-dialog-side'); 2607 if (sideDialog) { 2608 sideDialog.removeEventListener('keydown', Radzen.focusTrap); 2609 if (options.showMask) { 2610 sideDialog.addEventListener('keydown', Radzen.focusTrap); 2611 } 2612 sideDialog.removeEventListener('keydown', Radzen.closeSideDialogOnEsc); 2613 sideDialog.addEventListener('keydown', Radzen.closeSideDialogOnEsc); 2614 } 2615 setTimeout(function () { 2616 if (options.autoFocusFirstElement) { 2617 var dialogs = document.querySelectorAll('.rz-dialog-side-content'); 2618 if (dialogs.length == 0) return; 2619 var lastDialog = dialogs[dialogs.length - 1]; 2620 Radzen.focusFirstFocusableElement(lastDialog); 2621 } 2622 }, 500); 2623 }, 2624 closeSideDialog: function () { 2625 delete Radzen.sideDialogService; 2626 var invoker = Radzen.sideDialogInvokerElement; 2627 Radzen.sideDialogInvokerElement = null; 2628 if (invoker && typeof invoker.focus === 'function' && document.body.contains(invoker)) { 2629 invoker.focus(); 2630 } 2631 }, 2632 closeSideDialogOnEsc: function (e) { 2633 e = e || window.event; 2634 var isEscape = "key" in e ? (e.key === "Escape" || e.key === "Esc") : (e.keyCode === 27); 2635 if (isEscape && Radzen.sideDialogService) { 2636 var popups = document.querySelectorAll('.rz-popup,.rz-overlaypanel'); 2637 for (var i = 0; i < popups.length; i++) { 2638 if (popups[i].style.display != 'none') { 2639 return; 2640 } 2641 } 2642 try { 2643 Radzen.sideDialogService.invokeMethodAsync('DialogService.TryCloseSide', null); 2644 } catch (ex) { } 2645 } 2646 }, 2647 createSideDialogResizer: function(handle, sideDialog, options) { 2648 const normalizeDir = (value) => { 2649 if (typeof value === 'string' && value.length) { 2650 return value.toLowerCase(); 2651 } 2652 if (typeof value === 'number') { 2653 const positions = ['right', 'left', 'top', 'bottom']; 2654 return positions[value] || 'right'; 2655 } 2656 return 'right'; 2657 }; 2658 2659 const dir = normalizeDir(options?.position); 2660 2661 let start = null; 2662 2663 const onDown = (e) => { 2664 e.preventDefault(); 2665 2666 start = {x: e.clientX, y: e.clientY, w: sideDialog.clientWidth, h: sideDialog.clientHeight}; 2667 2668 document.addEventListener('pointermove', onMove); 2669 document.addEventListener('pointerup', onUp, {once: true}); 2670 document.addEventListener('pointercancel', onUp, {once: true}); 2671 }; 2672 2673 const clamp = (v, min, max) => Math.max(min, Math.min(max, v)); 2674 2675 const applyWidth = (w) => { 2676 sideDialog.style.width = Math.round(w) + 'px'; 2677 }; 2678 const applyHeight = (h) => { 2679 sideDialog.style.height = `${Math.round(h)}px`; 2680 }; 2681 2682 const onMove = (e) => { 2683 if (!start) return; 2684 2685 const dx = e.clientX - start.x; 2686 const dy = e.clientY - start.y; 2687 2688 switch (dir) { 2689 case 'right': 2690 applyWidth(clamp(start.w - dx, options.minWidth, Infinity)); 2691 break; 2692 case 'left': 2693 applyWidth(clamp(start.w + dx, options.minWidth, Infinity)); 2694 break; 2695 case 'bottom': 2696 applyHeight(clamp(start.h - dy, options.minHeight, Infinity)); 2697 break; 2698 case 'top': 2699 applyHeight(clamp(start.h + dy, options.minHeight, Infinity)); 2700 break; 2701 } 2702 }; 2703 2704 const onUp = (e) => { 2705 start = null; 2706 document.removeEventListener('pointermove', onMove); 2707 }; 2708 2709 handle.addEventListener('pointerdown', onDown); 2710 2711 return { 2712 dispose() { 2713 handle.removeEventListener('pointerdown', onDown); 2714 document.removeEventListener('pointermove', onMove); 2715 } 2716 }; 2717 }, 2718 openDialog: function (options, dialogService, dialog) { 2719 if (!Radzen.dialogInvokerElement) { 2720 var invoker = document.activeElement; 2721 if (invoker && invoker !== document.body && !invoker.closest('.rz-dialog-content')) { 2722 Radzen.dialogInvokerElement = invoker; 2723 } 2724 } 2725 if (Radzen.closeAllPopups) { 2726 Radzen.closeAllPopups(); 2727 } 2728 Radzen.dialogService = dialogService; 2729 if ( 2730 document.documentElement.scrollHeight > 2731 document.documentElement.clientHeight 2732 ) { 2733 document.body.classList.add('no-scroll'); 2734 } 2735 2736 var currentDialogs = document.querySelectorAll('.rz-dialog-content'); 2737 var currentDialog = currentDialogs.length ? currentDialogs[currentDialogs.length - 1] : null; 2738 if (currentDialog) { 2739 currentDialog.options = options; 2740 var dialogRoot = currentDialog.closest('.rz-dialog') || currentDialog; 2741 dialogRoot.removeEventListener('keydown', Radzen.focusTrap); 2742 dialogRoot.addEventListener('keydown', Radzen.focusTrap); 2743 } 2744 2745 setTimeout(function () { 2746 var dialogs = document.querySelectorAll('.rz-dialog-content'); 2747 if (dialogs.length == 0) return; 2748 var lastDialog = dialogs[dialogs.length - 1]; 2749 2750 if (lastDialog) { 2751 lastDialog.options = options; 2752 2753 if (options.resizable) { 2754 var dialogElement = lastDialog.parentElement; 2755 2756 dialog.offsetWidth = dialogElement.offsetWidth; 2757 dialog.offsetHeight = dialogElement.offsetHeight; 2758 2759 var userResizing = false;
2760 2761 var pushSize = function () { 2762 if (!dialog) return; 2763 if (dialog.offsetWidth == dialogElement.offsetWidth && 2764 dialog.offsetHeight == dialogElement.offsetHeight) return; 2765 2766 dialog.offsetWidth = dialogElement.offsetWidth; 2767 dialog.offsetHeight = dialogElement.offsetHeight; 2768 2769 dialog.invokeMethodAsync( 2770 'RadzenDialog.OnResize', 2771 dialogElement.offsetWidth, 2772 dialogElement.offsetHeight 2773 ).catch(function () { }); 2774 }; 2775 2776 var stopTracking = function () { 2777 document.removeEventListener('pointermove', onPointerMove, true); 2778 document.removeEventListener('pointerup', onPointerUp, true); 2779 document.removeEventListener('pointercancel', onPointerUp, true); 2780 }; 2781 2782 var onPointerMove = function (e) { 2783 if (e.buttons === 1) { 2784 userResizing = true; 2785 return; 2786 } 2787 2788 onPointerUp(); 2789 }; 2790 2791 var onPointerUp = function () { 2792 stopTracking(); 2793 if (!userResizing) return; 2794 userResizing = false; 2795 pushSize(); 2796 }; 2797 2798 var onPointerDown = function (e) { 2799 if (e.button !== 0 || !e.isPrimary || e.target !== dialogElement) return; 2800 2801 document.addEventListener('pointermove', onPointerMove, true); 2802 document.addEventListener('pointerup', onPointerUp, true); 2803 document.addEventListener('pointercancel', onPointerUp, true); 2804 }; 2805 2806 var dialogResize = function (e) { 2807 if (!dialog) return; 2808 2809 if (!e[0].target.isConnected) { 2810 resizer.dispose(); 2811 return; 2812 } 2813 2814 if (!userResizing) { 2815 dialog.offsetWidth = e[0].target.offsetWidth; 2816 dialog.offsetHeight = e[0].target.offsetHeight; 2817 return; 2818 } 2819 2820 pushSize(); 2821 }; 2822 2823 var resizeObserver = new ResizeObserver(dialogResize); 2824 resizeObserver.observe(dialogElement); 2825 2826 dialogElement.addEventListener('pointerdown', onPointerDown); 2827 2828 var resizer = { 2829 disposed: false, 2830 dispose: function () { 2831 if (this.disposed) return; 2832 this.disposed = true; 2833 resizeObserver.disconnect(); 2834 dialogElement.removeEventListener('pointerdown', onPointerDown); 2835 stopTracking(); 2836 var index = Radzen.dialogResizers.indexOf(this); 2837 if (index != -1) { 2838 Radzen.dialogResizers.splice(index, 1); 2839 } 2840 if (Radzen.dialogResizer === this) { 2841 Radzen.dialogResizer = null; 2842 } 2843 }, 2844 disconnect: function () { this.dispose(); } 2845 }; 2846 2847 Radzen.dialogResizers = Radzen.dialogResizers || []; 2848 Radzen.dialogResizers.push(resizer); 2849 Radzen.dialogResizer = resizer; 2850 } 2851 2852 if (options.draggable) { 2853 var dialogTitle = lastDialog.parentElement.querySelector('.rz-dialog-titlebar'); 2854 if (dialogTitle) { 2855 dialogTitle.dragHandler = function (e) { 2856 var rect = lastDialog.parentElement.getBoundingClientRect(); 2857 var offsetX = e.clientX - rect.left; 2858 var offsetY = e.clientY - rect.top; 2859 2860 var move = function (e) { 2861 var left = e.clientX - offsetX; 2862 var top = e.clientY - offsetY; 2863 2864 lastDialog.parentElement.style.left = left + 'px'; 2865 lastDialog.parentElement.style.top = top + 'px'; 2866
2867 try { suppressDisposed(dialog.invokeMethodAsync('RadzenDialog.OnDrag', top, left)); } catch { } 2868 }; 2869 2870 var stop = function () { 2871 document.removeEventListener('mousemove', move); 2872 document.removeEventListener('mouseup', stop); 2873 }; 2874 2875 document.addEventListener('mousemove', move); 2876 document.addEventListener('mouseup', stop); 2877 }; 2878 2879 dialogTitle.addEventListener('mousedown', dialogTitle.dragHandler); 2880 } 2881 } 2882 2883 if (options.autoFocusFirstElement) { 2884 Radzen.focusFirstFocusableElement(lastDialog); 2885 } 2886 } 2887 }, 500); 2888 2889 document.removeEventListener('keydown', Radzen.closePopupOrDialog); 2890 if (options.closeDialogOnEsc) { 2891 document.addEventListener('keydown', Radzen.closePopupOrDialog); 2892 } 2893 }, 2894 closeDialog: function () { 2895 var resizers = (Radzen.dialogResizers || []).slice(); 2896 for (var i = 0; i < resizers.length; i++) { 2897 resizers[i].dispose(); 2898 } 2899 Radzen.dialogResizers = []; 2900 Radzen.dialogResizer = null; 2901 document.body.classList.remove('no-scroll'); 2902 var dialogs = document.querySelectorAll('.rz-dialog-content'); 2903 2904 var lastDialog = dialogs.length && dialogs[dialogs.length - 1]; 2905 if (lastDialog) { 2906 var dialogTitle = lastDialog.parentElement.querySelector('.rz-dialog-titlebar'); 2907 if (dialogTitle && dialogTitle.dragHandler) { 2908 dialogTitle.removeEventListener('mousedown', dialogTitle.dragHandler); 2909 dialogTitle.dragHandler = null; 2910 } 2911 } 2912 2913 if (dialogs.length <= 1) { 2914 document.removeEventListener('keydown', Radzen.closePopupOrDialog); 2915 delete Radzen.dialogService; 2916 Radzen.restoreDialogInvokerFocus(); 2917 } 2918 }, 2919 restoreDialogInvokerFocus: function () { 2920 var invoker = Radzen.dialogInvokerElement; 2921 Radzen.dialogInvokerElement = null; 2922 if (invoker && typeof invoker.focus === 'function' && document.body.contains(invoker)) { 2923 invoker.focus(); 2924 } 2925 }, 2926 disableKeydown: function (e) { 2927 e = e || window.event; 2928 e.preventDefault(); 2929 }, 2930 getFocusableElements: function (element) { 2931 return [...element.querySelectorAll('a, button, input, textarea, select, details, iframe, embed, object, summary, dialog, audio[controls], video[controls], [contenteditable], [tabindex]')] 2932 .filter(el => { 2933 if (!el || el.hasAttribute('disabled') || el.offsetParent === null) return false; 2934 2935 // If this is inside a .rz-html-editor with tabindex="-1", skip it 2936 var editorParent = el.closest('.rz-html-editor'); 2937 if (editorParent && editorParent.hasAttribute('tabindex') && editorParent.tabIndex === -1) return false; 2938 else if (editorParent) return true; 2939 2940 return el.tabIndex > -1; 2941 }); 2942 }, 2943 focusTrap: function (e) { 2944 e = e || window.event; 2945 var isTab = false; 2946 if ("key" in e) { 2947 isTab = (e.key === "Tab"); 2948 } else { 2949 isTab = (e.keyCode === 9); 2950 } 2951 if (isTab) { 2952 var focusable = Radzen.getFocusableElements(e.currentTarget); 2953 var firstFocusable = focusable[0]; 2954 var lastFocusable = focusable[focusable.length - 1]; 2955 2956 if (firstFocusable && lastFocusable && e.shiftKey && document.activeElement === firstFocusable) { 2957 e.preventDefault(); 2958 lastFocusable.focus(); 2959 } else if (firstFocusable && lastFocusable && !e.shiftKey && document.activeElement === lastFocusable) { 2960 e.preventDefault(); 2961 firstFocusable.focus(); 2962 } 2963 } 2964 }, 2965 closePopupOrDialog: function (e) { 2966 e = e || window.event; 2967 var isEscape = false;
2968 if ("key" in e) { 2969 isEscape = (e.key === "Escape" || e.key === "Esc"); 2970 } else { 2971 isEscape = (e.keyCode === 27); 2972 } 2973 if (isEscape && Radzen.dialogService) { 2974 var popups = document.querySelectorAll('.rz-popup,.rz-overlaypanel'); 2975 for (var i = 0; i < popups.length; i++) { 2976 if (popups[i].style.display != 'none') { 2977 return; 2978 } 2979 } 2980 2981 var dialogs = document.querySelectorAll('.rz-dialog-content'); 2982 if (dialogs.length == 0) return; 2983 var lastDialog = dialogs[dialogs.length - 1]; 2984 2985 if (lastDialog && lastDialog.options && lastDialog.options.closeDialogOnEsc) { 2986 try { 2987 Radzen.dialogService.invokeMethodAsync('DialogService.TryClose', null).then(function(closed) { 2988 if (closed && dialogs.length <= 1) { 2989 document.removeEventListener('keydown', Radzen.closePopupOrDialog); 2990 delete Radzen.dialogService; 2991 var layout = document.querySelector('.rz-layout'); 2992 if (layout) { 2993 layout.removeEventListener('keydown', Radzen.disableKeydown); 2994 } 2995 } 2996 }); 2997 } catch (e) { } 2998 } 2999 } 3000 }, 3001 getNumericValue: function (arg) { 3002 var el = 3003 arg instanceof Element || arg instanceof HTMLDocument 3004 ? arg 3005 : document.getElementById(arg); 3006 return el ? Radzen.getInputValue(el.children[0]) : null; 3007 }, 3008 getInputValue: function (arg) { 3009 var input = 3010 arg instanceof Element || arg instanceof HTMLDocument 3011 ? arg 3012 : document.getElementById(arg); 3013 return input && input.value != '' ? input.value : null; 3014 }, 3015 setInputValue: function (arg, value) { 3016 var input = 3017 arg instanceof Element || arg instanceof HTMLDocument 3018 ? arg 3019 : document.getElementById(arg); 3020 if (input) { 3021 input.value = value; 3022 } 3023 }, 3024 getSelectionRange: function (arg) { 3025 var input = 3026 arg instanceof Element || arg instanceof HTMLDocument 3027 ? arg 3028 : document.getElementById(arg); 3029 if (!input) return null; 3030 try { 3031 if (input.selectionStart === null || input.selectionStart === undefined) return null; 3032 return [input.selectionStart, input.selectionEnd]; 3033 } catch (e) { 3034 return null; 3035 } 3036 }, 3037 setSelectionRange: function (arg, start, end) { 3038 var input = 3039 arg instanceof Element || arg instanceof HTMLDocument 3040 ? arg 3041 : document.getElementById(arg); 3042 if (!input) return; 3043 var max = input.value ? input.value.length : 0; 3044 var s = Math.max(0, Math.min(start, max)); 3045 var e = Math.max(0, Math.min(end, max)); 3046 try { 3047 if (typeof input.setSelectionRange === 'function') { 3048 input.setSelectionRange(s, e); 3049 } else { 3050 input.selectionStart = s; 3051 input.selectionEnd = e; 3052 } 3053 } catch (ex) { } 3054 }, 3055 isScrolledToBottom: function (arg, threshold) { 3056 var element = 3057 arg instanceof Element || arg instanceof HTMLDocument 3058 ? arg 3059 : document.getElementById(arg); 3060 if (!element) return false; 3061 var offset = typeof threshold === 'number' ? threshold : 0; 3062 return element.scrollTop + element.clientHeight >= element.scrollHeight - offset; 3063 }, 3064 blur: function (el, e) { 3065 if (el) { 3066 e.preventDefault(); 3067 el.dispatchEvent(new KeyboardEvent('keydown', { bubbles: true, cancelable: true, keyCode: 9 })); 3068 } 3069 }, 3070 readFileAsBase64: function (fileInput, maxFileSize, maxWidth, maxHeight) { 3071 var calculateWidthAndHeight = function (img) { 3072 var width = img.width; 3073 var height = img.height; 3074 // Change the resizing logic 3075 if (width > height) { 3076 if (width > maxWidth) { 3077 height = height * (maxWidth / width); 3078 width = maxWidth; 3079 } 3080 } else { 3081 if (height > maxHeight) { 3082 width = width * (maxHeight / height); 3083 height = maxHeight; 3084 } 3085 } 3086 return { width, height }; 3087 }; 3088 var readAsDataURL = function (fileInput) { 3089 return new Promise(function (resolve, reject) { 3090 var reader = new FileReader(); 3091 reader.onerror = function () { 3092 reader.abort(); 3093 reject('Error reading file.'); 3094 }; 3095 reader.addEventListener( 3096 'load', 3097 function () { 3098 if (fileInput.files[0] && fileInput.files[0].type.includes('image') && maxWidth > 0 && maxHeight > 0) { 3099 var img = document.createElement("img"); 3100 img.onload = function (event) { 3101 // Dynamically create a canvas element 3102 var canvas = document.createElement("canvas"); 3103 var res = calculateWidthAndHeight(img); 3104 canvas.width = res.width; 3105 canvas.height = res.height; 3106 var ctx = canvas.getContext("2d"); 3107 ctx.drawImage(img, 0, 0, res.width, res.height); 3108 resolve(canvas.toDataURL(fileInput.type)); 3109 } 3110 img.src = reader.result; 3111 } else { 3112 resolve(reader.result); 3113 } 3114 }, 3115 false 3116 ); 3117 var file = fileInput.files[0]; 3118 if (!file) return; 3119 if (file.size <= maxFileSize) {
3120 reader.readAsDataURL(file); 3121 } else { 3122 reject('File too large.'); 3123 } 3124 }); 3125 }; 3126 3127 return readAsDataURL(fileInput); 3128 }, 3129 closeMenuItem: function (item) { 3130 if (!item || !item.classList || !item.classList.contains('rz-navigation-item-active')) { 3131 return; 3132 } 3133 3134 item.classList.remove('rz-navigation-item-active'); 3135 3136 var wrapper = item.querySelector('.rz-navigation-item-wrapper'); 3137 if (wrapper) { 3138 wrapper.classList.remove('rz-navigation-item-wrapper-active'); 3139 } 3140 3141 var children = item.querySelector('.rz-navigation-menu'); 3142 if (children) { 3143 item.setAttribute('aria-expanded', false); 3144 children.onanimationend = function () { 3145 children.style.display = 'none'; 3146 children.style.insetInlineStart = ''; 3147 children.onanimationend = null; 3148 }; 3149 children.classList.remove('rz-open'); 3150 children.classList.add('rz-close'); 3151 3152 children.querySelectorAll('.rz-navigation-item-active').forEach(function (nested) { 3153 Radzen.closeMenuItem(nested); 3154 }); 3155 } 3156 3157 var icon = item.querySelector('.rz-navigation-item-icon-children'); 3158 if (icon) { 3159 icon.classList.remove('rz-state-expanded'); 3160 icon.classList.add('rz-state-collapsed'); 3161 } 3162 }, 3163 toggleMenuItem: function (target, event, defaultActive, clickToOpen) { 3164 if (!target) return; 3165 3166 var item = target.closest('.rz-navigation-item'); 3167 3168 if (!item) return; 3169 3170 var active = defaultActive != undefined ? defaultActive : !item.classList.contains('rz-navigation-item-active'); 3171 3172 function toggle(active) { 3173 if (active && item.parentElement) { 3174 Array.prototype.forEach.call(item.parentElement.children, function (sibling) { 3175 if (sibling !== item) { 3176 Radzen.closeMenuItem(sibling); 3177 } 3178 }); 3179 } 3180 3181 item.classList.toggle('rz-navigation-item-active', active); 3182 3183 target.classList.toggle('rz-navigation-item-wrapper-active', active); 3184 3185 var children = item.querySelector('.rz-navigation-menu'); 3186 3187 if (children) { 3188 item.setAttribute('aria-expanded', active); 3189 if (active) { 3190 children.onanimationend = null; 3191 children.style.display = ''; 3192 children.classList.add('rz-open'); 3193 children.classList.remove('rz-close'); 3194 3195 var isRtl = getComputedStyle(item).direction === 'rtl'; 3196 var round = function (value) { return Math.round(value * 1000) / 1000; }; 3197 var el = item.parentElement; 3198 var scrollParent = null; 3199 while (el && el !== document.body) { 3200 var s = getComputedStyle(el); 3201 if (s.overflowX === 'auto' || s.overflowX === 'scroll' || s.overflowX === 'hidden') { 3202 scrollParent = el; 3203 break; 3204 } 3205 el = el.parentElement; 3206 } 3207 3208 if (children.hasAttribute('data-flyout')) { 3209 children.removeAttribute('data-flyout-flip'); 3210 var childRect = children.getBoundingClientRect(); 3211 var itemRect = item.getBoundingClientRect(); 3212 if (isRtl) { 3213 var leftBoundary = scrollParent ? scrollParent.getBoundingClientRect().left : 0; 3214 if (round(itemRect.left - childRect.width) < round(leftBoundary)) { 3215 children.setAttribute('data-flyout-flip', ''); 3216 } 3217 } else { 3218 var rightBoundary = scrollParent ? scrollParent.getBoundingClientRect().right : document.documentElement.clientWidth; 3219 if (round(itemRect.right + childRect.width) > round(rightBoundary)) { 3220 children.setAttribute('data-flyout-flip', ''); 3221 } 3222 } 3223 } 3224 3225 // Shift dropdown left/right if it overflows the scroll parent or viewport 3226 children.style.insetInlineStart = children.style.insetInlineStart || ''; 3227 var childRect = children.getBoundingClientRect(); 3228 var rightBoundary = scrollParent ? scrollParent.getBoundingClientRect().right : document.documentElement.clientWidth; 3229 var leftBoundary = scrollParent ? scrollParent.getBoundingClientRect().left : 0; 3230 if (!isRtl && round(childRect.right) > round(rightBoundary)) { 3231 var offset = parseFloat(children.style.insetInlineStart) || 0; 3232 children.style.insetInlineStart = (offset + rightBoundary - childRect.right) + 'px'; 3233 } else if (isRtl && round(childRect.left) < round(leftBoundary)) { 3234 var offset = parseFloat(children.style.insetInlineStart) || 0; 3235 children.style.insetInlineStart = (offset + leftBoundary - childRect.left) + 'px'; 3236 } 3237 } else { 3238 children.onanimationend = function () { 3239 children.style.display = 'none'; 3240 children.style.insetInlineStart = ''; 3241 children.onanimationend = null; 3242 }
3243 children.classList.remove('rz-open'); 3244 children.classList.add('rz-close'); 3245 } 3246 } 3247 3248 var icon = item.querySelector('.rz-navigation-item-icon-children'); 3249 3250 if (icon) { 3251 icon.classList.toggle('rz-state-expanded', active); 3252 icon.classList.toggle('rz-state-collapsed', !active); 3253 } 3254 } 3255 3256 if (clickToOpen === false && item.parentElement && item.parentElement.closest('.rz-navigation-item') && !defaultActive) { 3257 return; 3258 }; 3259 3260 toggle(active); 3261 3262 document.removeEventListener('click', target.clickHandler); 3263 3264 target.clickHandler = function (event) { 3265 if (item.contains(event.target)) { 3266 var child = event.target.closest('.rz-navigation-item'); 3267 if (child && child.querySelector('.rz-navigation-menu')) { 3268 return; 3269 } 3270 } 3271 toggle(false); 3272 } 3273 3274 document.addEventListener('click', target.clickHandler); 3275 }, 3276 destroyChart: function (ref) { 3277 if(!ref) return; 3278 ref.removeEventListener('mouseleave', ref.mouseLeaveHandler); 3279 delete ref.mouseLeaveHandler; 3280 ref.removeEventListener('mouseenter', ref.mouseEnterHandler); 3281 delete ref.mouseEnterHandler; 3282 ref.removeEventListener('mousemove', ref.mouseMoveHandler); 3283 delete ref.mouseMoveHandler; 3284 ref.removeEventListener('click', ref.clickHandler); 3285 delete ref.clickHandler; 3286 ref.removeEventListener('wheel', ref.wheelHandler); 3287 delete ref.wheelHandler; 3288 if (ref.legendEnterHandler) { 3289 ref.removeEventListener('mouseenter', ref.legendEnterHandler, true); 3290 delete ref.legendEnterHandler; 3291 } 3292 if (ref.legendLeaveHandler) { 3293 ref.removeEventListener('mouseleave', ref.legendLeaveHandler, true); 3294 delete ref.legendLeaveHandler; 3295 } 3296 if (ref.scrollbarMoveHandler) { 3297 document.removeEventListener('mousemove', ref.scrollbarMoveHandler); 3298 delete ref.scrollbarMoveHandler; 3299 } 3300 if (ref.scrollbarUpHandler) { 3301 document.removeEventListener('mouseup', ref.scrollbarUpHandler); 3302 delete ref.scrollbarUpHandler; 3303 } 3304 if (ref.scrollbarTouchMoveHandler) { 3305 document.removeEventListener('touchmove', ref.scrollbarTouchMoveHandler); 3306 delete ref.scrollbarTouchMoveHandler; 3307 } 3308 if (ref.scrollbarTouchEndHandler) { 3309 document.removeEventListener('touchend', ref.scrollbarTouchEndHandler); 3310 delete ref.scrollbarTouchEndHandler; 3311 } 3312 if (ref.touchStartHandler) { 3313 ref.removeEventListener('touchstart', ref.touchStartHandler); 3314 delete ref.touchStartHandler; 3315 } 3316 if (ref.touchMoveHandler) { 3317 ref.removeEventListener('touchmove', ref.touchMoveHandler); 3318 delete ref.touchMoveHandler; 3319 } 3320 if (ref.touchEndHandler) { 3321 ref.removeEventListener('touchend', ref.touchEndHandler); 3322 delete ref.touchEndHandler; 3323 } 3324 if (ref._chartRTLObserver) { 3325 ref._chartRTLObserver.disconnect(); 3326 delete ref._chartRTLObserver; 3327 } 3328 this.destroyResizable(ref); 3329 }, 3330 createRangeNavigator: function (ref, instance) { 3331 if (!ref) return [0, 0]; 3332 3333 var width = ref.offsetWidth; 3334 var height = ref.offsetHeight; 3335 3336 var dragging = null; 3337 var dragStartX = 0; 3338 var dragStartStart = 0; 3339 var dragStartEnd = 0; 3340 var currentStart = 0; 3341 var currentEnd = 1; 3342 var minRange = 0.01; 3343 function isRTL() { 3344 return document.documentElement.dir === 'rtl'; 3345 } 3346 3347 function getPositionFromEvent(e) { 3348 var rect = ref.getBoundingClientRect(); 3349 var x = (e.touches ? e.touches[0].clientX : e.clientX) - rect.left; 3350 if (isRTL()) x = rect.width - x; 3351 return Math.max(0, Math.min(1, x / rect.width)); 3352 } 3353 3354 function readPositionFromDOM() { 3355 var w = ref.querySelector('.rz-range-nav-window'); 3356 if (w) { 3357 var wRect = w.getBoundingClientRect(); 3358 var rRect = ref.getBoundingClientRect(); 3359 if (rRect.width > 0) { 3360 if (isRTL()) { 3361 currentStart = (rRect.right - wRect.right) / rRect.width; 3362 currentEnd = (rRect.right - wRect.left) / rRect.width; 3363 } else { 3364 currentStart = (wRect.left - rRect.left) / rRect.width; 3365 currentEnd = (wRect.right - rRect.left) / rRect.width; 3366 } 3367 } 3368 } 3369 } 3370 3371 var snapThreshold = 0.01; 3372 function snap(v) { return v < snapThreshold ? 0 : v > 1 - snapThreshold ? 1 : v; } 3373 3374 // Label state — set by Radzen.updateRangeNavigatorLabels 3375 ref.navLabelIsDate = false;
3376 ref.navLabelInputStart = 0; 3377 ref.navLabelInputEnd = 0; 3378 3379 function formatLabel(fraction) { 3380 var inputStart = ref.navLabelInputStart; 3381 var inputEnd = ref.navLabelInputEnd; 3382 if (inputStart === inputEnd) return ''; 3383 var value = inputStart + fraction * (inputEnd - inputStart); 3384 if (ref.navLabelIsDate) { 3385 // .NET ticks to JS Date: ticks are 100ns intervals from 0001-01-01 3386 var ticksToMs = value / 10000 - 62135596800000; 3387 var d = new Date(ticksToMs); 3388 var m = d.getMonth() + 1; 3389 var day = d.getDate(); 3390 var y = d.getFullYear(); 3391 return (m < 10 ? '0' : '') + m + '/' + (day < 10 ? '0' : '') + day + '/' + y; 3392 } 3393 return Math.round(value).toString(); 3394 } 3395 3396 function setLabelText(el, text) { 3397 if (el.firstChild && el.firstChild.nodeType === 3) { 3398 el.firstChild.nodeValue = text; 3399 } else { 3400 el.textContent = text; 3401 } 3402 } 3403 3404 function updateLabels(start, end) { 3405 if (!ref.navLabelInputEnd) return; 3406 var labels = ref.querySelectorAll('.rz-range-nav-label'); 3407 if (labels.length >= 2) { 3408 setLabelText(labels[0], formatLabel(start)); 3409 setLabelText(labels[1], formatLabel(end)); 3410 // Flip label direction when near edges 3411 labels[0].className = 'rz-range-nav-label ' + (start < 0.1 ? 'rz-range-nav-label-end' : 'rz-range-nav-label-start'); 3412 labels[1].className = 'rz-range-nav-label ' + (end > 0.9 ? 'rz-range-nav-label-start' : 'rz-range-nav-label-end'); 3413 } 3414 } 3415 3416 function updateDOM(start, end) { 3417 currentStart = snap(start); 3418 currentEnd = snap(end); 3419 start = currentStart; 3420 end = currentEnd; 3421 var win = ref.querySelector('.rz-range-nav-window'); 3422 var shadeLeft = ref.querySelector('.rz-range-nav-shade-start'); 3423 var shadeRight = ref.querySelector('.rz-range-nav-shade-end'); 3424 if (win) { 3425 if (isRTL()) { 3426 win.style.right = (start * 100) + '%'; 3427 win.style.left = 'auto'; 3428 } else { 3429 win.style.left = (start * 100) + '%'; 3430 win.style.right = 'auto'; 3431 } 3432 win.style.width = ((end - start) * 100) + '%'; 3433 } 3434 if (shadeLeft) shadeLeft.style.width = (start * 100) + '%'; 3435 if (shadeRight) shadeRight.style.width = ((1 - end) * 100) + '%'; 3436 updateLabels(start, end); 3437 } 3438 3439 function notifyBlazor(start, end) { 3440 instance.invokeMethodAsync('OnNavigatorDrag', snap(start), snap(end)).catch(function (ex) { 3441 console.error('RangeNav invoke error:', ex); 3442 }); 3443 } 3444 3445 readPositionFromDOM(); 3446 3447 ref.navMouseDown = function (e) { 3448 // Always read fresh position from DOM on mousedown 3449 readPositionFromDOM(); 3450 3451 var pos = getPositionFromEvent(e); 3452 var handleZone = 12 / (ref.offsetWidth || 1); 3453 var winRange = currentEnd - currentStart; 3454 3455 if (pos >= currentStart - handleZone && pos <= currentEnd + handleZone) { 3456 var distToLeft = Math.abs(pos - currentStart); 3457 var distToRight = Math.abs(pos - currentEnd); 3458 3459 if (winRange < handleZone * 3) { 3460 dragging = distToLeft <= distToRight ? 'left' : 'right'; 3461 } else if (distToLeft <= handleZone) { 3462 dragging = 'left'; 3463 } else if (distToRight <= handleZone) { 3464 dragging = 'right'; 3465 } else { 3466 dragging = 'pan'; 3467 } 3468 } else { 3469 // Click on shade: center selection at click position 3470 var halfRange = winRange / 2; 3471 var newStart = Math.max(0, Math.min(1 - winRange, pos - halfRange)); 3472 var newEnd = newStart + winRange; 3473 updateDOM(newStart, newEnd); 3474 notifyBlazor(newStart, newEnd); 3475 return; 3476 } 3477 3478 if (dragging) { 3479 e.preventDefault(); 3480 dragStartX = (e.touches ? e.touches[0].clientX : e.clientX); 3481 dragStartStart = currentStart; 3482 dragStartEnd = currentEnd; 3483 } 3484 }; 3485 3486 ref.navMouseMove = function (e) { 3487 if (!dragging) return; 3488 e.preventDefault(); 3489 var clientX = e.touches ? e.touches[0].clientX : e.clientX; 3490 var dx = clientX - dragStartX; 3491 if (isRTL()) dx = -dx; 3492 var refWidth = ref.offsetWidth; 3493 if (refWidth <= 0) return; 3494 var delta = dx / refWidth; 3495 3496 var newStart = dragStartStart; 3497 var newEnd = dragStartEnd; 3498 3499 if (dragging === 'left') { 3500 newStart = Math.max(0, Math.min(dragStartEnd - minRange, dragStartStart + delta)); 3501 } else if (dragging === 'right') { 3502 newEnd = Math.max(dragStartStart + minRange, Math.min(1, dragStartEnd + delta)); 3503 } else if (dragging === 'pan') { 3504 var range = dragStartEnd - dragStartStart; 3505 newStart = dragStartStart + delta; 3506 newEnd = newStart + range; 3507 if (newStart < 0) { newStart = 0; newEnd = range; } 3508 if (newEnd > 1) { newEnd = 1; newStart = 1 - range; } 3509 } 3510 3511 updateDOM(newStart, newEnd); 3512 }; 3513 3514 ref.navMouseUp = function () { 3515 if (dragging) { 3516 notifyBlazor(currentStart, currentEnd); 3517 } 3518 dragging = null; 3519 }; 3520 3521 ref.addEventListener('mousedown', ref.navMouseDown); 3522 ref.addEventListener('touchstart', ref.navMouseDown, { passive: false }); 3523 document.addEventListener('mousemove', ref.navMouseMove); 3524 document.addEventListener('touchmove', ref.navMouseMove, { passive: false }); 3525 document.addEventListener('mouseup', ref.navMouseUp); 3526 document.addEventListener('touchend', ref.navMouseUp); 3527 3528 ref.navResizeObserver = new ResizeObserver(function (entries) {
3529 for (var entry of entries) { 3530 var w = entry.contentRect.width; 3531 var h = entry.contentRect.height; 3532 if (w > 0) { 3533 try { suppressDisposed(instance.invokeMethodAsync('OnResize', w, h)); } catch (ex) {} 3534 } 3535 } 3536 }); 3537 ref.navResizeObserver.observe(ref); 3538 3539 ref._radzenDispose = function () { 3540 if (ref.navMouseDown) { 3541 ref.removeEventListener('mousedown', ref.navMouseDown); 3542 ref.removeEventListener('touchstart', ref.navMouseDown); 3543 delete ref.navMouseDown; 3544 } 3545 if (ref.navMouseMove) { 3546 document.removeEventListener('mousemove', ref.navMouseMove); 3547 document.removeEventListener('touchmove', ref.navMouseMove); 3548 delete ref.navMouseMove; 3549 } 3550 if (ref.navMouseUp) { 3551 document.removeEventListener('mouseup', ref.navMouseUp); 3552 document.removeEventListener('touchend', ref.navMouseUp); 3553 delete ref.navMouseUp; 3554 } 3555 if (ref.navResizeObserver) { 3556 ref.navResizeObserver.disconnect(); 3557 delete ref.navResizeObserver; 3558 } 3559 }; 3560 return [width, height]; 3561 }, 3562 3563 updateRangeNavigatorLabels: function (ref, isDate, inputStart, inputEnd) { 3564 if (!ref) return; 3565 ref.navLabelIsDate = isDate; 3566 ref.navLabelInputStart = inputStart; 3567 ref.navLabelInputEnd = inputEnd; 3568 }, 3569 3570 destroyGauge: function (ref) { 3571 if (ref._gaugeRTLObserver) { 3572 ref._gaugeRTLObserver.disconnect(); 3573 delete ref._gaugeRTLObserver; 3574 } 3575 this.destroyResizable(ref); 3576 }, 3577 disposeElement: function (ref) { 3578 if (ref && ref._radzenDispose) { 3579 ref._radzenDispose(); 3580 delete ref._radzenDispose; 3581 } 3582 }, 3583 destroyResizable: function (ref) { 3584 if (ref.resizeObserver) { 3585 ref.resizeObserver.disconnect(); 3586 delete ref.resizeObserver; 3587 } 3588 if (ref.resizeHandler) { 3589 window.removeEventListener('resize', ref.resizeHandler); 3590 delete ref.resizeHandler; 3591 } 3592 }, 3593 createResizable: function (ref, instance) { 3594 ref.resizeHandler = function () { 3595 var rect = ref.getBoundingClientRect(); 3596 3597 try { suppressDisposed(instance.invokeMethodAsync('Resize', rect.width, rect.height)); } catch { } 3598 }; 3599 3600 if (window.ResizeObserver) { 3601 ref.resizeObserver = new ResizeObserver(ref.resizeHandler); 3602 ref.resizeObserver.observe(ref); 3603 } else { 3604 window.addEventListener('resize', ref.resizeHandler); 3605 } 3606 3607 var self = this; 3608 ref._radzenDispose = function () { self.destroyResizable(ref); }; 3609 var rect = ref.getBoundingClientRect(); 3610 return { width: rect.width, height: rect.height }; 3611 }, 3612 chartToSvg: function (ref) { 3613 var svg = ref && ref.querySelector(':scope > svg'); 3614 if (!svg) return ''; 3615 3616 var clone = svg.cloneNode(true); 3617 var props = ['fill', 'fill-opacity', 'stroke', 'stroke-width', 'stroke-dasharray', 'stroke-linecap', 3618 'stroke-linejoin', 'opacity', 'font-size', 'font-family', 'font-weight', 'font-variant-numeric', 3619 'text-anchor', 'dominant-baseline', 'stop-color', 'stop-opacity']; 3620 var bake = function (source, target) { 3621 var computed = getComputedStyle(source); 3622 var style = ''; 3623 for (var i = 0; i < props.length; i++) { 3624 var value = computed.getPropertyValue(props[i]); 3625 if (value && value !== 'none' || props[i] === 'fill' || props[i] === 'stroke') { 3626 style += props[i] + ':' + value + ';'; 3627 } 3628 } 3629 target.setAttribute('style', style); 3630 }; 3631 var sources = svg.querySelectorAll('*'); 3632 var targets = clone.querySelectorAll('*'); 3633 for (var i = 0; i < sources.length; i++) { 3634 bake(sources[i], targets[i]); 3635 } 3636 3637 var rect = svg.getBoundingClientRect(); 3638 clone.setAttribute('width', rect.width); 3639 clone.setAttribute('height', rect.height); 3640 clone.setAttribute('xmlns', 'http://www.w3.org/2000/svg'); 3641 3642 return new XMLSerializer().serializeToString(clone); 3643 }, 3644 svgToPng: async function (svg, width, height) { 3645 if (!svg) return null; 3646 3647 var svgUrl = 'data:image/svg+xml;charset=utf-8,' + encodeURIComponent(svg); 3648 var img = new Image(); 3649 await new Promise(function (resolve, reject) { 3650 img.onload = resolve; 3651 img.onerror = reject; 3652 img.src = svgUrl; 3653 }); 3654
3655 var naturalWidth = img.naturalWidth || img.width; 3656 var naturalHeight = img.naturalHeight || img.height; 3657 var canvas = document.createElement('canvas'); 3658 if (width > 0 || height > 0) { 3659 canvas.width = Math.round(width > 0 ? width : height * naturalWidth / naturalHeight); 3660 canvas.height = Math.round(height > 0 ? height : width * naturalHeight / naturalWidth); 3661 } else { 3662 var scale = Math.max(2, window.devicePixelRatio || 1); 3663 canvas.width = Math.round(naturalWidth * scale); 3664 canvas.height = Math.round(naturalHeight * scale); 3665 } 3666 var ctx = canvas.getContext('2d'); 3667 var background = getComputedStyle(document.body).backgroundColor; 3668 if (background && background !== 'rgba(0, 0, 0, 0)') { 3669 ctx.fillStyle = background; 3670 ctx.fillRect(0, 0, canvas.width, canvas.height); 3671 } 3672 ctx.drawImage(img, 0, 0, canvas.width, canvas.height); 3673 3674 return await new Promise(function (resolve) { 3675 canvas.toBlob(resolve, 'image/png'); 3676 }); 3677 }, 3678 downloadSvgAsPng: async function (svg, fileName, width, height) { 3679 var blob = await this.svgToPng(svg, width, height); 3680 if (blob) { 3681 this.downloadFile(fileName, blob, 'image/png'); 3682 } 3683 }, 3684 createChart: function (ref, instance, mouseMoveInterval) { 3685 var inside = false;
3686 var interval = mouseMoveInterval || 0; 3687 var lastDispatch = 0; 3688 var pendingMove = null; 3689 var moveRafId = null; 3690 3691 function dispatchMouseMove() { 3692 moveRafId = null; 3693 if (!pendingMove) return; 3694 var now = performance.now(); 3695 if (interval > 0 && now - lastDispatch < interval) { 3696 moveRafId = requestAnimationFrame(dispatchMouseMove); 3697 return; 3698 } 3699 lastDispatch = now; 3700 var move = pendingMove; 3701 pendingMove = null; 3702 try { suppressDisposed(instance.invokeMethodAsync('MouseMove', move.x, move.y)); } catch { } 3703 } 3704 3705 ref.mouseMoveHandler = function (e) { 3706 if (inside) { 3707 var rect = ref.getBoundingClientRect(); 3708 pendingMove = { x: e.clientX - rect.left, y: e.clientY - rect.top }; 3709 if (!moveRafId) { 3710 moveRafId = requestAnimationFrame(dispatchMouseMove); 3711 } 3712 } 3713 }; 3714 ref.mouseEnterHandler = function () { 3715 inside = true; 3716 }; 3717 ref.mouseLeaveHandler = function (e) { 3718 if (e.relatedTarget && (e.relatedTarget.matches('.rz-chart-tooltip') || e.relatedTarget.closest('.rz-chart-tooltip'))) { 3719 return; 3720 } 3721 inside = false;
3722 try { suppressDisposed(instance.invokeMethodAsync('MouseMove', -1, -1)); } catch { } 3723 }; 3724 ref.clickHandler = function (e) { 3725 var rect = ref.getBoundingClientRect(); 3726 var x = e.clientX - rect.left; 3727 var y = e.clientY - rect.top; 3728 if (!e.target.closest('.rz-marker') && !e.target.closest('.rz-legend-item')) { 3729 try { suppressDisposed(instance.invokeMethodAsync('Click', x, y)); } catch { } 3730 } 3731 }; 3732 3733 ref.wheelHandler = function (e) { 3734 if (!inside || ref.dataset.allowZoom !== 'true') return; 3735 var delta = e.deltaY > 0 ? 1 : -1; 3736 var range = parseFloat(ref.dataset.zoomEnd) - parseFloat(ref.dataset.zoomStart); 3737 if (isNaN(range)) range = 1; 3738 if (delta < 0 ? range <= 0.01 + 1e-6 : range >= 1 - 1e-6) return; 3739 e.preventDefault(); 3740 var rect = ref.getBoundingClientRect(); 3741 var x = e.clientX - rect.left; 3742 try { suppressDisposed(instance.invokeMethodAsync('OnWheel', x, delta)); } catch {} 3743 }; 3744 3745 ref.addEventListener('mouseenter', ref.mouseEnterHandler); 3746 ref.addEventListener('mouseleave', ref.mouseLeaveHandler); 3747 ref.addEventListener('mousemove', ref.mouseMoveHandler); 3748 ref.addEventListener('click', ref.clickHandler); 3749 ref.addEventListener('wheel', ref.wheelHandler, { passive: false }); 3750 3751 // Legend hover → series highlight (only when AllowSeriesHover is enabled) 3752 ref.legendEnterHandler = function (e) { 3753 if (!ref.classList.contains('rz-chart-series-hover')) return; 3754 var legendItem = e.target.closest('.rz-legend-item'); 3755 if (!legendItem) return; 3756 var g = legendItem.querySelector('g[class]'); 3757 if (!g) return; 3758 var classes = g.className.baseVal || g.getAttribute('class') || ''; 3759 var match = classes.match(/rz-series-item-\d+|rz-series-\d+/); 3760 if (!match) return; 3761 var selector = '.' + match[0]; 3762 var svg = ref.querySelector('svg'); 3763 if (!svg) return; 3764 var targets = svg.querySelectorAll(selector); 3765 targets.forEach(function (t) { t.classList.add('rz-state-hover'); }); 3766 }; 3767 ref.legendLeaveHandler = function (e) { 3768 if (!ref.classList.contains('rz-chart-series-hover')) return; 3769 var legendItem = e.target.closest('.rz-legend-item'); 3770 if (!legendItem) return; 3771 var svg = ref.querySelector('svg'); 3772 if (!svg) return; 3773 var hovered = svg.querySelectorAll('.rz-state-hover'); 3774 hovered.forEach(function (t) { t.classList.remove('rz-state-hover'); }); 3775 }; 3776 ref.addEventListener('mouseenter', ref.legendEnterHandler, true); 3777 ref.addEventListener('mouseleave', ref.legendLeaveHandler, true); 3778 3779 // Scrollbar drag handling via event delegation (survives Blazor re-renders) 3780 var dragging = false; 3781 var dragStartX = 0; 3782 var dragStartPos = 0; 3783 3784 function isChartRTL() { 3785 return document.documentElement.dir === 'rtl'; 3786 } 3787 3788 function getThumbPos(thumb) { 3789 return parseFloat(isChartRTL() ? thumb.style.right : thumb.style.left) || 0; 3790 } 3791 3792 function setThumbPos(thumb, pos) { 3793 if (isChartRTL()) { 3794 thumb.style.right = pos + '%'; 3795 thumb.style.left = ''; 3796 } else { 3797 thumb.style.left = pos + '%'; 3798 thumb.style.right = ''; 3799 } 3800 } 3801 3802 ref.addEventListener('mousedown', function (e) { 3803 var thumb = e.target.closest('.rz-chart-scrollbar-thumb'); 3804 if (!thumb) return; 3805 dragging = true; 3806 dragStartX = e.clientX; 3807 dragStartPos = getThumbPos(thumb); 3808 e.preventDefault(); 3809 }); 3810 3811 ref.scrollbarMoveHandler = function (e) { 3812 if (!dragging) return; 3813 var track = ref.querySelector('.rz-chart-scrollbar-track'); 3814 var thumb = ref.querySelector('.rz-chart-scrollbar-thumb'); 3815 if (!track || !thumb) return; 3816 var trackWidth = track.offsetWidth; 3817 if (trackWidth <= 0) return; 3818 var dx = e.clientX - dragStartX; 3819 var deltaPercent = (isChartRTL() ? -dx : dx) / trackWidth * 100; 3820 var newPos = Math.max(0, Math.min(100 - parseFloat(thumb.style.width), dragStartPos + deltaPercent)); 3821 setThumbPos(thumb, newPos); 3822 var position = newPos / 100;
3823 try { suppressDisposed(instance.invokeMethodAsync('OnPan', position)); } catch {} 3824 }; 3825 document.addEventListener('mousemove', ref.scrollbarMoveHandler); 3826 3827 ref.scrollbarUpHandler = function () { 3828 dragging = false; 3829 }; 3830 document.addEventListener('mouseup', ref.scrollbarUpHandler); 3831 3832 ref.addEventListener('click', function (e) { 3833 var track = e.target.closest('.rz-chart-scrollbar-track'); 3834 if (!track || e.target.closest('.rz-chart-scrollbar-thumb')) return; 3835 var thumb = track.querySelector('.rz-chart-scrollbar-thumb'); 3836 if (!thumb) return; 3837 var trackRect = track.getBoundingClientRect(); 3838 var clickX = isChartRTL() ? trackRect.right - e.clientX : e.clientX - trackRect.left; 3839 var thumbWidth = thumb.offsetWidth; 3840 var position = Math.max(0, Math.min(1 - thumbWidth / track.offsetWidth, (clickX - thumbWidth / 2) / track.offsetWidth)); 3841 try { suppressDisposed(instance.invokeMethodAsync('OnPan', position)); } catch {} 3842 }); 3843 3844 // Touch support for scrollbar drag 3845 ref.addEventListener('touchstart', function (e) { 3846 var thumb = e.target.closest('.rz-chart-scrollbar-thumb'); 3847 if (!thumb) return; 3848 dragging = true; 3849 dragStartX = e.touches[0].clientX; 3850 dragStartPos = getThumbPos(thumb); 3851 e.preventDefault(); 3852 }, { passive: false }); 3853 3854 ref.scrollbarTouchMoveHandler = function (e) { 3855 if (!dragging) return; 3856 var track = ref.querySelector('.rz-chart-scrollbar-track'); 3857 var thumb = ref.querySelector('.rz-chart-scrollbar-thumb'); 3858 if (!track || !thumb) return; 3859 var trackWidth = track.offsetWidth; 3860 if (trackWidth <= 0) return; 3861 var dx = e.touches[0].clientX - dragStartX; 3862 var deltaPercent = (isChartRTL() ? -dx : dx) / trackWidth * 100; 3863 var newPos = Math.max(0, Math.min(100 - parseFloat(thumb.style.width), dragStartPos + deltaPercent)); 3864 setThumbPos(thumb, newPos); 3865 var position = newPos / 100;
3866 try { suppressDisposed(instance.invokeMethodAsync('OnPan', position)); } catch {} 3867 e.preventDefault(); 3868 }; 3869 document.addEventListener('touchmove', ref.scrollbarTouchMoveHandler, { passive: false }); 3870 3871 ref.scrollbarTouchEndHandler = function () { 3872 dragging = false; 3873 }; 3874 document.addEventListener('touchend', ref.scrollbarTouchEndHandler); 3875 3876 // Touch pan and pinch-to-zoom support 3877 var pinchStartDistance = 0; 3878 var pinchActive = false; 3879 var touchPanning = false; 3880 var touchPanStartX = 0; 3881 3882 ref.touchStartHandler = function (e) { 3883 if (e.touches.length === 2) { 3884 // Two-finger: pinch-to-zoom 3885 pinchActive = true; 3886 touchPanning = false; 3887 var dx = e.touches[0].clientX - e.touches[1].clientX; 3888 var dy = e.touches[0].clientY - e.touches[1].clientY; 3889 pinchStartDistance = Math.sqrt(dx * dx + dy * dy); 3890 e.preventDefault(); 3891 } else if (e.touches.length === 1 && !e.target.closest('.rz-chart-scrollbar')) { 3892 // Single-finger on chart area: pan 3893 touchPanning = true; 3894 touchPanStartX = e.touches[0].clientX; 3895 } 3896 }; 3897 ref.addEventListener('touchstart', ref.touchStartHandler, { passive: false }); 3898 3899 ref.touchMoveHandler = function (e) { 3900 if (pinchActive && e.touches.length === 2) { 3901 // Pinch-to-zoom 3902 var dx = e.touches[0].clientX - e.touches[1].clientX; 3903 var dy = e.touches[0].clientY - e.touches[1].clientY; 3904 var currentDistance = Math.sqrt(dx * dx + dy * dy); 3905 if (pinchStartDistance <= 0) return; 3906 var midX = (e.touches[0].clientX + e.touches[1].clientX) / 2; 3907 var rect = ref.getBoundingClientRect(); 3908 var x = midX - rect.left; 3909 var ratio = currentDistance / pinchStartDistance; 3910 if (ratio > 1.05) { 3911 try { suppressDisposed(instance.invokeMethodAsync('OnWheel', x, -1)); } catch {} 3912 pinchStartDistance = currentDistance; 3913 } else if (ratio < 0.95) { 3914 try { suppressDisposed(instance.invokeMethodAsync('OnWheel', x, 1)); } catch {} 3915 pinchStartDistance = currentDistance; 3916 } 3917 e.preventDefault(); 3918 } else if (touchPanning && e.touches.length === 1) { 3919 // Single-finger pan 3920 var rect = ref.getBoundingClientRect(); 3921 var chartWidth = rect.width; 3922 if (chartWidth <= 0) return; 3923 var dx = e.touches[0].clientX - touchPanStartX; 3924 var thumb = ref.querySelector('.rz-chart-scrollbar-thumb'); 3925 if (!thumb) return; 3926 var thumbWidth = parseFloat(thumb.style.width) || 50; 3927 var currentPos = getThumbPos(thumb); 3928 // Swipe in reading direction = move view backward, swipe against = move view forward 3929 var deltaPercent = (isChartRTL() ? dx : -dx) / chartWidth * 100; 3930 var newPos = Math.max(0, Math.min(100 - thumbWidth, currentPos + deltaPercent)); 3931 var position = newPos / 100; 3932 try { suppressDisposed(instance.invokeMethodAsync('OnPan', position)); } catch {} 3933 touchPanStartX = e.touches[0].clientX; 3934 e.preventDefault(); 3935 } 3936 }; 3937 ref.addEventListener('touchmove', ref.touchMoveHandler, { passive: false }); 3938 3939 ref.touchEndHandler = function (e) { 3940 if (e.touches.length < 2) { 3941 pinchActive = false; 3942 } 3943 if (e.touches.length === 0) { 3944 touchPanning = false; 3945 } 3946 }; 3947 ref.addEventListener('touchend', ref.touchEndHandler); 3948 3949 // RTL detection 3950 ref._chartRTLObserver = new MutationObserver(function () { 3951 try { suppressDisposed(instance.invokeMethodAsync('SetRTL', document.documentElement.dir === 'rtl')); } catch (e) { } 3952 }); 3953 ref._chartRTLObserver.observe(document.documentElement, { attributes: true, attributeFilter: ['dir'] }); 3954 try { suppressDisposed(instance.invokeMethodAsync('SetRTL', document.documentElement.dir === 'rtl')); } catch (e) { } 3955 3956 this.createResizable(ref, instance); 3957 var self = this; 3958 ref._radzenDispose = function () { self.destroyChart(ref); }; 3959 var rect = ref.getBoundingClientRect(); 3960 return { width: rect.width, height: rect.height }; 3961 }, 3962 createGauge: function (ref, instance) { 3963 this.createResizable(ref, instance); 3964 ref._gaugeRTLObserver = new MutationObserver(function () {
3965 try { suppressDisposed(instance.invokeMethodAsync('SetRTL', document.documentElement.dir === 'rtl')); } catch (e) { } 3966 }); 3967 ref._gaugeRTLObserver.observe(document.documentElement, { attributes: true, attributeFilter: ['dir'] }); 3968 try { suppressDisposed(instance.invokeMethodAsync('SetRTL', document.documentElement.dir === 'rtl')); } catch (e) { } 3969 var rect = ref.getBoundingClientRect(); 3970 return { width: rect.width, height: rect.height }; 3971 }, 3972 innerHTML: function (ref, value) { 3973 if (value != undefined) { 3974 if (ref != null) { 3975 ref.innerHTML = value; 3976 } 3977 } else { 3978 return ref.innerHTML; 3979 } 3980 }, 3981 execCommand: function (ref, name, value) { 3982 if (document.activeElement != ref && ref) { 3983 ref.focus(); 3984 } 3985 document.execCommand(name, false, value); 3986 return this.queryCommands(ref); 3987 }, 3988 formatTableColumnHeader: function (ref, index) { 3989 var format = (ref && ref.tableColumnHeaderFormat) || 'Column {0}'; 3990 return format.replace('{0}', (index + 1).toString()); 3991 }, 3992 createTableHTML: function (ref, options) { 3993 options = options || {}; 3994 var rows = Math.max(parseInt(options.rows || 0, 10) || 0, 1); 3995 var columns = Math.max(parseInt(options.columns || 0, 10) || 0, 1); 3996 var width = options.width || '100%'; 3997 var border = Math.max(parseInt(options.border || 0, 10) || 0, 0); 3998 var headerRow = !!options.headerRow; 3999 var html = '<table style="border-collapse: collapse; width: ' + width + ';" border="' + border + '">'; 4000 4001 if (headerRow) { 4002 html += '<thead><tr>'; 4003 for (var headerIndex = 0; headerIndex < columns; headerIndex++) { 4004 html += '<th>' + this.formatTableColumnHeader(ref, headerIndex) + '</th>'; 4005 } 4006 html += '</tr></thead>'; 4007 } 4008 4009 html += '<tbody>'; 4010 for (var rowIndex = 0; rowIndex < rows; rowIndex++) { 4011 html += '<tr>'; 4012 for (var columnIndex = 0; columnIndex < columns; columnIndex++) { 4013 html += '<td> </td>'; 4014 } 4015 html += '</tr>'; 4016 } 4017 html += '</tbody></table><p></p>'; 4018 4019 return html; 4020 }, 4021 buildTableContext: function (ref, element) { 4022 if (!ref) { 4023 return { ref: ref }; 4024 } 4025 4026 if (!element || !ref.contains(element)) { 4027 return { ref: ref }; 4028 } 4029 4030 var cell = element.closest('td,th'); 4031 var table = element.closest('table'); 4032 4033 if (!cell || !table || !ref.contains(table)) { 4034 return { ref: ref, table: table }; 4035 } 4036 4037 var row = cell.parentElement; 4038 var tbody = table.tBodies && table.tBodies.length ? table.tBodies[0] : null; 4039 var thead = table.tHead; 4040 var rowIndex = -1; 4041 4042 if (tbody && tbody.contains(row)) { 4043 rowIndex = Array.prototype.indexOf.call(tbody.rows, row); 4044 } 4045 4046 return { 4047 ref: ref, 4048 table: table, 4049 cell: cell, 4050 row: row, 4051 tbody: tbody, 4052 thead: thead, 4053 inHeader: !!(thead && thead.contains(cell)), 4054 rowIndex: rowIndex, 4055 columnIndex: Array.prototype.indexOf.call(row.children, cell) 4056 }; 4057 }, 4058 getTableContext: function (ref) { 4059 var selection = getSelection(); 4060 var range = selection && selection.rangeCount > 0 ? selection.getRangeAt(0) : null; 4061 var node = selection && selection.focusNode ? selection.focusNode : range && range.commonAncestorContainer; 4062 4063 if (!node) { 4064 return { ref: ref }; 4065 } 4066 4067 return this.buildTableContext(ref, node.nodeType === 3 ? node.parentElement : node); 4068 }, 4069 getCellMatrix: function (section) { 4070 var matrix = []; 4071 if (!section || !section.rows) { 4072 return matrix; 4073 } 4074 4075 for (var rowIndex = 0; rowIndex < section.rows.length; rowIndex++) { 4076 var row = section.rows[rowIndex]; 4077 if (!matrix[rowIndex]) { 4078 matrix[rowIndex] = []; 4079 } 4080 4081 var columnIndex = 0; 4082 for (var cellIndex = 0; cellIndex < row.cells.length; cellIndex++) { 4083 var cell = row.cells[cellIndex]; 4084 while (matrix[rowIndex][columnIndex]) { 4085 columnIndex++; 4086 } 4087 4088 var colSpan = Math.max(parseInt(cell.getAttribute('colspan') || 1, 10) || 1, 1); 4089 var rowSpan = Math.max(parseInt(cell.getAttribute('rowspan') || 1, 10) || 1, 1); 4090 4091 for (var r = 0; r < rowSpan; r++) { 4092 var targetRow = rowIndex + r; 4093 if (!matrix[targetRow]) { 4094 matrix[targetRow] = []; 4095 } 4096 4097 for (var c = 0; c < colSpan; c++) { 4098 matrix[targetRow][columnIndex + c] = cell; 4099 } 4100 } 4101 4102 columnIndex += colSpan; 4103 } 4104 } 4105 4106 return matrix; 4107 },
4108 getCellPosition: function (section, cell, matrix) { 4109 matrix = matrix || this.getCellMatrix(section); 4110 4111 for (var rowIndex = 0; rowIndex < matrix.length; rowIndex++) { 4112 for (var columnIndex = 0; columnIndex < (matrix[rowIndex] || []).length; columnIndex++) { 4113 if (matrix[rowIndex][columnIndex] === cell) { 4114 return { rowIndex: rowIndex, columnIndex: columnIndex }; 4115 } 4116 } 4117 } 4118 4119 return { rowIndex: -1, columnIndex: -1 }; 4120 }, 4121 clearSelectedTableCells: function (ref) { 4122 if (!ref) { 4123 return; 4124 } 4125 4126 Array.prototype.forEach.call(ref.querySelectorAll('td.rz-html-editor-cell-selected,th.rz-html-editor-cell-selected'), function (cell) { 4127 cell.classList.remove('rz-html-editor-cell-selected'); 4128 }); 4129 }, 4130 getSelectedTableCells: function (ref) { 4131 if (!ref) { 4132 return []; 4133 } 4134 4135 return Array.prototype.filter.call(ref.querySelectorAll('td.rz-html-editor-cell-selected,th.rz-html-editor-cell-selected'), function (cell) { 4136 return ref.contains(cell); 4137 }); 4138 }, 4139 selectTableCellRange: function (ref, startCell, endCell) { 4140 if (!ref || !startCell || !endCell) { 4141 return false; 4142 } 4143 4144 var startSection = startCell.parentElement ? startCell.parentElement.parentElement : null; 4145 var endSection = endCell.parentElement ? endCell.parentElement.parentElement : null; 4146 4147 if (!startSection || startSection !== endSection) { 4148 return false; 4149 } 4150 4151 var matrix = this.getCellMatrix(startSection); 4152 var start = this.getCellPosition(startSection, startCell, matrix); 4153 var end = this.getCellPosition(startSection, endCell, matrix); 4154 4155 if (start.rowIndex < 0 || start.columnIndex < 0 || end.rowIndex < 0 || end.columnIndex < 0) { 4156 return false; 4157 } 4158 4159 var minRow = Math.min(start.rowIndex, end.rowIndex); 4160 var maxRow = Math.max(start.rowIndex, end.rowIndex); 4161 var minColumn = Math.min(start.columnIndex, end.columnIndex); 4162 var maxColumn = Math.max(start.columnIndex, end.columnIndex); 4163 this.clearSelectedTableCells(ref); 4164 4165 for (var rowIndex = minRow; rowIndex <= maxRow; rowIndex++) { 4166 for (var columnIndex = minColumn; columnIndex <= maxColumn; columnIndex++) { 4167 var cell = (matrix[rowIndex] || [])[columnIndex]; 4168 if (cell) { 4169 cell.classList.add('rz-html-editor-cell-selected'); 4170 } 4171 } 4172 } 4173 4174 return true; 4175 }, 4176 getSelectedCellBounds: function (ref, section) { 4177 var selectedCells = this.getSelectedTableCells(ref); 4178 if (!selectedCells.length) { 4179 return null; 4180 } 4181 4182 var matrix = this.getCellMatrix(section); 4183 var minRow = Number.MAX_SAFE_INTEGER; 4184 var maxRow = -1; 4185 var minColumn = Number.MAX_SAFE_INTEGER; 4186 var maxColumn = -1; 4187 4188 selectedCells.forEach(function (selectedCell) { 4189 var position = Radzen.getCellPosition(section, selectedCell, matrix); 4190 var rowIndex = position.rowIndex; 4191 var columnIndex = position.columnIndex; 4192 if (rowIndex < 0 || columnIndex < 0) { 4193 return; 4194 } 4195 4196 var rowSpan = Math.max(parseInt(selectedCell.getAttribute('rowspan') || 1, 10) || 1, 1); 4197 var colSpan = Math.max(parseInt(selectedCell.getAttribute('colspan') || 1, 10) || 1, 1); 4198 4199 minRow = Math.min(minRow, rowIndex); 4200 maxRow = Math.max(maxRow, rowIndex + rowSpan - 1); 4201 minColumn = Math.min(minColumn, columnIndex); 4202 maxColumn = Math.max(maxColumn, columnIndex + colSpan - 1); 4203 }); 4204 4205 if (minRow === Number.MAX_SAFE_INTEGER || minColumn === Number.MAX_SAFE_INTEGER) { 4206 return null; 4207 } 4208 4209 for (var rowIndex = minRow; rowIndex <= maxRow; rowIndex++) { 4210 for (var columnIndex = minColumn; columnIndex <= maxColumn; columnIndex++) { 4211 var candidate = (matrix[rowIndex] || [])[columnIndex]; 4212 if (!candidate || selectedCells.indexOf(candidate) === -1) { 4213 return null; 4214 } 4215 } 4216 } 4217 4218 return { 4219 selectedCells: selectedCells, 4220 matrix: matrix, 4221 minRow: minRow, 4222 maxRow: maxRow, 4223 minColumn: minColumn, 4224 maxColumn: maxColumn 4225 }; 4226 }, 4227 copySelectedTableCells: function (ref) {
4228 var cells = this.getSelectedTableCells(ref); 4229 if (!cells.length) { 4230 return false; 4231 } 4232 4233 var section = cells[0].parentElement ? cells[0].parentElement.parentElement : null; 4234 var bounds = this.getSelectedCellBounds(ref, section); 4235 if (!bounds) { 4236 return false; 4237 } 4238 4239 var copiedMatrix = []; 4240 for (var rowIndex = bounds.minRow; rowIndex <= bounds.maxRow; rowIndex++) { 4241 copiedMatrix.push([]); 4242 for (var columnIndex = bounds.minColumn; columnIndex <= bounds.maxColumn; columnIndex++) { 4243 var cell = (bounds.matrix[rowIndex] || [])[columnIndex]; 4244 copiedMatrix[copiedMatrix.length - 1].push(bounds.selectedCells.indexOf(cell) > -1 && cell ? cell.outerHTML : null); 4245 } 4246 } 4247 4248 ref.copiedCells = { 4249 matrix: copiedMatrix, 4250 rows: copiedMatrix.length, 4251 columns: copiedMatrix.length ? copiedMatrix[0].length : 0 4252 }; 4253 4254 return true; 4255 }, 4256 pasteSelectedTableCells: function (ref, targetCell) { 4257 if (!ref || !ref.copiedCells || !ref.copiedCells.matrix || !targetCell || !targetCell.parentElement) { 4258 return false; 4259 } 4260 4261 var section = targetCell.parentElement.parentElement; 4262 var matrix = this.getCellMatrix(section); 4263 var position = this.getCellPosition(section, targetCell, matrix); 4264 var startRow = position.rowIndex; 4265 var startColumn = position.columnIndex; 4266 4267 if (startRow < 0 || startColumn < 0) { 4268 return false; 4269 } 4270 4271 for (var guardRowOffset = 0; guardRowOffset < ref.copiedCells.rows; guardRowOffset++) { 4272 for (var guardColumnOffset = 0; guardColumnOffset < ref.copiedCells.columns; guardColumnOffset++) { 4273 var guardCell = (matrix[startRow + guardRowOffset] || [])[startColumn + guardColumnOffset]; 4274 if (guardCell) { 4275 var guardCellPosition = this.getCellPosition(section, guardCell, matrix); 4276 var guardRowSpan = Math.max(parseInt(guardCell.getAttribute('rowspan') || 1, 10) || 1, 1); 4277 var guardColSpan = Math.max(parseInt(guardCell.getAttribute('colspan') || 1, 10) || 1, 1); 4278 if ((guardRowSpan > 1 || guardColSpan > 1) && (guardCellPosition.rowIndex !== startRow + guardRowOffset || guardCellPosition.columnIndex !== startColumn + guardColumnOffset)) { 4279 return false; 4280 } 4281 } 4282 } 4283 } 4284 4285 for (var rowOffset = 0; rowOffset < ref.copiedCells.rows; rowOffset++) { 4286 var targetRow = section.rows[startRow + rowOffset]; 4287 if (!targetRow) { 4288 if (section.tagName === 'TBODY') { 4289 targetRow = section.insertRow(); 4290 } else { 4291 return false; 4292 } 4293 } 4294 4295 for (var columnOffset = 0; columnOffset < ref.copiedCells.columns; columnOffset++) { 4296 var target = (this.getCellMatrix(section)[startRow + rowOffset] || [])[startColumn + columnOffset]; 4297 if (!target) { 4298 target = document.createElement(targetCell.tagName.toLowerCase()); 4299 target.innerHTML = ' '; 4300 targetRow.appendChild(target); 4301 } 4302 4303 var html = ref.copiedCells.matrix[rowOffset][columnOffset]; 4304 if (html) { 4305 var template = document.createElement('template'); 4306 template.innerHTML = html.trim(); 4307 var sourceCell = template.content.firstElementChild; 4308 if (sourceCell) { 4309 target.innerHTML = sourceCell.innerHTML; 4310 } 4311 } 4312 } 4313 } 4314 4315 return true; 4316 }, 4317 createCommandResult: function (ref, success, message) { 4318 var result = this.queryCommands(ref); 4319 result.success = success; 4320 result.message = message || null; 4321 return result; 4322 }, 4323 getContextTableSelection: function (ref) { 4324 var context = ref && ref.contextMenuTarget ? this.getTableContextFromTarget(ref, ref.contextMenuTarget) : this.getTableContext(ref); 4325 if (!context || !context.table) { 4326 return this.getTableSelection(ref); 4327 } 4328 4329 return this.getTableSelectionFromContext(ref, context); 4330 }, 4331 getTableContextFromTarget: function (ref, target) { 4332 if (!target) { 4333 return this.getTableContext(ref); 4334 } 4335 4336 return this.buildTableContext(ref, target.nodeType === 3 ? target.parentElement : target); 4337 }, 4338 getTableSelectionFromContext: function (ref, context) { 4339 var table = context.table; 4340 4341 if (!table) { 4342 return this.getTableSelection(ref); 4343 } 4344 4345 var cell = context.cell;
4346 var section = context.inHeader && table.tHead ? table.tHead : (context.row ? context.row.parentElement : (table.tBodies[0] || table)); 4347 var matrix = this.getCellMatrix(section); 4348 var position = cell ? this.getCellPosition(section, cell, matrix) : { rowIndex: -1, columnIndex: context.columnIndex }; 4349 var rowIndex = position.rowIndex; 4350 var columnIndex = position.columnIndex; 4351 var colSpan = cell ? Math.max(parseInt(cell.getAttribute('colspan') || 1, 10) || 1, 1) : 1; 4352 var rowSpan = cell ? Math.max(parseInt(cell.getAttribute('rowspan') || 1, 10) || 1, 1) : 1; 4353 var rowCells = matrix[rowIndex] || []; 4354 var rightCell = rowCells[columnIndex + colSpan]; 4355 var belowRow = matrix[rowIndex + rowSpan] || []; 4356 var canMergeDown = true; 4357 4358 for (var i = 0; i < colSpan; i++) { 4359 if (!belowRow[columnIndex + i]) { 4360 canMergeDown = false; 4361 break; 4362 } 4363 } 4364 4365 var bodyRows = table.tBodies && table.tBodies.length ? table.tBodies[0].rows.length : 0; 4366 var firstRow = table.rows && table.rows.length ? table.rows[0] : null; 4367 var border = parseInt(table.getAttribute('border') || 0, 10) || 0; 4368 var columnWidth = cell && cell.style ? cell.style.width || null : null;
4369 var cellBackground = cell && cell.style ? cell.style.backgroundColor || null : null; 4370 var cellPadding = cell && cell.style ? cell.style.padding || null : null; 4371 var cellTextAlign = cell && cell.style ? cell.style.textAlign || null : null; 4372 var cellVerticalAlign = cell && cell.style ? cell.style.verticalAlign || null : null; 4373 var cellBorder = cell && cell.style ? cell.style.border || null : null; 4374 var columnWidthPx = columnWidth ? parseInt(columnWidth, 10) || null : null; 4375 var cellPaddingPx = cellPadding ? parseInt(cellPadding, 10) || null : null; 4376 var borderTop = !!(cell && cell.style && cell.style.borderTop !== 'none' && cell.style.borderTop !== ''); 4377 var borderRight = !!(cell && cell.style && cell.style.borderRight !== 'none' && cell.style.borderRight !== ''); 4378 var borderBottom = !!(cell && cell.style && cell.style.borderBottom !== 'none' && cell.style.borderBottom !== ''); 4379 var borderLeft = !!(cell && cell.style && cell.style.borderLeft !== 'none' && cell.style.borderLeft !== ''); 4380 var borderStyle = cell && cell.style ? (cell.style.borderStyle || (cellBorder ? cellBorder.split(' ')[1] : null)) : null; 4381 var borderWidthPx = cell && cell.style && cell.style.borderWidth ? parseInt(cell.style.borderWidth, 10) || null : (cellBorder ? parseInt(cellBorder, 10) || null : null); 4382 var borderColor = cell && cell.style ? (cell.style.borderColor || null) : null; 4383 4384 return { 4385 inTable: true, 4386 inHeader: !!context.inHeader, 4387 rowIndex: context.rowIndex, 4388 columnIndex: columnIndex, 4389 rows: bodyRows, 4390 columns: firstRow ? firstRow.children.length : 0, 4391 width: table.style.width || table.getAttribute('width') || '100%', 4392 border: border, 4393 headerRow: !!(table.tHead && table.tHead.rows.length), 4394 colSpan: colSpan, 4395 rowSpan: rowSpan, 4396 canMergeRight: !!rightCell && rightCell !== cell, 4397 canMergeDown: canMergeDown, 4398 canSplit: colSpan > 1 || rowSpan > 1, 4399 columnWidth: columnWidth,
4400 cellBackground: cellBackground, 4401 cellPadding: cellPadding, 4402 cellTextAlign: cellTextAlign, 4403 cellVerticalAlign: cellVerticalAlign, 4404 cellBorder: cellBorder, 4405 columnWidthPx: columnWidthPx, 4406 cellPaddingPx: cellPaddingPx, 4407 borderStyle: borderStyle, 4408 borderWidthPx: borderWidthPx, 4409 borderColor: borderColor, 4410 borderTop: borderTop, 4411 borderRight: borderRight, 4412 borderBottom: borderBottom, 4413 borderLeft: borderLeft 4414 }; 4415 }, 4416 getTableSelection: function (ref) { 4417 var context = this.getTableContext(ref); 4418 if (!context.table) { 4419 return { 4420 inTable: false, 4421 inHeader: false, 4422 rowIndex: -1, 4423 columnIndex: -1, 4424 rows: 0, 4425 columns: 0, 4426 width: null, 4427 border: 0, 4428 headerRow: false, 4429 colSpan: 1, 4430 rowSpan: 1, 4431 canMergeRight: false, 4432 canMergeDown: false, 4433 canSplit: false, 4434 columnWidth: null, 4435 columnWidthPx: null, 4436 cellBackground: null, 4437 cellPadding: null, 4438 cellPaddingPx: null, 4439 cellTextAlign: null, 4440 cellVerticalAlign: null, 4441 cellBorder: null, 4442 borderStyle: null, 4443 borderWidthPx: null, 4444 borderColor: null, 4445 borderTop: false, 4446 borderRight: false, 4447 borderBottom: false, 4448 borderLeft: false 4449 }; 4450 } 4451 4452 return this.getTableSelectionFromContext(ref, context); 4453 }, 4454 ensureTableBody: function (table) { 4455 if (!table.tBodies.length) { 4456 table.appendChild(document.createElement('tbody')); 4457 } 4458 return table.tBodies[0]; 4459 }, 4460 getTableColumnCount: function (table) { 4461 var firstRow = table.rows.length ? table.rows[0] : null; 4462 return firstRow ? firstRow.children.length : 0; 4463 }, 4464 createTableRow: function (ref, columns, header) { 4465 var tr = document.createElement('tr'); 4466 for (var i = 0; i < columns; i++) { 4467 var element = document.createElement(header ? 'th' : 'td'); 4468 element.innerHTML = header ? this.formatTableColumnHeader(ref, i) : ' '; 4469 tr.appendChild(element); 4470 } 4471 return tr; 4472 }, 4473 updateTable: function (context, value) { 4474 value = value || {}; 4475 var table = context.table; 4476 var cell = context.cell; 4477 var row = context.row; 4478 var columns = Math.max(parseInt(value.columns || 0, 10) || 0, 1); 4479 var rows = Math.max(parseInt(value.rows || 0, 10) || 0, 1); 4480 var border = Math.max(parseInt(value.border || 0, 10) || 0, 0); 4481 var columnWidth = value.columnWidthPx ? value.columnWidthPx + 'px' : (value.columnWidth || ''); 4482 var cellPadding = value.cellPaddingPx != null ? value.cellPaddingPx + 'px' : (value.cellPadding || ''); 4483 var borderStyle = value.borderStyle || 'solid'; 4484 var borderWidth = value.borderWidthPx != null ? value.borderWidthPx + 'px' : '1px'; 4485 var borderColor = value.borderColor || 'currentColor'; 4486 4487 table.style.width = value.width || '100%'; 4488 if (!table.style.borderCollapse) { 4489 table.style.borderCollapse = 'collapse'; 4490 } 4491 table.setAttribute('border', border.toString()); 4492 4493 this.updateTableHeader(context.ref, table, columns, !!value.headerRow); 4494 this.updateTableBody(context.ref, table, rows, columns); 4495 4496 if (cell) { 4497 this.updateTableCellStyles(row, cell, context, { 4498 columnWidth: columnWidth,
4499 cellBackground: value.cellBackground || '', 4500 cellPadding: cellPadding, 4501 cellTextAlign: value.cellTextAlign || '', 4502 cellVerticalAlign: value.cellVerticalAlign || '', 4503 cellBorder: value.cellBorder || '', 4504 borderValue: borderWidth + ' ' + borderStyle + ' ' + borderColor, 4505 borderTop: value.borderTop, 4506 borderRight: value.borderRight, 4507 borderBottom: value.borderBottom, 4508 borderLeft: value.borderLeft 4509 }); 4510 } 4511 }, 4512 updateTableHeader: function (ref, table, columns, headerRow) { 4513 if (headerRow) { 4514 var thead = table.tHead || table.createTHead(); 4515 var header = thead.rows.length ? thead.rows[0] : thead.insertRow(); 4516 while (header.children.length < columns) { 4517 var th = document.createElement('th'); 4518 th.innerHTML = this.formatTableColumnHeader(ref, header.children.length); 4519 header.appendChild(th); 4520 } 4521 while (header.children.length > columns) { 4522 header.removeChild(header.lastElementChild); 4523 } 4524 for (var h = 0; h < header.children.length; h++) { 4525 if (!header.children[h].innerHTML || header.children[h].innerHTML === ' ') { 4526 header.children[h].innerHTML = this.formatTableColumnHeader(ref, h); 4527 } 4528 } 4529 } else if (table.tHead) { 4530 table.deleteTHead(); 4531 } 4532 }, 4533 updateTableBody: function (ref, table, rows, columns) { 4534 var tbody = this.ensureTableBody(table); 4535 while (tbody.rows.length < rows) { 4536 tbody.appendChild(this.createTableRow(ref, columns, false)); 4537 } 4538 while (tbody.rows.length > rows) { 4539 tbody.removeChild(tbody.lastElementChild); 4540 } 4541 for (var r = 0; r < tbody.rows.length; r++) { 4542 var bodyRow = tbody.rows[r]; 4543 while (bodyRow.children.length < columns) { 4544 var td = document.createElement('td'); 4545 td.innerHTML = ' '; 4546 bodyRow.appendChild(td); 4547 } 4548 while (bodyRow.children.length > columns) { 4549 bodyRow.removeChild(bodyRow.lastElementChild); 4550 } 4551 } 4552 }, 4553 updateTableCellStyles: function (row, cell, context, options) { 4554 var sectionMatrix = row && row.parentElement ? this.getCellMatrix(row.parentElement) : []; 4555 var resizePosition = row && row.parentElement ? this.getCellPosition(row.parentElement, cell, sectionMatrix) : { columnIndex: context.columnIndex }; 4556 var resizeColumnIndex = resizePosition.columnIndex; 4557 4558 for (var rowIndex = 0; rowIndex < sectionMatrix.length; rowIndex++) { 4559 var syncCell = sectionMatrix[rowIndex][resizeColumnIndex]; 4560 if (syncCell && options.columnWidth) { 4561 syncCell.style.width = options.columnWidth; 4562 } else if (syncCell) { 4563 syncCell.style.removeProperty('width'); 4564 } 4565 } 4566
4567 options.cellBackground ? cell.style.backgroundColor = options.cellBackground : cell.style.removeProperty('background-color'); 4568 options.cellPadding ? cell.style.padding = options.cellPadding : cell.style.removeProperty('padding'); 4569 options.cellTextAlign ? cell.style.textAlign = options.cellTextAlign : cell.style.removeProperty('text-align'); 4570 options.cellVerticalAlign ? cell.style.verticalAlign = options.cellVerticalAlign : cell.style.removeProperty('vertical-align'); 4571 4572 if (options.cellBorder) { 4573 cell.style.border = options.cellBorder; 4574 } else { 4575 cell.style.borderTop = options.borderTop ? options.borderValue : 'none'; 4576 cell.style.borderRight = options.borderRight ? options.borderValue : 'none'; 4577 cell.style.borderBottom = options.borderBottom ? options.borderValue : 'none'; 4578 cell.style.borderLeft = options.borderLeft ? options.borderValue : 'none'; 4579 } 4580 }, 4581 addTableRow: function (context, command) { 4582 var row = context.row; 4583 var newRow = this.createTableRow(context.ref, this.getTableColumnCount(context.table), context.inHeader); 4584 row.parentNode.insertBefore(newRow, command === 'addRowBefore' ? row : row.nextSibling); 4585 }, 4586 deleteTableRow: function (context) { 4587 var table = context.table; 4588 if (context.row) { 4589 context.row.remove(); 4590 } 4591 if (table.tHead && !table.tHead.rows.length) { 4592 table.deleteTHead(); 4593 } 4594 if (table.tBodies.length && !table.tBodies[0].rows.length) { 4595 table.tBodies[0].appendChild(this.createTableRow(context.ref, this.getTableColumnCount(table) || 1, false)); 4596 } 4597 }, 4598 addTableColumn: function (context, command) { 4599 var self = this; 4600 var ref = context.ref; 4601 var table = context.table; 4602 var columnIndex = Math.max(context.columnIndex, 0); 4603 var insertIndex = command === 'addColumnBefore' ? columnIndex : columnIndex + 1; 4604 Array.prototype.forEach.call(table.rows, function (tableRow) { 4605 var header = table.tHead && table.tHead.contains(tableRow); 4606 var column = document.createElement(header ? 'th' : 'td'); 4607 column.innerHTML = header ? self.formatTableColumnHeader(ref, insertIndex) : ' '; 4608 tableRow.insertBefore(column, tableRow.children[insertIndex] || null); 4609 }); 4610 }, 4611 deleteTableColumn: function (context) { 4612 var index = context.columnIndex; 4613 if (index >= 0) { 4614 Array.prototype.forEach.call(context.table.rows, function (tableRow) { 4615 if (tableRow.children.length > 1 && tableRow.children[index]) { 4616 tableRow.removeChild(tableRow.children[index]); 4617 } 4618 }); 4619 } 4620 }, 4621 mergeTableCellRight: function (ref, context) { 4622 var row = context.row; 4623 var cell = context.cell; 4624 var sectionRight = row && row.parentElement ? row.parentElement : null; 4625 var boundsRight = this.getSelectedCellBounds(ref, sectionRight); 4626 if (boundsRight && boundsRight.selectedCells.length > 1) { 4627 var anchorCellRight = (boundsRight.matrix[boundsRight.minRow] || [])[boundsRight.minColumn]; 4628 if (!anchorCellRight) { 4629 return false; 4630 } 4631 anchorCellRight.setAttribute('colspan', Math.max(boundsRight.maxColumn - boundsRight.minColumn + 1, 1)); 4632 anchorCellRight.setAttribute('rowspan', Math.max(boundsRight.maxRow - boundsRight.minRow + 1, 1)); 4633 for (var mergeRow = boundsRight.minRow; mergeRow <= boundsRight.maxRow; mergeRow++) { 4634 for (var mergeCol = boundsRight.minColumn; mergeCol <= boundsRight.maxColumn; mergeCol++) { 4635 var mergedCell = (boundsRight.matrix[mergeRow] || [])[mergeCol]; 4636 if (mergedCell && mergedCell !== anchorCellRight && mergedCell.parentElement) { 4637 mergedCell.remove(); 4638 } 4639 } 4640 } 4641 return true; 4642 } 4643 if (cell && row && row.parentElement) { 4644 var rightMatrix = this.getCellMatrix(row.parentElement); 4645 var rightPosition = this.getCellPosition(row.parentElement, cell, rightMatrix); 4646 var currentRightSpan = Math.max(parseInt(cell.getAttribute('colspan') || 1, 10) || 1, 1); 4647 var nextCell = (rightMatrix[rightPosition.rowIndex] || [])[rightPosition.columnIndex + currentRightSpan]; 4648 if (!nextCell || nextCell === cell) { 4649 return true; 4650 } 4651 cell.setAttribute('colspan', currentRightSpan + Math.max(parseInt(nextCell.getAttribute('colspan') || 1, 10) || 1, 1)); 4652 if (!cell.innerHTML || cell.innerHTML === ' ') { 4653 cell.innerHTML = nextCell.innerHTML; 4654 } else if (nextCell.innerHTML && nextCell.innerHTML !== ' ') { 4655 cell.innerHTML += ' ' + nextCell.innerHTML; 4656 } 4657 nextCell.remove(); 4658 } 4659 return true; 4660 }, 4661 mergeTableCellDown: function (context) { 4662 var cell = context.cell; 4663 var row = context.row; 4664 if (cell && row && row.parentElement) { 4665 var downMatrix = this.getCellMatrix(row.parentElement); 4666 var downPosition = this.getCellPosition(row.parentElement, cell, downMatrix); 4667 var currentRowSpan = Math.max(parseInt(cell.getAttribute('rowspan') || 1, 10) || 1, 1); 4668 var targetCell = (downMatrix[downPosition.rowIndex + currentRowSpan] || [])[downPosition.columnIndex]; 4669 if (targetCell) { 4670 cell.setAttribute('rowspan', currentRowSpan + Math.max(parseInt(targetCell.getAttribute('rowspan') || 1, 10) || 1, 1)); 4671 if (!cell.innerHTML || cell.innerHTML === ' ') { 4672 cell.innerHTML = targetCell.innerHTML; 4673 } else if (targetCell.innerHTML && targetCell.innerHTML !== ' ') { 4674 cell.innerHTML += '<br>' + targetCell.innerHTML; 4675 } 4676 targetCell.remove(); 4677 } 4678 } 4679 }, 4680 splitTableCell: function (context) { 4681 var cell = context.cell; 4682 var row = context.row; 4683 if (!cell) { 4684 return; 4685 } 4686 var splitColSpan = Math.max(parseInt(cell.getAttribute('colspan') || 1, 10) || 1, 1);
4687 var splitRowSpan = Math.max(parseInt(cell.getAttribute('rowspan') || 1, 10) || 1, 1); 4688 var splitPosition = row && row.parentElement ? this.getCellPosition(row.parentElement, cell) : { rowIndex: row ? row.sectionRowIndex : 0, columnIndex: context.columnIndex }; 4689 if (splitColSpan > 1) { 4690 cell.removeAttribute('colspan'); 4691 for (var c = 1; c < splitColSpan; c++) { 4692 var splitCell = document.createElement(cell.tagName.toLowerCase()); 4693 splitCell.innerHTML = ' '; 4694 cell.parentElement.insertBefore(splitCell, cell.parentElement.cells[(Array.prototype.indexOf.call(cell.parentElement.cells, cell) + c)] || null); 4695 } 4696 } 4697 if (splitRowSpan > 1 && row && row.parentElement) { 4698 cell.removeAttribute('rowspan'); 4699 for (var sr = 1; sr < splitRowSpan; sr++) { 4700 var splitRow = row.parentElement.rows[row.sectionRowIndex + sr]; 4701 if (splitRow) { 4702 var splitMatrix = this.getCellMatrix(row.parentElement); 4703 var splitDownCell = document.createElement(cell.tagName.toLowerCase()); 4704 splitDownCell.innerHTML = ' '; 4705 var splitReference = null; 4706 for (var rc = splitPosition.columnIndex; rc < (splitMatrix[splitPosition.rowIndex + sr] || []).length; rc++) { 4707 if (splitMatrix[splitPosition.rowIndex + sr][rc] && splitMatrix[splitPosition.rowIndex + sr][rc] !== cell) { 4708 splitReference = splitMatrix[splitPosition.rowIndex + sr][rc]; 4709 break; 4710 } 4711 } 4712 splitRow.insertBefore(splitDownCell, splitReference); 4713 } 4714 } 4715 } 4716 }, 4717 execTableCommand: function (ref, name, value) { 4718 if (document.activeElement != ref && ref) { 4719 ref.focus(); 4720 } 4721 4722 this.captureTableColumnHeaderFormat(ref, value); 4723 4724 try { 4725 if (name === 'insertTable') { 4726 return this.insertTable(ref, value); 4727 } 4728 4729 var context = (ref && ref.contextMenuTarget) 4730 ? this.getTableContextFromTarget(ref, ref.contextMenuTarget) 4731 : this.getTableContext(ref); 4732 4733 if (!context.table) { 4734 return this.createCommandResult(ref, false, 'table.action.requiresTable'); 4735 } 4736 4737 switch (name) { 4738 case 'copyCells': return this.copyTableCells(ref); 4739 case 'pasteCells': return this.pasteTableCells(ref, context); 4740 case 'updateTable': this.updateTable(context, value); break; 4741 case 'addRowBefore': 4742 case 'addRowAfter': this.addTableRow(context, name); break; 4743 case 'deleteRow': this.deleteTableRow(context); break; 4744 case 'addColumnBefore': 4745 case 'addColumnAfter': this.addTableColumn(context, name); break; 4746 case 'deleteColumn': this.deleteTableColumn(context); break; 4747 case 'mergeCellRight': 4748 if (!this.mergeTableCellRight(ref, context)) { 4749 return this.createCommandResult(ref, false, 'table.merge.invalidSelection'); 4750 } 4751 break; 4752 case 'mergeCellDown': this.mergeTableCellDown(context); break; 4753 case 'splitCell': this.splitTableCell(context); break; 4754 case 'deleteTable': this.deleteTable(context); break; 4755 } 4756 4757 return this.createCommandResult(ref, true); 4758 } finally { 4759 if (ref) { 4760 ref.contextMenuTarget = null; 4761 } 4762 } 4763 }, 4764 insertTable: function (ref, value) { 4765 this.captureTableColumnHeaderFormat(ref, value); 4766 document.execCommand('insertHTML', false, this.createTableHTML(ref, value)); 4767 return this.createCommandResult(ref, true); 4768 }, 4769 captureTableColumnHeaderFormat: function (ref, value) { 4770 if (ref && value && typeof value.defaultColumnHeader === 'string' && value.defaultColumnHeader) { 4771 ref.tableColumnHeaderFormat = value.defaultColumnHeader; 4772 } 4773 }, 4774 copyTableCells: function (ref) { 4775 return this.copySelectedTableCells(ref) 4776 ? this.createCommandResult(ref, true) 4777 : this.createCommandResult(ref, false, 'table.copy.invalidSelection'); 4778 }, 4779 pasteTableCells: function (ref, context) { 4780 return this.pasteSelectedTableCells(ref, context.cell) 4781 ? this.createCommandResult(ref, true) 4782 : this.createCommandResult(ref, false, 'table.paste.blocked'); 4783 }, 4784 deleteTable: function (context) { 4785 context.table.remove(); 4786 }, 4787 queryCommands: function (ref) { 4788 return { 4789 html: ref != null ? ref.innerHTML : null, 4790 fontName: document.queryCommandValue('fontName'), 4791 fontSize: document.queryCommandValue('fontSize'), 4792 formatBlock: document.queryCommandValue('formatBlock'), 4793 bold: document.queryCommandState('bold'),
4794 underline: document.queryCommandState('underline'), 4795 justifyRight: document.queryCommandState('justifyRight'), 4796 justifyLeft: document.queryCommandState('justifyLeft'), 4797 justifyCenter: document.queryCommandState('justifyCenter'), 4798 justifyFull: document.queryCommandState('justifyFull'), 4799 italic: document.queryCommandState('italic'), 4800 strikeThrough: document.queryCommandState('strikeThrough'), 4801 superscript: document.queryCommandState('superscript'), 4802 subscript: document.queryCommandState('subscript'), 4803 unlink: document.queryCommandEnabled('unlink'), 4804 undo: document.queryCommandEnabled('undo'), 4805 redo: document.queryCommandEnabled('redo') 4806 }; 4807 }, 4808 mediaQueries: {}, 4809 mediaQuery: function(query, instance) { 4810 if (instance) { 4811 function callback(event) { 4812 try { suppressDisposed(instance.invokeMethodAsync('OnChange', event.matches)); } catch { } 4813 }; 4814 var query = matchMedia(query); 4815 this.mediaQueries[instance._id] = function() { 4816 query.removeListener(callback); 4817 } 4818 query.addListener(callback); 4819 return query.matches; 4820 } else { 4821 instance = query; 4822 if (this.mediaQueries[instance._id]) { 4823 this.mediaQueries[instance._id](); 4824 delete this.mediaQueries[instance._id]; 4825 } 4826 } 4827 }, 4828 createEditor: function (ref, uploadUrl, paste, instance, shortcuts) { 4829 ref.inputListener = function () { 4830 try { suppressDisposed(instance.invokeMethodAsync('OnChange', ref.innerHTML)); } catch { } 4831 }; 4832 ref.keydownListener = function (e) { 4833 if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === 'c') { 4834 var currentCell = e.target && e.target.closest ? e.target.closest('td,th') : null; 4835 if (currentCell && ref.contains(currentCell)) { 4836 if (!currentCell.classList.contains('rz-html-editor-cell-selected')) { 4837 Radzen.clearSelectedTableCells(ref); 4838 currentCell.classList.add('rz-html-editor-cell-selected'); 4839 } 4840 e.preventDefault(); 4841 Radzen.copySelectedTableCells(ref); 4842 return; 4843 } 4844 } 4845 4846 if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === 'v') { 4847 var pasteCell = e.target && e.target.closest ? e.target.closest('td,th') : null; 4848 if (pasteCell && ref.contains(pasteCell) && ref.copiedCells && ref.copiedCells.matrix) { 4849 e.preventDefault(); 4850 Radzen.pasteSelectedTableCells(ref, pasteCell); 4851 try { instance.invokeMethodAsync('OnChange', ref.innerHTML); } catch { } 4852 return; 4853 } 4854 } 4855 4856 if (e.key === 'Tab') { 4857 var activeCell = e.target && e.target.closest ? e.target.closest('td,th') : null; 4858 if (activeCell && ref.contains(activeCell)) { 4859 e.preventDefault(); 4860 var activeRow = activeCell.parentElement; 4861 var section = activeRow ? activeRow.parentElement : null; 4862 var matrix = Radzen.getCellMatrix(section); 4863 var activePosition = Radzen.getCellPosition(section, activeCell, matrix); 4864 var rowIndex = activePosition.rowIndex; 4865 var columnIndex = activePosition.columnIndex; 4866 var colSpan = Math.max(parseInt(activeCell.getAttribute('colspan') || 1, 10) || 1, 1); 4867 var rowSpan = Math.max(parseInt(activeCell.getAttribute('rowspan') || 1, 10) || 1, 1); 4868 var nextColumnIndex = e.shiftKey ? columnIndex - 1 : columnIndex + colSpan; 4869 var nextRowIndex = rowIndex; 4870 4871 if (nextColumnIndex < 0) { 4872 nextRowIndex = Math.max(rowIndex - 1, 0); 4873 nextColumnIndex = Math.max((matrix[nextRowIndex] || []).length - 1, 0); 4874 } 4875 4876 while (matrix[nextRowIndex] && !matrix[nextRowIndex][nextColumnIndex] && nextColumnIndex >= 0) { 4877 nextColumnIndex += e.shiftKey ? -1 : 1; 4878 } 4879 4880 if ((!matrix[nextRowIndex] || !matrix[nextRowIndex][nextColumnIndex]) && !e.shiftKey) { 4881 nextRowIndex = rowIndex + rowSpan; 4882 nextColumnIndex = 0; 4883 } 4884 4885 var nextCell = (matrix[nextRowIndex] || [])[nextColumnIndex]; 4886 if (!nextCell && !e.shiftKey && section && activeRow && activeRow.parentElement && activeRow.parentElement.tagName === 'TBODY') { 4887 var table = activeCell.closest('table'); 4888 if (table) { 4889 Radzen.execTableCommand(ref, 'addRowAfter'); 4890 matrix = Radzen.getCellMatrix(section); 4891 nextRowIndex = Math.min(rowIndex + rowSpan, matrix.length - 1); 4892 nextCell = (matrix[nextRowIndex] || [])[0]; 4893 } 4894 } 4895 4896 if (nextCell) { 4897 var range = document.createRange(); 4898 range.selectNodeContents(nextCell); 4899 range.collapse(true); 4900 var selection = getSelection(); 4901 selection.removeAllRanges(); 4902 selection.addRange(range); 4903 ref.focus(); 4904 } 4905 return; 4906 } 4907 } 4908 4909 var key = ''; 4910 if (e.ctrlKey || e.metaKey) { 4911 key += 'Ctrl+'; 4912 } 4913 if (e.altKey) { 4914 key += 'Alt+'; 4915 } 4916 if (e.shiftKey) { 4917 key += 'Shift+'; 4918 } 4919 key += e.code.replace('Key', '').replace('Digit', '').replace('Numpad', ''); 4920 4921 if (shortcuts.includes(key)) { 4922 e.preventDefault(); 4923 try { suppressDisposed(instance.invokeMethodAsync('ExecuteShortcutAsync', key)); } catch { } 4924 } 4925 }; 4926 4927 ref.clickListener = function (e) { 4928 if (e.target) { 4929 if (e.target.matches('a,button')) { 4930 e.preventDefault(); 4931 } 4932 4933 for (var img of ref.querySelectorAll('img.rz-state-selected')) { 4934 img.classList.remove('rz-state-selected'); 4935 } 4936 4937 if (e.target.matches('img')) { 4938 e.target.classList.add('rz-state-selected'); 4939 var range = document.createRange(); 4940 range.selectNode(e.target); 4941 getSelection().removeAllRanges(); 4942 getSelection().addRange(range); 4943 } else { 4944 var clickedCell = e.target.closest && e.target.closest('td,th'); 4945 if (clickedCell && ref.contains(clickedCell)) { 4946 if (e.shiftKey && ref.lastSelectedTableCell) { 4947 Radzen.selectTableCellRange(ref, ref.lastSelectedTableCell, clickedCell); 4948 } else if (e.ctrlKey || e.metaKey) { 4949 clickedCell.classList.toggle('rz-html-editor-cell-selected'); 4950 } else { 4951 Radzen.clearSelectedTableCells(ref); 4952 clickedCell.classList.add('rz-html-editor-cell-selected'); 4953 } 4954 ref.lastSelectedTableCell = clickedCell; 4955 } else { 4956 Radzen.clearSelectedTableCells(ref); 4957 ref.lastSelectedTableCell = null; 4958 } 4959 } 4960 } 4961 } 4962 4963 ref.contextMenuListener = function (e) { 4964 var cell = e.target && e.target.closest ? e.target.closest('td,th') : null; 4965 if (cell && ref.contains(cell)) { 4966 if (!cell.classList.contains('rz-html-editor-cell-selected')) { 4967 Radzen.clearSelectedTableCells(ref); 4968 cell.classList.add('rz-html-editor-cell-selected'); 4969 } 4970 ref.lastSelectedTableCell = cell; 4971 ref.contextMenuTarget = cell; 4972 e.preventDefault(); 4973 try { instance.invokeMethodAsync('OnContextMenu', e.clientX, e.clientY); } catch { } 4974 } 4975 } 4976 4977 ref.mousemoveListener = function (e) { 4978 var hoveredCell = e.target && e.target.closest ? e.target.closest('td,th') : null; 4979 if (!hoveredCell || !ref.contains(hoveredCell)) { 4980 ref.style.cursor = ''; 4981 return; 4982 } 4983 4984 var rect = hoveredCell.getBoundingClientRect(); 4985 var nearRightEdge = Math.abs(rect.right - e.clientX) < 6; 4986 if (nearRightEdge) { 4987 ref.style.cursor = 'col-resize'; 4988 ref.resizeTargetCell = hoveredCell; 4989 } else if (!ref.isResizingColumn) { 4990 ref.style.cursor = ''; 4991 ref.resizeTargetCell = null; 4992 } 4993 }; 4994 4995 ref.mousedownResizeListener = function (e) { 4996 if (ref.resizeTargetCell && ref.style.cursor === 'col-resize') { 4997 e.preventDefault(); 4998 ref.isResizingColumn = true; 4999 ref.resizeStartX = e.clientX; 5000 ref.resizeStartWidth = ref.resizeTargetCell.getBoundingClientRect().width; 5001 document.addEventListener('mouseup', ref.mouseupResizeListener); 5002 document.addEventListener('mousemove', ref.documentMouseMoveResizeListener); 5003 } 5004 }; 5005 5006 ref.mouseupResizeListener = function () { 5007 if (ref.isResizingColumn) { 5008 ref.isResizingColumn = false;
5009 ref.style.cursor = ''; 5010 document.removeEventListener('mouseup', ref.mouseupResizeListener); 5011 document.removeEventListener('mousemove', ref.documentMouseMoveResizeListener); 5012 try { instance.invokeMethodAsync('OnChange', ref.innerHTML); } catch { } 5013 } 5014 }; 5015 5016 ref.documentMouseMoveResizeListener = function (e) { 5017 if (ref.isResizingColumn && ref.resizeTargetCell && ref.isConnected) { 5018 var width = Math.max(ref.resizeStartWidth + (e.clientX - ref.resizeStartX), 24); 5019 var resizeSection = ref.resizeTargetCell.parentElement ? ref.resizeTargetCell.parentElement.parentElement : null; 5020 var resizeMatrix = Radzen.getCellMatrix(resizeSection); 5021 var resizePosition = Radzen.getCellPosition(resizeSection, ref.resizeTargetCell, resizeMatrix); 5022 var resizeColumnIndex = resizePosition.columnIndex; 5023 for (var resizeRowIndex = 0; resizeRowIndex < resizeMatrix.length; resizeRowIndex++) { 5024 var resizeCell = resizeMatrix[resizeRowIndex][resizeColumnIndex]; 5025 if (resizeCell) { 5026 resizeCell.style.width = width + 'px'; 5027 } 5028 } 5029 } 5030 }; 5031 5032 ref.selectionChangeListener = function () { 5033 if (document.activeElement == ref) { 5034 try { suppressDisposed(instance.invokeMethodAsync('OnSelectionChange')); } catch { } 5035 } 5036 }; 5037 ref.handleInsert = function (e, transfer, hasDelegate) { 5038 var hasFiles = transfer.files.length > 0; 5039 var hasHtml = transfer.types.indexOf('text/html') > -1; 5040 var hasText = transfer.types.indexOf('text/plain') > -1; 5041 5042 if (hasFiles && !hasHtml && !hasText) { 5043 for (const file of transfer.files) { 5044 ref.handleFileInsert(e, file, hasDelegate); 5045 } 5046 } 5047 else if (hasDelegate) { 5048 ref.handleTextInsert(e, transfer); 5049 } 5050 }; 5051 ref.handleFileInsert = function (event, file, hasDelegate) { 5052 event.preventDefault(); 5053 5054 if (uploadUrl) { 5055 var xhr = new XMLHttpRequest(); 5056 var data = new FormData(); 5057 data.append("file", file); 5058 xhr.onreadystatechange = function (e) { 5059 if (xhr.readyState === XMLHttpRequest.DONE) { 5060 var status = xhr.status; 5061 if (status === 0 || (status >= 200 && status < 400)) { 5062 var result = JSON.parse(xhr.responseText); 5063 var html = '<img src="' + result.url + '">'; 5064 if (hasDelegate) { 5065 try { instance.invokeMethodAsync('OnPaste', html) 5066 .then(function (html) { 5067 document.execCommand("insertHTML", false, html); 5068 }); } catch { } 5069 } else { 5070 document.execCommand("insertHTML", false, '<img src="' + result.url + '">'); 5071 } 5072 try { suppressDisposed(instance.invokeMethodAsync('OnUploadComplete', xhr.responseText)); } catch { } 5073 } else { 5074 try { suppressDisposed(instance.invokeMethodAsync('OnError', xhr.responseText)); } catch { } 5075 } 5076 } 5077 } 5078 try { instance.invokeMethodAsync('GetHeaders').then(function (headers) { 5079 xhr.open('POST', uploadUrl, true); 5080 for (var name in headers) { 5081 xhr.setRequestHeader(name, headers[name]); 5082 } 5083 xhr.send(data); 5084 }); } catch { } 5085 } else { 5086 var reader = new FileReader(); 5087 reader.onload = function (e) { 5088 var html = '<img src="' + e.target.result + '">'; 5089 5090 if (hasDelegate) { 5091 try { instance.invokeMethodAsync('OnPaste', html) 5092 .then(function (html) { 5093 document.execCommand("insertHTML", false, html); 5094 }); } catch { } 5095 } else { 5096 document.execCommand("insertHTML", false, html); 5097 } 5098 }; 5099 reader.readAsDataURL(file); 5100 } 5101 } 5102 ref.handleTextInsert = function (e, transfer) { 5103 e.preventDefault(); 5104 5105 var data = transfer.getData('text/html') || transfer.getData('text/plain'); 5106 5107 const startMarker = "<!--StartFragment-->"; 5108 const endMarker = "<!--EndFragment-->"; 5109 5110 const startIndex = data.indexOf(startMarker); 5111 const endIndex = data.indexOf(endMarker); 5112 5113 // check if the pasted data contains fragment markers 5114 if (startIndex != -1 || endIndex != -1 || endIndex > startIndex) { 5115 // only paste the fragment 5116 data = data.substring(startIndex + startMarker.length, endIndex).trim(); 5117 } 5118
5119 try { instance.invokeMethodAsync('OnPaste', data) 5120 .then(ref.focus()) 5121 .then(function (html) { 5122 document.execCommand("insertHTML", false, html); 5123 }); } catch { } 5124 } 5125 ref.pasteListener = function (e) { 5126 ref.handleInsert(e, e.clipboardData, paste); 5127 }; 5128 ref.dropListener = function (e) { 5129 ref.handleInsert(e, e.dataTransfer, paste); 5130 }; 5131 ref.addEventListener('input', ref.inputListener); 5132 ref.addEventListener('paste', ref.pasteListener); 5133 ref.addEventListener('drop', ref.dropListener); 5134 ref.addEventListener('keydown', ref.keydownListener); 5135 ref.addEventListener('click', ref.clickListener); 5136 ref.addEventListener('contextmenu', ref.contextMenuListener); 5137 ref.addEventListener('mousemove', ref.mousemoveListener); 5138 ref.addEventListener('mousedown', ref.mousedownResizeListener); 5139 document.addEventListener('selectionchange', ref.selectionChangeListener); 5140 document.execCommand('styleWithCSS', false, true); 5141 return { 5142 dispose: function () { 5143 if (ref) { 5144 ref.removeEventListener('input', ref.inputListener); 5145 ref.removeEventListener('paste', ref.pasteListener); 5146 ref.removeEventListener('drop', ref.dropListener); 5147 ref.removeEventListener('keydown', ref.keydownListener); 5148 ref.removeEventListener('click', ref.clickListener); 5149 ref.removeEventListener('contextmenu', ref.contextMenuListener); 5150 ref.removeEventListener('mousemove', ref.mousemoveListener); 5151 ref.removeEventListener('mousedown', ref.mousedownResizeListener); 5152 ref.isResizingColumn = false; 5153 document.removeEventListener('mouseup', ref.mouseupResizeListener); 5154 document.removeEventListener('mousemove', ref.documentMouseMoveResizeListener); 5155 document.removeEventListener('selectionchange', ref.selectionChangeListener); 5156 } 5157 } 5158 }; 5159 }, 5160 saveSelection: function (ref) { 5161 if (!ref) return; 5162 var selection = getSelection(); 5163 if (selection.rangeCount > 0) { 5164 var range = selection.getRangeAt(0); 5165 if (ref.contains(range.commonAncestorContainer)) { 5166 ref.range = range; 5167 } 5168 } 5169 }, 5170 restoreSelection: function (ref) { 5171 if (!ref) return; 5172 var range = ref.range; 5173 if (range) { 5174 delete ref.range; 5175 if(ref) { 5176 ref.focus(); 5177 } 5178 var selection = getSelection(); 5179 selection.removeAllRanges(); 5180 selection.addRange(range); 5181 } 5182 }, 5183 selectionAttributes: function (selector, attributes, container) { 5184 var selection = getSelection(); 5185 var range = selection.rangeCount > 0 && selection.getRangeAt(0); 5186 var parent = range && range.commonAncestorContainer; 5187 var img = container.querySelector('img.rz-state-selected'); 5188 var inside = img && selector == 'img'; 5189 while (parent) { 5190 if (parent == container) { 5191 inside = true; 5192 break; 5193 } 5194 parent = parent.parentNode; 5195 } 5196 if (!inside) { 5197 return {}; 5198 } 5199 var target = selection.focusNode; 5200 var innerHTML; 5201 5202 if (img && selector == 'img') { 5203 target = img; 5204 } else if (target) { 5205 if (target.nodeType == 3) { 5206 target = target.parentElement; 5207 } else { 5208 if (img) { 5209 target = target.childNodes[range.startOffset] 5210 } else { 5211 target = target.childNodes[selection.focusOffset]; 5212 } 5213 if (target) { 5214 innerHTML = target.outerHTML; 5215 } 5216 } 5217 if (target && target.matches && !target.matches(selector)) { 5218 target = target.closest(selector); 5219 } 5220 } 5221 5222 return attributes.reduce(function (result, name) { 5223 if (target) { 5224 result[name] = name == 'innerText' ? target[name] : target.getAttribute(name); 5225 } 5226 return result; 5227 }, { innerText: selection.toString(), innerHTML: innerHTML }); 5228 }, 5229 startDrag: function (ref, instance, handler) { 5230 if (!ref) { 5231 return { left: 0, top: 0, width: 0, height: 0 }; 5232 } 5233 Radzen.endDrag(ref); 5234 ref.mouseMoveHandler = function (e) { 5235 try { suppressDisposed(instance.invokeMethodAsync(handler, { clientX: e.clientX, clientY: e.clientY })); } catch { } 5236 }; 5237 ref.touchMoveHandler = function (e) { 5238 if (e.targetTouches[0] && ref.contains(e.targetTouches[0].target)) { 5239 try { suppressDisposed(instance.invokeMethodAsync(handler, { clientX: e.targetTouches[0].clientX, clientY: e.targetTouches[0].clientY })); } catch { } 5240 } 5241 }; 5242 ref.mouseUpHandler = function (e) { 5243 Radzen.endDrag(ref); 5244 }; 5245 ref.dragStartHandler = function (e) { 5246 e.preventDefault(); 5247 }; 5248 document.addEventListener('mousemove', ref.mouseMoveHandler); 5249 document.addEventListener('mouseup', ref.mouseUpHandler); 5250 document.addEventListener('touchmove', ref.touchMoveHandler, { passive: true, capture: true }) 5251 document.addEventListener('touchend', ref.mouseUpHandler, { passive: true }); 5252 document.addEventListener('dragstart', ref.dragStartHandler); 5253 document.addEventListener('dragend', ref.mouseUpHandler); 5254 return Radzen.clientRect(ref); 5255 }, 5256 submit: function (form) { 5257 form.submit(); 5258 }, 5259 clientRect: function (arg) { 5260 var el = arg instanceof Element || arg instanceof HTMLDocument 5261 ? arg 5262 : document.getElementById(arg); 5263 var rect = el.getBoundingClientRect(); 5264 return { left: rect.left, top: rect.top, width: rect.width, height: rect.height }; 5265 }, 5266 outerHTML: function (arg) { 5267 var el = arg instanceof Element || arg instanceof HTMLDocument 5268 ? arg 5269 : document.getElementById(arg); 5270 return el ? el.outerHTML : ''; 5271 }, 5272 endDrag: function (ref) { 5273 document.removeEventListener('mousemove', ref.mouseMoveHandler); 5274 document.removeEventListener('mouseup', ref.mouseUpHandler); 5275 document.removeEventListener('touchmove', ref.touchMoveHandler) 5276 document.removeEventListener('touchend', ref.mouseUpHandler); 5277 document.removeEventListener('dragstart', ref.dragStartHandler); 5278 document.removeEventListener('dragend', ref.mouseUpHandler); 5279 }, 5280 capturePointer: function (el, pointerId) { 5281 try { 5282 if (el && el.setPointerCapture) { 5283 el.setPointerCapture(pointerId); 5284 } 5285 } catch (e) { /* ignore */ } 5286 }, 5287 releasePointer: function (el, pointerId) { 5288 try { 5289 if (el && el.releasePointerCapture && (!el.hasPointerCapture || el.hasPointerCapture(pointerId))) { 5290 el.releasePointerCapture(pointerId); 5291 } 5292 } catch (e) { /* ignore */ } 5293 }, 5294 startColumnReorder: function(id, gridId, gridRef) { 5295 var grid = document.getElementById(gridId); 5296 var el = document.getElementById(id + '-drag'); 5297 Radzen[id + 'cell'] = el.parentNode.parentNode; 5298 var visual = document.createElement("th"); 5299 visual.className = Radzen[id + 'cell'].className + ' rz-column-draggable'; 5300 visual.style = Radzen[id + 'cell'].style; 5301 visual.style.display = 'none'; 5302 visual.style.position = 'absolute'; 5303 visual.style.height = Radzen[id + 'cell'].offsetHeight + 'px'; 5304 visual.style.width = Radzen[id + 'cell'].offsetWidth + 'px'; 5305 visual.style.zIndex = 2000; 5306 visual.style.pointerEvents = 'none'; 5307 visual.innerHTML = Radzen[id + 'cell'].firstChild.outerHTML; 5308 visual.id = id + 'visual'; 5309 document.body.appendChild(visual); 5310 5311 var resizers = Radzen[id + 'cell'].parentNode.querySelectorAll('.rz-column-resizer'); 5312 for (let i = 0; i < resizers.length; i++) { 5313 resizers[i].style.display = 'none'; 5314 } 5315 5316 Radzen[id + 'lastTouchX'] = null; 5317 Radzen[id + 'lastTouchY'] = null; 5318 5319 Radzen[id + 'end'] = function (e) { 5320 var triggeredByTouch = e && (e.type === 'touchend' || e.type === 'touchcancel'); 5321 var touchX = Radzen[id + 'lastTouchX']; 5322 var touchY = Radzen[id + 'lastTouchY']; 5323 if (triggeredByTouch && e.changedTouches && e.changedTouches[0]) { 5324 touchX = e.changedTouches[0].clientX; 5325 touchY = e.changedTouches[0].clientY; 5326 } 5327 5328 var el = document.getElementById(id + 'visual'); 5329 if (el) { 5330 document.body.removeChild(el); 5331 var resizers = Radzen[id + 'cell'].parentNode.querySelectorAll('.rz-column-resizer'); 5332 for (let i = 0; i < resizers.length; i++) { 5333 resizers[i].style.display = 'block'; 5334 } 5335 } 5336 5337 grid.removeEventListener('mousemove', Radzen[id + 'move']); 5338 grid.removeEventListener('touchmove', Radzen[id + 'touchmove']); 5339 grid.removeEventListener('click', Radzen[id + 'end']); 5340 document.removeEventListener('mouseup', Radzen[id + 'end']); 5341 document.removeEventListener('touchend', Radzen[id + 'end']); 5342 document.removeEventListener('touchcancel', Radzen[id + 'end']); 5343 5344 Radzen[id + 'end'] = null; 5345 Radzen[id + 'move'] = null; 5346 Radzen[id + 'touchmove'] = null; 5347 Radzen[id + 'lastTouchX'] = null; 5348 Radzen[id + 'lastTouchY'] = null; 5349 5350 if (triggeredByTouch && gridRef && touchX != null && touchY != null) { 5351 var target = document.elementFromPoint(touchX, touchY); 5352 if (target && grid.contains(target)) { 5353 var groupHeader = target.closest('.rz-group-header'); 5354 if (groupHeader && grid.contains(groupHeader)) { 5355 try { gridRef.invokeMethodAsync('RadzenGrid.OnColumnDropToGroup'); } catch { } 5356 return; 5357 } 5358 var th = target.closest('th[data-column-index]'); 5359 if (th && grid.contains(th)) { 5360 var columnIndex = parseInt(th.getAttribute('data-column-index'), 10); 5361 if (!isNaN(columnIndex)) { 5362 try { gridRef.invokeMethodAsync('RadzenGrid.OnColumnReorderEnded', columnIndex); } catch { } 5363 } 5364 } 5365 } 5366 } 5367 } 5368 grid.removeEventListener('click', Radzen[id + 'end']); 5369 grid.addEventListener('click', Radzen[id + 'end']); 5370 document.removeEventListener('mouseup', Radzen[id + 'end']); 5371 document.addEventListener('mouseup', Radzen[id + 'end']); 5372 document.removeEventListener('touchend', Radzen[id + 'end']); 5373 document.addEventListener('touchend', Radzen[id + 'end'], { passive: true }); 5374 document.removeEventListener('touchcancel', Radzen[id + 'end']); 5375 document.addEventListener('touchcancel', Radzen[id + 'end'], { passive: true }); 5376 5377 Radzen[id + 'move'] = function (e) { 5378 var el = document.getElementById(id + 'visual'); 5379 if (el) { 5380 el.style.display = 'block'; 5381 5382 if (/Edge/.test(navigator.userAgent)) { 5383 var scrollLeft = document.body.scrollLeft; 5384 var scrollTop = document.body.scrollTop; 5385 } else { 5386 var scrollLeft = document.documentElement.scrollLeft; 5387 var scrollTop = document.documentElement.scrollTop; 5388 } 5389 5390 el.style.top = e.clientY + scrollTop + 10 + 'px'; 5391 el.style.left = e.clientX + scrollLeft + 10 + 'px'; 5392 } 5393 } 5394 grid.removeEventListener('mousemove', Radzen[id + 'move']); 5395 grid.addEventListener('mousemove', Radzen[id + 'move']); 5396 5397 Radzen[id + 'touchmove'] = function (e) { 5398 if (e.touches && e.touches[0]) { 5399 Radzen[id + 'lastTouchX'] = e.touches[0].clientX; 5400 Radzen[id + 'lastTouchY'] = e.touches[0].clientY; 5401 Radzen[id + 'move']({ clientX: e.touches[0].clientX, clientY: e.touches[0].clientY }); 5402 if (e.cancelable) { 5403 e.preventDefault(); 5404 } 5405 } 5406 } 5407 grid.removeEventListener('touchmove', Radzen[id + 'touchmove']); 5408 grid.addEventListener('touchmove', Radzen[id + 'touchmove'], { passive: false }); 5409 }, 5410 stopColumnResize: function (id, grid, columnIndex) { 5411 var el = document.getElementById(id + '-resizer'); 5412 if(!el) return; 5413 var cell = el.parentNode.parentNode; 5414 if (!cell) return; 5415 if (Radzen[el]) { 5416 try { grid.invokeMethodAsync( 5417 'RadzenGrid.OnColumnResized', 5418 columnIndex, 5419 cell.getBoundingClientRect().width 5420 ); } catch { } 5421 el.style.width = null; 5422 document.removeEventListener('mousemove', Radzen[el].mouseMoveHandler); 5423 document.removeEventListener('mouseup', Radzen[el].mouseUpHandler); 5424 document.removeEventListener('touchmove', Radzen[el].touchMoveHandler) 5425 document.removeEventListener('touchend', Radzen[el].mouseUpHandler); 5426 Radzen[el] = null; 5427 } 5428 }, 5429 updateFrozenColumnPositions: function(gridElement) { 5430 if (!gridElement) return; 5431 // Get frozen cell positions from the header row first, then apply to all rows 5432 var headerRow = gridElement.querySelector('thead tr'); 5433 if (!headerRow) return; 5434 var leftHeaderCells = headerRow.querySelectorAll('.rz-frozen-cell-left, .rz-frozen-cell-left-end, .rz-frozen-cell-left-inner'); 5435 var rightHeaderCells = headerRow.querySelectorAll('.rz-frozen-cell-right, .rz-frozen-cell-right-end, .rz-frozen-cell-right-inner'); 5436 // Calculate offsets from header widths 5437 var leftOffsets = []; 5438 var offset = 0; 5439 for (var i = 0; i < leftHeaderCells.length; i++) { 5440 leftOffsets.push(offset); 5441 offset += leftHeaderCells[i].getBoundingClientRect().width; 5442 } 5443 var rightOffsets = []; 5444 offset = 0; 5445 for (var i = rightHeaderCells.length - 1; i >= 0; i--) { 5446 rightOffsets[i] = offset; 5447 offset += rightHeaderCells[i].getBoundingClientRect().width; 5448 } 5449 // Apply offsets to all rows 5450 var rows = gridElement.querySelectorAll('tr'); 5451 for (var r = 0; r < rows.length; r++) { 5452 var row = rows[r]; 5453 var leftCells = row.querySelectorAll('.rz-frozen-cell-left, .rz-frozen-cell-left-end, .rz-frozen-cell-left-inner'); 5454 for (var i = 0; i < leftCells.length && i < leftOffsets.length; i++) { 5455 leftCells[i].style.setProperty('inset-inline-start', leftOffsets[i] + 'px'); 5456 } 5457 var rightCells = row.querySelectorAll('.rz-frozen-cell-right, .rz-frozen-cell-right-end, .rz-frozen-cell-right-inner'); 5458 for (var i = 0; i < rightCells.length && i < rightOffsets.length; i++) { 5459 rightCells[i].style.setProperty('inset-inline-end', rightOffsets[i] + 'px'); 5460 } 5461 } 5462 }, 5463 startColumnResize: function(id, grid, columnIndex, clientX) { 5464 var el = document.getElementById(id + '-resizer'); 5465 var cell = el.parentNode.parentNode; 5466 var col = document.getElementById(id + '-col'); 5467 var dataCol = document.getElementById(id + '-data-col'); 5468 var footerCol = document.getElementById(id + '-footer-col'); 5469 var isFrozen = cell.classList.contains('rz-frozen-cell'); 5470 var gridElement = isFrozen ? cell.closest('.rz-data-grid') : null; 5471 Radzen[el] = { 5472 clientX: clientX, 5473 width: cell.getBoundingClientRect().width, 5474 mouseUpHandler: function (e) { 5475 if (Radzen[el]) { 5476 try { grid.invokeMethodAsync( 5477 'RadzenGrid.OnColumnResized', 5478 columnIndex, 5479 cell.getBoundingClientRect().width 5480 ); } catch { } 5481 el.style.width = null; 5482 document.removeEventListener('mousemove', Radzen[el].mouseMoveHandler); 5483 document.removeEventListener('mouseup', Radzen[el].mouseUpHandler); 5484 document.removeEventListener('touchmove', Radzen[el].touchMoveHandler) 5485 document.removeEventListener('touchend', Radzen[el].mouseUpHandler); 5486 Radzen[el] = null; 5487 } 5488 }, 5489 mouseMoveHandler: function (e) { 5490 if (Radzen[el]) { 5491 var widthFloat = (Radzen[el].width - (Radzen.isRTL(cell) ? -1 : 1) * (Radzen[el].clientX - e.clientX)); 5492 var minWidth = parseFloat(cell.style.minWidth || 0) 5493 var maxWidth = parseFloat(cell.style.maxWidth || 0) 5494 5495 if (widthFloat < minWidth) { 5496 widthFloat = minWidth; 5497 } 5498 5499 if (cell.style.maxWidth &&
5499 widthFloat > maxWidth) { 5500 widthFloat = maxWidth; 5501 } 5502 5503 var width = widthFloat + 'px'; 5504 5505 if (cell) { 5506 cell.style.width = width; 5507 } 5508 if (col) { 5509 col.style.width = width; 5510 } 5511 if (dataCol) { 5512 dataCol.style.width = width; 5513 } 5514 if (footerCol) { 5515 footerCol.style.width = width; 5516 } 5517 5518 if (gridElement) { 5519 Radzen.updateFrozenColumnPositions(gridElement); 5520 } 5521 } 5522 }, 5523 touchMoveHandler: function (e) { 5524 if (e.targetTouches[0]) { 5525 e.preventDefault(); 5526 Radzen[el].mouseMoveHandler(e.targetTouches[0]); 5527 } 5528 } 5529 }; 5530 el.style.width = "100%"; 5531 document.addEventListener('mousemove', Radzen[el].mouseMoveHandler); 5532 document.addEventListener('mouseup', Radzen[el].mouseUpHandler); 5533 document.addEventListener('touchmove', Radzen[el].touchMoveHandler, { passive: false }) 5534 document.addEventListener('touchend', Radzen[el].mouseUpHandler); 5535 }, 5536 startSplitterResize: function(id, 5537 splitter, 5538 paneId, 5539 paneNextId, 5540 orientation, 5541 clientPos, 5542 minValue, 5543 maxValue, 5544 minNextValue, 5545 maxNextValue) { 5546 5547 var el = document.getElementById(id); 5548 var pane = document.getElementById(paneId); 5549 var paneNext = document.getElementById(paneNextId); 5550 var separator = pane ? document.getElementById(pane.id + '-resize') : null; 5551 var paneLength; 5552 var paneNextLength; 5553 var panePerc; 5554 var paneNextPerc; 5555 var isHOrientation=orientation == 'Horizontal'; 5556 5557 var totalLength = 0.0; 5558 Array.from(el.children).forEach(element => { 5559 totalLength += isHOrientation 5560 ? element.getBoundingClientRect().width 5561 : element.getBoundingClientRect().height; 5562 }); 5563 5564 if (pane) { 5565 paneLength = isHOrientation 5566 ? pane.getBoundingClientRect().width 5567 : pane.getBoundingClientRect().height; 5568 5569 panePerc = (paneLength / totalLength * 100) + '%'; 5570 } 5571 5572 if (paneNext) { 5573 paneNextLength = isHOrientation 5574 ? paneNext.getBoundingClientRect().width 5575 : paneNext.getBoundingClientRect().height; 5576 5577 paneNextPerc = (paneNextLength / totalLength * 100) + '%'; 5578 } 5579 5580 function ensurevalue(value) { 5581 if (!value) 5582 return null; 5583 5584 value=value.trim().toLowerCase(); 5585 5586 if (value.endsWith("%")) 5587 return totalLength*parseFloat(value)/100; 5588 5589 if (value.endsWith("px")) 5590 return parseFloat(value); 5591 5592 throw 'Invalid value'; 5593 } 5594 5595 minValue=ensurevalue(minValue); 5596 maxValue=ensurevalue(maxValue); 5597 minNextValue=ensurevalue(minNextValue); 5598 maxNextValue=ensurevalue(maxNextValue); 5599 5600 Radzen[el] = { 5601 clientPos: clientPos, 5602 panePerc: parseFloat(panePerc), 5603 paneNextPerc: isFinite(parseFloat(paneNextPerc)) ? parseFloat(paneNextPerc) : 0, 5604 paneLength: paneLength, 5605 paneNextLength: isFinite(paneNextLength) ? paneNextLength : 0, 5606 mouseUpHandler: function(e) { 5607 if (Radzen[el]) { 5608 try { splitter.invokeMethodAsync( 5609 'RadzenSplitter.OnPaneResized', 5610 parseInt(pane.getAttribute('data-index')), 5611 parseFloat(pane.style.flexBasis), 5612 paneNext ? parseInt(paneNext.getAttribute('data-index')) : null, 5613 paneNext ? parseFloat(paneNext.style.flexBasis) : null 5614 ); } catch { } 5615 5616 document.removeEventListener('pointerup', Radzen[el].mouseUpHandler); 5617 document.removeEventListener('pointercancel', Radzen[el].mouseUpHandler); 5618 document.removeEventListener('pointermove', Radzen[el].mouseMoveHandler); 5619 el.removeEventListener('touchmove', preventDefaultAndStopPropagation); 5620 Radzen[el] = null; 5621 } 5622 }, 5623 mouseMoveHandler: function(e) { 5624 if (Radzen[el]) { 5625 5626 if (e.buttons === 0) { 5627 Radzen[el].mouseUpHandler(e); 5628 return; 5629 } 5630 5631 try { splitter.invokeMethodAsync(
5632 'RadzenSplitter.OnPaneResizing' 5633 ); } catch { } 5634 5635 var spacePerc = Radzen[el].panePerc + Radzen[el].paneNextPerc; 5636 var spaceLength = Radzen[el].paneLength + Radzen[el].paneNextLength; 5637 5638 var length = (Radzen[el].paneLength - 5639 (isHOrientation && Radzen.isRTL(e.target) ? -1 : 1) * (Radzen[el].clientPos - (isHOrientation ? e.clientX : e.clientY))); 5640 5641 if (length > spaceLength) 5642 length = spaceLength; 5643 5644 if (minValue && length < minValue) length = minValue; 5645 if (maxValue && length > maxValue) length = maxValue; 5646 5647 if (paneNext) { 5648 var nextSpace=spaceLength-length; 5649 if (minNextValue && nextSpace < minNextValue) length = spaceLength-minNextValue; 5650 if (maxNextValue && nextSpace > maxNextValue) length = spaceLength-maxNextValue; 5651 } 5652 5653 var perc = length / Radzen[el].paneLength; 5654 if (!isFinite(perc)) { 5655 perc = 1; 5656 Radzen[el].panePerc = 0.1; 5657 Radzen[el].paneLength =isHOrientation 5658 ? pane.getBoundingClientRect().width 5659 : pane.getBoundingClientRect().height; 5660 } 5661 5662 var newPerc = Radzen[el].panePerc * perc; 5663 if (newPerc < 0) newPerc = 0; 5664 if (newPerc > 100) newPerc = 100; 5665 5666 pane.style.flexBasis = newPerc + '%'; 5667 if (paneNext) 5668 paneNext.style.flexBasis = (spacePerc - newPerc) + '%'; 5669 5670 if (separator) { 5671 var valueMin = parseFloat(separator.getAttribute('aria-valuemin')) || 0; 5672 var valueMax = parseFloat(separator.getAttribute('aria-valuemax')); 5673 if (!isFinite(valueMax)) valueMax = 100; 5674 var valueNow = Math.round(newPerc); 5675 if (valueNow < valueMin) valueNow = valueMin; 5676 if (valueNow > valueMax) valueNow = valueMax; 5677 separator.setAttribute('aria-valuenow', valueNow); 5678 } 5679 } 5680 }, 5681 touchMoveHandler: function(e) { 5682 if (e.targetTouches[0]) { 5683 Radzen[el].mouseMoveHandler(e.targetTouches[0]); 5684 } 5685 } 5686 }; 5687 5688 const preventDefaultAndStopPropagation = (ev) => { 5689 ev.preventDefault(); 5690 ev.stopPropagation(); 5691 }; 5692 document.addEventListener('pointerup', Radzen[el].mouseUpHandler); 5693 document.addEventListener('pointercancel', Radzen[el].mouseUpHandler); 5694 document.addEventListener('pointermove', Radzen[el].mouseMoveHandler); 5695 el.addEventListener('touchmove', preventDefaultAndStopPropagation, { passive: false }); 5696 }, 5697 resizeSplitter(id, e) { 5698 var el = document.getElementById(id); 5699 if (el && Radzen[el]) { 5700 Radzen[el].mouseMoveHandler(e); 5701 if (Radzen[el]) { 5702 Radzen[el].mouseUpHandler(e); 5703 } 5704 } 5705 }, 5706 openWaiting: function() { 5707 if (document.documentElement.scrollHeight > document.documentElement.clientHeight) { 5708 document.body.classList.add('no-scroll'); 5709 } 5710 if (Radzen.WaitingIntervalId != null) { 5711 clearInterval(Radzen.WaitingIntervalId); 5712 } 5713 5714 setTimeout(function() { 5715 var timerObj = document.getElementsByClassName('rz-waiting-timer'); 5716 if (timerObj.length == 0) return; 5717 var timerStart = new Date().getTime(); 5718 Radzen.WaitingIntervalId = setInterval(function() { 5719 if (timerObj == null || timerObj[0] == null) { 5720 clearInterval(Radzen.WaitingIntervalId); 5721 } else { 5722 var time = new Date(new Date().getTime() - timerStart); 5723 timerObj[0].innerHTML = Math.floor(time / 1000) + "." + Math.floor((time % 1000) / 100); 5724 } 5725 }, 5726 100); 5727 }, 5728 100); 5729 }, 5730 closeWaiting: function() { 5731 document.body.classList.remove('no-scroll'); 5732 if (Radzen.WaitingIntervalId != null) { 5733 clearInterval(Radzen.WaitingIntervalId); 5734 Radzen.WaitingIntervalId = null; 5735 } 5736 }, 5737 toggleDictation: function (componentRef, language) { 5738 var restarts = 0; 5739 5740 function start() { 5741 const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition; 5742 5743 if (!SpeechRecognition) { 5744 return; 5745 } 5746 5747 radzenRecognition = new SpeechRecognition(); 5748 radzenRecognition.componentRef = componentRef; 5749 radzenRecognition.continuous = true; 5750 5751 if (language) { 5752 radzenRecognition.lang = language; 5753 } 5754 5755 radzenRecognition.onresult = function (event) { 5756 if (event.results.length < 1) { 5757 return; 5758 } 5759 5760 restarts = 0; 5761 5762 let current = event.results[event.results.length - 1][0] 5763 let result = current.transcript; 5764 5765 try { suppressDisposed(componentRef.invokeMethodAsync("OnResult", result)); } catch { } 5766 }; 5767 radzenRecognition.onerror = function (event) { 5768 if (event.error == 'not-allowed' || event.error == 'service-not-allowed' || event.error == 'audio-capture' || event.error == 'language-not-supported') { 5769 this.stopRequested = true; 5770 } 5771 }; 5772 radzenRecognition.onend = function (event) { 5773 if (!this.stopRequested && restarts++ < 10) { 5774 start(); 5775 return; 5776 } 5777 5778 if (this == radzenRecognition) { 5779 radzenRecognition = null; 5780 } 5781 5782 try { suppressDisposed(componentRef.invokeMethodAsync("StopRecording")); } catch { } 5783 }; 5784 radzenRecognition.start(); 5785 } 5786 5787 if (radzenRecognition) { 5788 radzenRecognition.stopRequested = true; 5789 if (radzenRecognition.componentRef._id != componentRef._id) { 5790 radzenRecognition.addEventListener('end', function () { start(); }); 5791 } 5792 radzenRecognition.stop(); 5793 } else { 5794 start(); 5795 } 5796 }, 5797 openChartTooltip: function (chart, x, y, id, instance, callback) { 5798 var existing = document.getElementById(id); 5799 var wasOpen = existing && existing.style.display != 'none' && existing.offsetParent != null; 5800 5801 Radzen.closeTooltip(id); 5802 5803 var chartRect = chart.getBoundingClientRect(); 5804 x = Math.max(2, chartRect.left + x); 5805 y = Math.max(2, chartRect.top + y); 5806 Radzen.openPopup(chart, id, false, null, x, y, instance, callback, true, false, false); 5807 5808 var popup = document.getElementById(id); 5809 if (!popup) { 5810 return; 5811 } 5812 var tooltipContent = popup.children[0]; 5813 5814 var inner = tooltipContent.querySelector('.rz-chart-tooltip-content'); 5815 if (inner) { 5816 inner.classList.remove('rz-chart-tooltip-enter'); 5817 if (!wasOpen) { 5818 void inner.offsetWidth; 5819 inner.classList.add('rz-chart-tooltip-enter'); 5820 } 5821 } 5822 var tooltipContentRect = tooltipContent.getBoundingClientRect(); 5823 var tooltipContentClassName = 'rz-top-chart-tooltip'; 5824 if (y - tooltipContentRect.height < 0) { 5825 tooltipContentClassName = 'rz-bottom-chart-tooltip'; 5826 } 5827 tooltipContent.classList.remove('rz-top-chart-tooltip'); 5828 tooltipContent.classList.remove('rz-bottom-chart-tooltip'); 5829 tooltipContent.classList.add(tooltipContentClassName); 5830 }, 5831 createScrollListener: function (ref, selectors, selector) { 5832 let currentSelector; 5833 const container = selector ? document.querySelector(selector) : document.documentElement; 5834 const elements = selectors.map(document.querySelector, document); 5835 5836 let rafId = null; 5837 5838 const scrollHandler = () => { 5839 if (rafId !== null) { 5840 return; 5841 } 5842 5843 rafId = requestAnimationFrame(() => { 5844 rafId = null; 5845 5846 const isHtml = !selector || container.tagName === 'HTML'; 5847 const threshold = isHtml ? 10 : container.getBoundingClientRect().top + 10; 5848 const atBottom = isHtml 5849 ? window.scrollY > 0 && (window.innerHeight + window.scrollY) >= document.documentElement.scrollHeight - 2 5850 : container.scrollTop > 0 && (container.scrollTop + container.clientHeight) >= container.scrollHeight - 2; 5851 5852 let match; 5853 5854 if (atBottom) { 5855 for (let i = selectors.length - 1; i >= 0; i--) { 5856 if (elements[i]) { 5857 match = selectors[i]; 5858 break; 5859 } 5860 } 5861 } else { 5862 for (let i = elements.length - 1; i >= 0; i--) { 5863 const element = elements[i]; 5864 5865 if (!element) { 5866 continue; 5867 } 5868 5869 if (element.getBoundingClientRect().top <= threshold) { 5870 match = selectors[i]; 5871 break; 5872 } 5873 } 5874 } 5875 5876 if (match !== currentSelector) { 5877 currentSelector = match; 5878 try { 5879 ref.invokeMethodAsync('ScrollIntoView', currentSelector); 5880 } catch { 5881 } 5882 } 5883 }); 5884 }; 5885 5886 const scrollTarget = selector ? container : window; 5887 scrollTarget.addEventListener('scroll', scrollHandler, { passive: true }); 5888 window.addEventListener('resize', scrollHandler, { passive: true }); 5889 5890 scrollHandler(); 5891 5892 return { 5893 dispose() { 5894 scrollTarget.removeEventListener('scroll', scrollHandler); 5895 window.removeEventListener('resize', scrollHandler); 5896 } 5897 }; 5898 }, 5899 setTheme: function (href, wcagHref) { 5900 const theme = document.getElementById('radzen-theme-link'); 5901 if (theme && theme.sheet && theme.sheet.href === theme.href && theme.href != href) { 5902 theme.href = href; 5903 } 5904 5905 let wcagTheme = document.getElementById('radzen-wcag-theme-link'); 5906 5907 if (!wcagTheme && wcagHref) { 5908 wcagTheme = document.createElement('link'); 5909 wcagTheme.id = 'radzen-wcag-theme-link'; 5910 wcagTheme.rel = 'stylesheet'; 5911 wcagTheme.href = wcagHref; 5912 theme.parentNode.insertBefore(wcagTheme, theme.nextSibling); 5913 } else if (wcagTheme && wcagTheme.href != wcagHref) { 5914 if (!wcagHref) { 5915 wcagTheme.parentNode.removeChild(wcagTheme); 5916 return; 5917 } else { 5918 wcagTheme.href = wcagHref; 5919 } 5920 } 5921 }, 5922 createDraggable: function(element, ref, onDragStart) { 5923 function handleDragStart(e) { 5924 e.dataTransfer.setData('', e.target.id); 5925 try { suppressDisposed(ref.invokeMethodAsync(onDragStart)); } catch { } 5926 } 5927 element.draggable = true; 5928 element.addEventListener('dragstart', handleDragStart); 5929 return { 5930 dispose() { 5931 element.removeEventListener('dragstart', handleDragStart); 5932 } 5933 }; 5934 } 5935}; 5936 5937Radzen.registerFabMenu = function(element, dotnet){ 5938 if(!element) return; 5939 if(element.__rzOutsideClickHandler){ 5940 document.removeEventListener('click', element.__rzOutsideClickHandler); 5941 delete element.__rzOutsideClickHandler; 5942 } 5943 const handler = function(e){ 5944 if(!element.contains(e.target)){
5945 try { suppressDisposed(dotnet.invokeMethodAsync('CloseAsync')); } catch { } 5946 } 5947 }; 5948 element.__rzOutsideClickHandler = handler; 5949 document.addEventListener('click', handler); 5950}; 5951Radzen.unregisterFabMenu = function(element){ 5952 if(!element) return; 5953 const handler = element.__rzOutsideClickHandler; 5954 if(handler){ 5955 document.removeEventListener('click', handler); 5956 delete element.__rzOutsideClickHandler; 5957 } 5958}; 5959Radzen.chatIsNearBottom = function(container, threshold) { 5960 if (!container) return true; 5961 return container.scrollHeight - container.scrollTop - container.clientHeight <= (threshold || 50); 5962}; 5963Radzen.chatScrollToBottom = function(container) { 5964 if (!container) return; 5965 container.scrollTop = container.scrollHeight; 5966}; 5967Radzen.noop = function() {}; 5968Radzen.getCookies = function() { 5969 return document.cookie; 5970}; 5971Radzen.setCookie = function(cookie) { 5972 document.cookie = cookie; 5973}; 5974Radzen.scrollToTop = function(elementId) { 5975 try { var el = document.getElementById(elementId); if (el) el.scrollTop = 0; } catch(e) {} 5976}; 5977Radzen.scrollIntoView = function(selector) { 5978 var el = document.querySelector(selector); 5979 if (el) el.scrollIntoView(); 5980}; 5981Radzen.delayedFocus = function(elementId, delay) { 5982 setTimeout(function() { var el = document.getElementById(elementId); if (el) el.focus(); }, delay || 200); 5983}; 5984Radzen.invokeRadzenCallback = function(key) { 5985 var fn = Radzen[key]; 5986 if (typeof fn === 'function') fn(); 5987}; 5988Radzen.chatScrollAfterRender = function(selector, delay) { 5989 setTimeout(function() { 5990 var container = document.querySelector(selector); 5991 if (container) container.scrollTop = container.scrollHeight; 5992 }, delay || 100); 5993}; 5994Radzen.createAutoComplete = function(el, popupId, openOnFocus, instance, openCallback, closeCallback) { 5995 if (!el) return { dispose: function() {} }; 5996 var input = el.querySelector('input.rz-autocomplete-input, textarea.rz-autocomplete-input'); 5997 var list = el.querySelector('.rz-autocomplete-list'); 5998 if (!input) return { dispose: function() {} }; 5999 function open() { 6000 var popup = document.getElementById(popupId); 6001 var wasOpen = popup && popup.style.display == 'block'; 6002 Radzen.openPopup(input.parentNode, popupId, true, null, null, null, instance, closeCallback); 6003 if (!wasOpen && instance && openCallback) { 6004 try { suppressDisposed(instance.invokeMethodAsync(openCallback)); } catch { } 6005 } 6006 } 6007 function onInput() { open(); } 6008 function onFocus() { open(); } 6009 function clearActive() { Radzen.activeElement = null; } 6010 input.addEventListener('input', onInput); 6011 input.addEventListener('blur', clearActive); 6012 if (openOnFocus) input.addEventListener('focus', onFocus); 6013 if (list) list.addEventListener('mousedown', clearActive); 6014 return { dispose: function() { 6015 input.removeEventListener('input', onInput); 6016 input.removeEventListener('blur', clearActive); 6017 if (openOnFocus) input.removeEventListener('focus', onFocus); 6018 if (list) list.removeEventListener('mousedown', clearActive); 6019 }}; 6020}; 6021Radzen.createDataGrid = function(el) { 6022 if (!el) return { dispose: function() {} }; 6023 function onClick(e) { 6024 var label = e.target.closest('.rz-cell-filter-label'); 6025 if (label) { e.preventDefault(); } 6026 var btn = e.target.closest('button[aria-haspopup][aria-controls]'); 6027 if (btn && !btn.closest('.rz-datepicker') && el.contains(btn) && label && label.contains(btn) && btn.getAttribute('aria-controls')) { 6028 Radzen.togglePopup(btn.parentNode, btn.getAttribute('aria-controls')); 6029 } 6030 } 6031 function onMousedown(e) { 6032 var btn = e.target.closest('.rz-apply-filter'); 6033 if (btn) { Radzen.blur(btn, e); } 6034 } 6035 el.addEventListener('click', onClick); 6036 el.addEventListener('mousedown', onMousedown); 6037 return { dispose: function() { 6038 el.removeEventListener('click', onClick); 6039 el.removeEventListener('mousedown', onMousedown); 6040 }}; 6041}; 6042Radzen.createDropDown = function(el) { 6043 if (!el) return { dispose: function() {} }; 6044 function onMousedown() { Radzen.activeElement = null; } 6045 function onFilterClick(e) { 6046 var input = e.target.closest('.rz-multiselect-filter-container input'); 6047 if (input) { e.preventDefault(); e.stopPropagation(); } 6048 } 6049 el.addEventListener('mousedown', onMousedown); 6050 el.addEventListener('click', onFilterClick, true); 6051 return { dispose: function() { 6052 el.removeEventListener('mousedown', onMousedown); 6053 el.removeEventListener('click', onFilterClick, true); 6054 }}; 6055}; 6056Radzen.createFileInput = function(el) { 6057 if (!el) return { dispose: function() {} }; 6058 var choose = el.querySelector('.rz-fileupload-choose'); 6059 var fileInput = el.querySelector('input[type=file]'); 6060 function onKeydown(e) { 6061 if (e.keyCode === 32 || e.keyCode === 13) { 6062 e.preventDefault(); 6063 var child = choose.firstElementChild; 6064 if (child) child.click(); 6065 } 6066 } 6067 function onStopKeydown(e) { e.stopPropagation(); } 6068 function onChange(e) { Radzen.uploadInputChange(e, null, false, false, true); } 6069 if (choose) choose.addEventListener('keydown', onKeydown); 6070 if (fileInput) { 6071 fileInput.addEventListener('keydown', onStopKeydown); 6072 fileInput.addEventListener('change', onChange); 6073 } 6074 return { dispose: function() { 6075 if (choose) choose.removeEventListener('keydown', onKeydown); 6076 if (fileInput) { 6077 fileInput.removeEventListener('keydown', onStopKeydown); 6078 fileInput.removeEventListener('change', onChange); 6079 } 6080 }}; 6081}; 6082Radzen.createMask = function(el, id, mask, pattern, charPattern) { 6083 if (!el) return { dispose: function() {} }; 6084 function onInput() { Radzen.mask(id, mask, pattern, charPattern); } 6085 el.addEventListener('input', onInput); 6086 return { dispose: function() { el.removeEventListener('input', onInput); }}; 6087}; 6088Radzen.createNumeric = function(el, isInteger, separator, min, max, isNullable) { 6089 if (!el) return { dispose: function() {} }; 6090 var input = el.querySelector('.rz-numeric-input'); 6091 if (!input) return { dispose: function() {} }; 6092 function onKeypress(e) { Radzen.numericKeyPress(e, isInteger, separator); } 6093 function onBlur(e) { Radzen.numericOnInput(e, min, max, isNullable); } 6094 function onPaste(e) { Radzen.numericOnPaste(e, min, max); } 6095 input.addEventListener('keypress', onKeypress); 6096 if (min !== null || max !== null) { 6097 input.addEventListener('blur', onBlur); 6098 input.addEventListener('paste', onPaste); 6099 } 6100 return { dispose: function() { 6101 input.removeEventListener('keypress', onKeypress); 6102 input.removeEventListener('blur', onBlur); 6103 input.removeEventListener('paste', onPaste); 6104 }}; 6105}; 6106Radzen.createProfileMenu = function(el) { 6107 if (!el) return { dispose: function() {} }; 6108 var toggle = el.querySelector('.rz-navigation-item-wrapper'); 6109 if (!toggle) return { dispose: function() {} }; 6110 function onClick() { Radzen.toggleMenuItem(toggle); } 6111 toggle.addEventListener('click', onClick); 6112 return { dispose: function() { toggle.removeEventListener('click', onClick); }}; 6113}; 6114Radzen.createSplitButton = function(el, popupId) { 6115 if (!el) return { dispose: function() {} }; 6116 var btn = el.querySelector('.rz-splitbutton-menubutton'); 6117 if (!btn) return { dispose: function() {} }; 6118 function onClick() { if (popupId) Radzen.togglePopup(btn.parentNode, popupId); } 6119 btn.addEventListener('click', onClick); 6120 return { dispose: function() { btn.removeEventListener('click', onClick); }}; 6121}; 6122Radzen.createMenu = function(el, clickToOpen) { 6123 if (!el) return { dispose: function() {} }; 6124 function onClick(e) { 6125 var item = e.target.closest('.rz-navigation-item-wrapper'); 6126 if (!item || !el.contains(item)) return; 6127 var navItem = item.closest('.rz-navigation-item'); 6128 var hasChildren = navItem && navItem.querySelector('.rz-navigation-menu'); 6129 if (clickToOpen || hasChildren) { 6130 Radzen.toggleMenuItem(item); 6131 } else { 6132 Radzen.toggleMenuItem(item, e, false); 6133 } 6134 } 6135 el.addEventListener('click', onClick); 6136 var hoverItems = []; 6137 if (!clickToOpen) { 6138 el.querySelectorAll('.rz-navigation-item').forEach(function(navItem) { 6139 if (!navItem.querySelector('.rz-navigation-menu')) return; 6140 var li = navItem.closest('li') || navItem; 6141 function onEnter(e) { Radzen.toggleMenuItem(li, e, true, false); } 6142 function onLeave(e) { Radzen.toggleMenuItem(li, e, false, false); } 6143 li.addEventListener('mouseenter', onEnter); 6144 li.addEventListener('mouseleave', onLeave); 6145 hoverItems.push({ el: li, onEnter: onEnter, onLeave: onLeave }); 6146 }); 6147 } 6148 return { dispose: function() { 6149 el.removeEventListener('click', onClick);
6150 hoverItems.forEach(function(h) { 6151 h.el.removeEventListener('mouseenter', h.onEnter); 6152 h.el.removeEventListener('mouseleave', h.onLeave); 6153 }); 6154 }}; 6155}; 6156Radzen.createUpload = function(el, url, auto, multiple, parameterName, method, stream) { 6157 if (!el) return { dispose: function() {} }; 6158 var choose = el.querySelector('.rz-fileupload-choose'); 6159 var fileInput = el.querySelector('input[type=file]'); 6160 function onKeydown(e) { 6161 if (e.keyCode === 32 || e.keyCode === 13) { 6162 e.preventDefault(); 6163 var child = choose.firstElementChild; 6164 if (child) child.click(); 6165 } 6166 } 6167 function onStopKeydown(e) { e.stopPropagation(); } 6168 function onChange(e) { 6169 Radzen.uploadInputChange(e, url, auto, multiple, true, parameterName, method, stream); 6170 } 6171 function onImgError() { this.style.display = 'none'; } 6172 if (choose) choose.addEventListener('keydown', onKeydown); 6173 if (fileInput) { 6174 fileInput.addEventListener('keydown', onStopKeydown); 6175 if (url) fileInput.addEventListener('change', onChange); 6176 } 6177 el.querySelectorAll('.rz-fileupload-row img').forEach(function(img) { 6178 img.addEventListener('error', onImgError); 6179 }); 6180 return { dispose: function() { 6181 if (choose) choose.removeEventListener('keydown', onKeydown); 6182 if (fileInput) { 6183 fileInput.removeEventListener('keydown', onStopKeydown); 6184 if (url) fileInput.removeEventListener('change', onChange); 6185 } 6186 el.querySelectorAll('.rz-fileupload-row img').forEach(function(img) { 6187 img.removeEventListener('error', onImgError); 6188 }); 6189 }}; 6190}; 6191class Spreadsheet { 6192 constructor(element, dotNetRef, shortcuts) { 6193 this.element = element; 6194 this.dotNetRef = dotNetRef; 6195 this.shortcuts = shortcuts || {}; // map of key -> isGlobal (true = global, false = grid-only) 6196 this.rtl = Radzen.isRTL(element); 6197 this.element.addEventListener('keydown', this.onKeyDown); 6198 this.element.addEventListener('pointerdown', this.onPointerDown); 6199 this.element.addEventListener('dblclick', this.onDoubleClick); 6200 this.element.addEventListener('contextmenu', this.onContextMenu); 6201 addEventListener('paste', this.onPaste); 6202 addEventListener('copy', this.onCopy); 6203 } 6204 6205 onPaste = (e) => { 6206 if (this.isActive(e.target)) { 6207 var text = e.clipboardData.getData('text/plain'); 6208 this.dotNetRef.invokeMethodAsync('OnPasteAsync', text); 6209 } 6210 } 6211 6212 onCopy = async (e) => { 6213 if (this.isActive(e.target)) { 6214 this.dotNetRef.invokeMethodAsync('OnCopyAsync'); 6215 } 6216 } 6217 6218 isActive = (target) => { 6219 return target == this.element || this.element.contains(target); 6220 } 6221 6222 copyToClipboard = async (text) => { 6223 try { 6224 await navigator.clipboard.writeText(text); 6225 } catch { 6226 // Clipboard API failed (e.g. user activation expired) 6227 } 6228 } 6229 6230 readClipboardText = async () => { 6231 try { 6232 return await navigator.clipboard.readText(); 6233 } catch { 6234 return null; 6235 } 6236 } 6237 6238 onPointerDown = async (e) => { 6239 if (e.button != 0) return; 6240 6241 this.rtl = Radzen.isRTL(this.element); 6242 6243 if (e.target.matches('.rz-spreadsheet-autofill-handle')) { 6244 addEventListener('pointermove', this.onAutofillPointerMove); 6245 addEventListener('pointerup', this.onAutofillPointerUp); 6246 this.dotNetRef.invokeMethodAsync('OnAutofillPointerDownAsync', this.toEventArgs(e)); 6247 e.preventDefault(); 6248 e.stopPropagation(); 6249 return; 6250 } 6251 6252 if (e.target.matches('.rz-spreadsheet-cell')) { 6253 const cell = e.target; 6254 const row = +cell.dataset.row; 6255 const column = +cell.dataset.column; 6256 addEventListener('pointerup', this.onCellPointerUp); 6257 addEventListener('pointermove', this.onCellPointerMove); 6258 if (!(await this.dotNetRef.invokeMethodAsync('OnCellPointerDownAsync', { row, column, pointer: this.toEventArgs(e) }))) { 6259 removeEventListener('pointermove', this.onCellPointerMove); 6260 } 6261 } else if (e.target.matches('.rz-spreadsheet-row-header')) { 6262 const row = +e.target.dataset.row; 6263 addEventListener('pointerup', this.onRowPointerUp); 6264 addEventListener('pointermove', this.onRowPointerMove); 6265 if (!(await this.dotNetRef.invokeMethodAsync('OnRowPointerDownAsync', { row, pointer: this.toEventArgs(e) }))) { 6266 removeEventListener('pointermove', this.onRowPointerMove); 6267 } 6268 } else if (e.target.matches('.rz-spreadsheet-column-header')) { 6269 const column = +e.target.dataset.column; 6270 addEventListener('pointerup', this.onColumnPointerUp); 6271 addEventListener('pointermove', this.onColumnPointerMove); 6272 if (!(await this.dotNetRef.invokeMethodAsync('OnColumnPointerDownAsync', { column, pointer: this.toEventArgs(e) }))) { 6273 removeEventListener('pointermove', this.onColumnPointerMove); 6274 } 6275 } else if (e.target.matches('.rz-spreadsheet-resize-handle')) { 6276 const direction = e.target.dataset.direction; 6277 addEventListener('pointermove', this.onDrawingResizeMove); 6278 addEventListener('pointerup', this.onDrawingResizeUp); 6279 if (!(await this.dotNetRef.invokeMethodAsync('OnDrawingResizePointerDownAsync', { direction, pointer: this.toEventArgs(e) }))) { 6280 removeEventListener('pointermove', this.onDrawingResizeMove); 6281 removeEventListener('pointerup', this.onDrawingResizeUp); 6282 } 6283 e.preventDefault(); 6284 e.stopPropagation(); 6285 } else if (e.target.closest('.rz-spreadsheet-image') || e.target.closest('.rz-spreadsheet-chart')) { 6286 addEventListener('pointermove', this.onDrawingMoveMove); 6287 addEventListener('pointerup', this.onDrawingMoveUp); 6288 this.dotNetRef.invokeMethodAsync('OnDrawingMovePointerDownAsync', this.toEventArgs(e)); 6289 e.preventDefault(); 6290 } else if (e.target.matches('.rz-spreadsheet-column-resize-handle')) { 6291 const column = +e.target.dataset.column; 6292 addEventListener('pointermove', this.onColumnResizeMove); 6293 addEventListener('pointerup', this.onColumnResizeUp); 6294 if (!(await this.dotNetRef.invokeMethodAsync('OnColumnResizePointerDownAsync', { column, pointer: this.toEventArgs(e) }))) { 6295 removeEventListener('pointermove', this.onColumnResizeMove); 6296 removeEventListener('pointerup', this.onColumnResizeUp); 6297 } 6298 e.preventDefault(); 6299 e.stopPropagation(); 6300 } else if (e.target.matches('.rz-spreadsheet-row-resize-handle')) {
6301 const row = +e.target.dataset.row; 6302 addEventListener('pointermove', this.onRowResizeMove); 6303 addEventListener('pointerup', this.onRowResizeUp); 6304 if (!(await this.dotNetRef.invokeMethodAsync('OnRowResizePointerDownAsync', { row, pointer: this.toEventArgs(e) }))) { 6305 removeEventListener('pointermove', this.onRowResizeMove); 6306 removeEventListener('pointerup', this.onRowResizeUp); 6307 } 6308 e.preventDefault(); 6309 e.stopPropagation(); 6310 } 6311 } 6312 6313 onContextMenu = (e) => { 6314 if (e.target.matches('.rz-spreadsheet-cell')) { 6315 e.preventDefault(); 6316 const row = +e.target.dataset.row; 6317 const column = +e.target.dataset.column; 6318 this.dotNetRef.invokeMethodAsync('OnCellContextMenuAsync', { row, column, pointer: this.toEventArgs(e) }); 6319 } else if (e.target.matches('.rz-spreadsheet-row-header')) { 6320 e.preventDefault(); 6321 const row = +e.target.dataset.row; 6322 this.dotNetRef.invokeMethodAsync('OnRowContextMenuAsync', { row, pointer: this.toEventArgs(e) }); 6323 } else if (e.target.matches('.rz-spreadsheet-column-header')) { 6324 e.preventDefault(); 6325 const column = +e.target.dataset.column; 6326 this.dotNetRef.invokeMethodAsync('OnColumnContextMenuAsync', { column, pointer: this.toEventArgs(e) }); 6327 } else if (e.target === this.element) { 6328 // Keyboard-triggered (Shift+F10 / Menu key) lands on the grid root, not a cell. Suppress the 6329 // browser's native menu; the C# Shift+F10 shortcut opens our menu at the active cell. 6330 e.preventDefault(); 6331 } 6332 } 6333 6334 onDoubleClick = (e) => { 6335 if (e.target.matches('.rz-spreadsheet-cell')) { 6336 const cell = e.target; 6337 const row = +cell.dataset.row; 6338 const column = +cell.dataset.column; 6339 this.dotNetRef.invokeMethodAsync('OnCellDoubleClickAsync', { row, column, pointer: this.toEventArgs(e) }); 6340 } else if (e.target.matches('.rz-spreadsheet-column-resize-handle')) { 6341 e.preventDefault(); 6342 e.stopPropagation(); 6343 const column = +e.target.dataset.column; 6344 this.dotNetRef.invokeMethodAsync('OnColumnResizeDoubleClickAsync', { row: 0, column, pointer: this.toEventArgs(e) }); 6345 } 6346 } 6347 6348 measureTexts = (items) => { 6349 const probe = document.createElement('div'); 6350 probe.className = 'rz-spreadsheet-cell'; 6351 probe.style.visibility = 'hidden'; 6352 this.element.appendChild(probe); 6353 const style = getComputedStyle(probe); 6354 const baseFont = `${style.fontStyle} ${style.fontWeight} ${style.fontSize} ${style.fontFamily}`; 6355 const padding = (parseFloat(style.paddingLeft) || 0) + (parseFloat(style.paddingRight) || 0) 6356 + (parseFloat(style.borderLeftWidth) || 0) + (parseFloat(style.borderRightWidth) || 0); 6357 const baseFontSize = style.fontSize; 6358 const baseFontFamily = style.fontFamily; 6359 this.element.removeChild(probe); 6360 6361 this.measureCanvas ??= document.createElement('canvas'); 6362 const context = this.measureCanvas.getContext('2d'); 6363 context.direction = this.rtl ? 'rtl' : 'ltr'; 6364 6365 return items.map(item => { 6366 // Invalid font shorthand assignments are silently ignored; reset so they fall back to the base font. 6367 context.font = baseFont; 6368 if (item.bold || item.italic || item.fontSize != null || item.fontFamily) { 6369 const size = item.fontSize != null ? item.fontSize + 'pt' : baseFontSize; 6370 const family = item.fontFamily ? `"${item.fontFamily.replaceAll('"', '\\"')}", ${baseFontFamily}` : baseFontFamily; 6371 context.font = `${item.italic ? 'italic ' : ''}${item.bold ? 'bold ' : ''}${size} ${family}`; 6372 } 6373 const width = context.measureText(item.text).width; 6374 // 3% over-fit absorbs metric differences between canvas and other renderers (e.g. Excel after export). 6375 return Number.isFinite(width) ? Math.ceil(width * 1.03 + padding) : 0; 6376 }); 6377 } 6378 6379 onColumnPointerUp = (e) => { 6380 removeEventListener('pointermove', this.onColumnPointerMove); 6381 removeEventListener('pointerup', this.onColumnPointerUp); 6382 this.dotNetRef.invokeMethodAsync('OnSelectionPointerUpAsync'); 6383 } 6384 6385 onColumnPointerMove = (e) => { 6386 this.invokeAsync('OnColumnPointerMoveAsync', e); 6387 } 6388 6389 onRowPointerMove = (e) => { 6390 this.invokeAsync('OnRowPointerMoveAsync', e); 6391 } 6392 6393 onRowPointerUp = (e) => { 6394 removeEventListener('pointermove', this.onRowPointerMove); 6395 removeEventListener('pointerup', this.onRowPointerUp); 6396 this.dotNetRef.invokeMethodAsync('OnSelectionPointerUpAsync'); 6397 } 6398 6399 onCellPointerMove = (e) => { 6400 this.invokeAsync('OnCellPointerMoveAsync', e); 6401 } 6402 6403 onCellPointerUp = (e) => { 6404 removeEventListener('pointermove', this.onCellPointerMove); 6405 removeEventListener('pointerup', this.onCellPointerUp); 6406 this.dotNetRef.invokeMethodAsync('OnSelectionPointerUpAsync'); 6407 } 6408 6409 onKeyDown = (e) => { 6410 let key = ''; 6411 6412 if (e.ctrlKey || e.metaKey) { 6413 key += 'Ctrl+'; 6414 } 6415 6416 if (e.altKey) { 6417 key += 'Alt+'; 6418 } 6419 6420 if (e.shiftKey) { 6421 key += 'Shift+'; 6422 } 6423 6424 key += e.code.replace('Key', '').replace('Digit', '').replace('Numpad', ''); 6425 6426 // Grid context = focus on THIS spreadsheet's root or inside one of ITS cell/formula editors. 6427 // Scope the editor check to this.element so a sibling spreadsheet on the same page can never 6428 // match. Outside the grid (a toolbar button, sheet tab, ...) only global shortcuts act, so Tab 6429 // etc. stay native and the chrome is keyboard-navigable. 6430 let isGridContext = e.target === this.element; 6431 if (!isGridContext && e.target.closest) { 6432 const editorInput = e.target.closest('.rz-spreadsheet-editor-input'); 6433 isGridContext = editorInput != null && this.element.contains(editorInput); 6434 } 6435 6436 const global = this.shortcuts[key]; // true = global, false = grid-only, undefined = not a shortcut 6437 if (global === true || (global === false && isGridContext)) { 6438 e.preventDefault(); 6439 } 6440 6441 // Prevent default for printable characters when not already editing. 6442 // Without this, the character gets inserted twice: once by StartEdit and 6443 // once by the browser's default insertText when the editor receives focus. 6444 if (!e.ctrlKey && !e.metaKey && !e.altKey && e.key.length === 1 && e.target === this.element) { 6445 e.preventDefault(); 6446 } 6447 6448 this.dotNetRef.invokeMethodAsync('OnKeyDownAsync', this.toEventArgs(e), isGridContext); 6449 } 6450 6451 // F6 / Shift+F6 cycle focus between the spreadsheet regions in their visible top-to-bottom order: 6452 // ribbon tabs -> active toolbar -> formula bar -> grid -> sheet tabs. This is the advertised escape 6453 // from the grid (WCAG 2.1.2). 6454 focusAdjacent = (forward) => { 6455 // this.element IS this spreadsheet's root (.rz-spreadsheet, role=application). querySelector 6456 // only matches descendants of root, so regions from another spreadsheet on the page are never 6457 // matched. 6458 const root = this.element; 6459 const regions = [ 6460 root.querySelector('[role="tablist"], .rz-tabs-nav'), 6461 root.querySelector('.rz-toolbar'), 6462 root.querySelector('.rz-spreadsheet-formula-editor .rz-spreadsheet-editor-input'), 6463 root, 6464 root.querySelector('.rz-spreadsheet-sheet-tabs') 6465 ].filter(r => r); 6466 6467 if (regions.length === 0) { 6468 return; 6469 } 6470
6471 // Regions nest (the ribbon tabview contains the toolbar; the root contains everything), so pick 6472 // the INNERMOST region that contains the focused element - otherwise an outer region captures 6473 // focus that belongs to a nested one and F6 gets stuck cycling between two regions. 6474 const active = document.activeElement; 6475 let index = -1; 6476 let best = null; 6477 regions.forEach((r, i) => { 6478 if ((r === active || r.contains(active)) && (best === null || best.contains(r))) { 6479 best = r; 6480 index = i; 6481 } 6482 }); 6483 if (index === -1) { 6484 index = regions.indexOf(root); 6485 } 6486 6487 const next = (index + (forward ? 1 : -1) + regions.length) % regions.length; 6488 this.focusRegion(regions[next]); 6489 } 6490 6491 focusRegion = (region) => { 6492 // Focus the region itself when it is the tab stop: the grid root and the ribbon tablist both have 6493 // tabindex=0 (the tablist owns arrow-key tab switching via aria-activedescendant, so focusing an 6494 // individual tab would break the arrows), and the formula bar is a tabindex=-1 contenteditable. 6495 // Otherwise focus the region's first focusable child (e.g. the first toolbar button). 6496 if (region.tabIndex >= 0 || region.matches('.rz-spreadsheet-editor-input')) { 6497 region.focus(); 6498 return; 6499 } 6500 6501 // Skip hidden focusables: inline-rendered but closed popups (color pickers, numeric steppers) 6502 // match the selector yet calling focus() on a hidden element silently fails, which would strand 6503 // the user on the previous region. Pick the first one that is actually rendered. 6504 const focusables = region.querySelectorAll('button:not([disabled]), a[href], input:not([disabled]), [tabindex]:not([tabindex="-1"]), [contenteditable="true"]'); 6505 const target = [...focusables].find(el => el.offsetParent !== null || el.getClientRects().length > 0); 6506 (target || region).focus(); 6507 } 6508 6509 // Opens the cell context menu at the active cell (Shift+F10 / ContextMenu key). The cell element is 6510 // scoped to this spreadsheet; a synthetic pointer carries its on-screen position. 6511 openCellContextMenu = (row, column) => { 6512 const cell = this.element.querySelector('.rz-spreadsheet-cell[data-row="' + row + '"][data-column="' + column + '"]'); 6513 const rect = (cell || this.element).getBoundingClientRect(); 6514 const pointer = { 6515 clientX: Math.round(rect.left + 8), 6516 clientY: Math.round(cell ? rect.bottom : rect.top + 8), 6517 button: 0, buttons: 0, pointerType: 'mouse', isPrimary: true 6518 }; 6519 this.dotNetRef.invokeMethodAsync('OnCellContextMenuAsync', { row, column, pointer }); 6520 } 6521 6522 invokeAsync(name, e) { 6523 this.dotNetRef.invokeMethodAsync(name, this.toEventArgs(e)); 6524 } 6525 6526 toEventArgs(e) { 6527 return { 6528 key: e.key, 6529 code: this.rtl && (e.code === 'ArrowLeft' || e.code === 'ArrowRight') 6530 ? (e.code === 'ArrowLeft' ? 'ArrowRight' : 'ArrowLeft') 6531 : e.code, 6532 location: e.location, 6533 repeat: e.repeat, 6534 ctrlKey: e.ctrlKey, 6535 shiftKey: e.shiftKey, 6536 altKey: e.altKey, 6537 metaKey: e.metaKey, 6538 type: e.type, 6539 button: e.button, 6540 buttons: e.buttons, 6541 clientX: this.rtl ? -e.clientX : e.clientX, 6542 clientY: e.clientY, 6543 offsetX: this.rtl ? (e.target?.offsetWidth ?? 0) - e.offsetX : e.offsetX, 6544 offsetY: e.offsetY, 6545 pageX: e.pageX, 6546 pageY: e.pageY, 6547 screenX: e.screenX, 6548 screenY: e.screenY 6549 }; 6550 } 6551 6552 dispose() { 6553 this.element.removeEventListener('keydown', this.onKeyDown); 6554 this.element.removeEventListener('pointerdown', this.onPointerDown); 6555 this.element.removeEventListener('dblclick', this.onDoubleClick); 6556 this.element.removeEventListener('contextmenu', this.onContextMenu); 6557 removeEventListener('paste', this.onPaste); 6558 removeEventListener('copy', this.onCopy); 6559 } 6560 6561 onColumnResizeMove = (e) => { 6562 this.invokeAsync('OnColumnResizePointerMoveAsync', e); 6563 } 6564 6565 onColumnResizeUp = (e) => { 6566 this.invokeAsync('OnColumnResizePointerUpAsync', e); 6567 removeEventListener('pointermove', this.onColumnResizeMove); 6568 removeEventListener('pointerup', this.onColumnResizeUp); 6569 } 6570 6571 onRowResizeMove = (e) => { 6572 this.invokeAsync('OnRowResizePointerMoveAsync', e); 6573 } 6574 6575 onRowResizeUp = (e) => { 6576 this.invokeAsync('OnRowResizePointerUpAsync', e); 6577 removeEventListener('pointermove', this.onRowResizeMove); 6578 removeEventListener('pointerup', this.onRowResizeUp); 6579 } 6580 6581 onDrawingResizeMove = (e) => { 6582 this.invokeAsync('OnDrawingResizePointerMoveAsync', e); 6583 } 6584 6585 onDrawingResizeUp = (e) => { 6586 this.invokeAsync('OnDrawingResizePointerUpAsync', e); 6587 removeEventListener('pointermove', this.onDrawingResizeMove); 6588 removeEventListener('pointerup', this.onDrawingResizeUp); 6589 } 6590 6591 onDrawingMoveMove = (e) => { 6592 this.invokeAsync('OnDrawingMovePointerMoveAsync', e); 6593 } 6594 6595 onDrawingMoveUp = (e) => { 6596 this.invokeAsync('OnDrawingMovePointerUpAsync', e); 6597 removeEventListener('pointermove', this.onDrawingMoveMove); 6598 removeEventListener('pointerup', this.onDrawingMoveUp); 6599 } 6600 6601 onAutofillPointerMove = (e) => { 6602 this.invokeAsync('OnAutofillPointerMoveAsync', e); 6603 } 6604 6605 onAutofillPointerUp = (e) => { 6606 this.dotNetRef.invokeMethodAsync('OnAutofillPointerUpAsync', this.toEventArgs(e)); 6607 removeEventListener('pointermove', this.onAutofillPointerMove); 6608 removeEventListener('pointerup', this.onAutofillPointerUp); 6609 } 6610} 6611 6612Radzen.beginRangePickKeyHandler = function (dotNetRef) { 6613 Radzen.endRangePickKeyHandler(); 6614 Radzen.rangePickKeyHandler = function (e) { 6615 if (e.key === 'Escape') { 6616 e.preventDefault(); 6617 e.stopPropagation(); 6618 dotNetRef.invokeMethodAsync('OnEscapeKeyAsync'); 6619 } 6620 }; 6621 document.addEventListener('keydown', Radzen.rangePickKeyHandler, true); 6622}; 6623 6624Radzen.endRangePickKeyHandler = function () { 6625 if (Radzen.rangePickKeyHandler) { 6626 document.removeEventListener('keydown', Radzen.rangePickKeyHandler, true); 6627 Radzen.rangePickKeyHandler = null; 6628 } 6629}; 6630 6631class SheetEditor { 6632 constructor(element, value, autoFocus, dotNetRef) { 6633 this.element = element; 6634 this.element.innerText = value; 6635 this.dotNetRef = dotNetRef; 6636 this.element.addEventListener('input', this.onInput); 6637 this.element.addEventListener('keydown', this.onKeyDown); 6638 this.element.addEventListener('blur', this.onBlur); 6639 this.element.addEventListener('focus', this.onFocus); 6640 this.element.addEventListener('paste', this.onPaste); 6641 document.addEventListener('selectionchange', this.onSelectionChange); 6642 if (autoFocus) { 6643 this.focus(); 6644 } 6645 } 6646 6647 onPaste = (e) => { 6648 e.preventDefault(); 6649 const text = e.clipboardData.getData('text/plain'); 6650 const selection = getSelection(); 6651 if (!selection.rangeCount) return; 6652 selection.deleteFromDocument(); 6653 selection.getRangeAt(0).insertNode(document.createTextNode(text)); 6654 selection.collapseToEnd(); 6655 this.onInput(); 6656 }; 6657 6658 onSelectionChange = (e) => { 6659 const selection = getSelection(); 6660 if (!selection.focusNode) return; 6661 const inside = selection.focusNode.parentElement == this.element || selection.focusNode == this.element;
6662 let caretPosition = -1; 6663 6664 if (inside && selection.isCollapsed) 6665 { 6666 caretPosition = selection.focusOffset; 6667 } 6668 6669 this.dotNetRef.invokeMethodAsync('OnSelectionChangeAsync', caretPosition); 6670 }; 6671 6672 onInput = () => { 6673 this.dotNetRef.invokeMethodAsync('OnInputAsync', this.element.innerText); 6674 }; 6675 6676 setValue = (value, moveCaretTo) => { 6677 this.element.innerText = value; 6678 if (moveCaretTo != null) { 6679 const range = document.createRange(); 6680 const el = this.element.childNodes[0]; 6681 range.selectNodeContents(el) 6682 range.setStart(el, 0); 6683 range.setEnd(el, moveCaretTo); 6684 range.collapse(false); 6685 const selection = getSelection(); 6686 selection.removeAllRanges(); 6687 selection.addRange(range); 6688 } 6689 }; 6690 6691 onKeyDown = (e) => { 6692 if (e.key == 'Enter' && e.altKey) { 6693 e.preventDefault(); 6694 e.stopPropagation(); 6695 6696 const range = document.createRange(); 6697 range.selectNodeContents(this.element); 6698 range.collapse(false); 6699 range.deleteContents(); 6700 6701 6702 let br = document.createElement("br"); 6703 range.insertNode(br); 6704 6705 if (!br.previousSibling || br.previousSibling.nodeName != 'BR') { 6706 br = br.cloneNode(); 6707 range.insertNode(br); 6708 } 6709 6710 range.setStartAfter(br); 6711 range.setEndAfter(br); 6712 6713 const selection = getSelection(); 6714 selection.removeAllRanges(); 6715 selection.addRange(range); 6716 } else { 6717 const popup = document.querySelector('.rz-spreadsheet-highlight-popup .rz-state-highlight') != null; 6718 if (popup && (e.key == 'Tab' || e.key == 'ArrowUp' || e.key == 'ArrowDown')) { 6719 e.stopPropagation(); 6720 e.preventDefault(); 6721 this.dotNetRef.invokeMethodAsync('OnKeyDownAsync', { key: e.key }); 6722 } else if (e.key != 'Enter' && e.key != 'Escape' && e.key != 'Tab' && e.key != 'F6') { 6723 e.stopPropagation(); 6724 } 6725 } 6726 }; 6727 6728 onBlur = (e) => { 6729 if (e.relatedTarget && e.relatedTarget.matches('.rz-spreadsheet-editor-input') && e.relatedTarget.closest('.rz-spreadsheet') == this.element.closest('.rz-spreadsheet')) { 6730 return; 6731 } 6732 6733 this.dotNetRef.invokeMethodAsync('OnBlurAsync'); 6734 } 6735 6736 onFocus = () => { 6737 this.dotNetRef.invokeMethodAsync('OnFocusAsync'); 6738 } 6739 6740 focus() { 6741 this.element.focus(); 6742 const range = document.createRange(); 6743 range.selectNodeContents(this.element); 6744 range.collapse(false); 6745 6746 const selection = getSelection(); 6747 selection.removeAllRanges(); 6748 selection.addRange(range); 6749 } 6750 6751 dispose() { 6752 this.element.removeEventListener('input', this.onInput); 6753 this.element.removeEventListener('keydown', this.onKeyDown); 6754 this.element.removeEventListener('blur', this.onBlur); 6755 this.element.removeEventListener('focus', this.onFocus); 6756 this.element.removeEventListener('paste', this.onPaste); 6757 document.removeEventListener('selectionchange', this.onSelectionChange); 6758 } 6759} 6760 6761 6762 6763 6764Radzen.createSheetEditor = (element, value, autoFocus, dotNetRef) => new SheetEditor(element, value, autoFocus, dotNetRef); 6765Radzen.createSpreadsheet = (element, dotNetRef, shortcuts) => new Spreadsheet(element, dotNetRef, shortcuts); 6766Radzen.createVirtualItemContainer = (scrollable, content, ref) => { 6767 var height = scrollable.clientHeight; 6768 var width = scrollable.clientWidth; 6769 var scrollHeight = scrollable.scrollHeight; 6770 var scrollWidth = scrollable.scrollWidth; 6771 6772 content.addEventListener('mousewheel', function (e) { 6773 scrollable.scrollBy({ 6774 top: e.deltaY, 6775 left: e.deltaX 6776 }); 6777 e.preventDefault(); 6778 }); 6779 6780 var rtl = Radzen.isRTL(scrollable); 6781 6782 scrollable.addEventListener('scroll', function () { 6783 var scrollTop = scrollable.scrollTop; 6784 // In RTL the native scrollLeft is 0 at the right and negative toward the left; 6785 // report a non-negative logical scroll so the C# layout math stays direction-agnostic. 6786 var scrollLeft = rtl ? -scrollable.scrollLeft : scrollable.scrollLeft; 6787 6788 ref.invokeMethodAsync('OnScroll', scrollLeft, scrollTop); 6789 }); 6790 6791 var observer = new ResizeObserver(function () { 6792 const height = scrollable.clientHeight; 6793 const width = scrollable.clientWidth; 6794 6795 ref.invokeMethodAsync('OnResize', width, height); 6796 }); 6797 6798 observer.observe(scrollable); 6799 6800 return { width, height, scrollHeight, scrollWidth }; 6801}; 6802Radzen.scrollElementTo = (scrollable, left, top) => { 6803 scrollable.scrollTo({ top: top, left: Radzen.isRTL(scrollable) ? -left : left }); 6804}; 6805Radzen.createFormField = function(el) { 6806 if (!el || typeof el.addEventListener !== 'function') return { dispose: function() {} }; 6807 function onFocusIn() { el.classList.add('rz-state-focused'); } 6808 function onFocusOut() { el.classList.remove('rz-state-focused'); } 6809 el.addEventListener('focusin', onFocusIn); 6810 el.addEventListener('focusout', onFocusOut); 6811 return { dispose: function() { 6812 el.removeEventListener('focusin', onFocusIn); 6813 el.removeEventListener('focusout', onFocusOut); 6814 }}; 6815}; 6816Radzen.createSignaturePad = function(element, ref, strokeColor, strokeWidth, disabled, initialValue) { 6817 var noop = { update: function() {}, clear: function() {}, dispose: function() {} }; 6818 if (!element) return noop; 6819 6820 var canvas = element.querySelector('canvas'); 6821 if (!canvas) return noop; 6822 6823 var ctx = canvas.getContext('2d'); 6824 var drawing = false;
6825 var paths = []; 6826 var currentPath = []; 6827 6828 function syncSize() { 6829 var rect = canvas.getBoundingClientRect(); 6830 var w = Math.round(rect.width); 6831 var h = Math.round(rect.height); 6832 if (w > 0 && h > 0 && (canvas.width !== w || canvas.height !== h)) { 6833 canvas.width = w; 6834 canvas.height = h; 6835 redraw(); 6836 } 6837 } 6838 6839 function getPointerPos(e) { 6840 var rect = canvas.getBoundingClientRect(); 6841 var scaleX = canvas.width / rect.width; 6842 var scaleY = canvas.height / rect.height; 6843 return { 6844 x: (e.clientX - rect.left) * scaleX, 6845 y: (e.clientY - rect.top) * scaleY 6846 }; 6847 } 6848 6849 function redraw() { 6850 ctx.clearRect(0, 0, canvas.width, canvas.height); 6851 ctx.strokeStyle = strokeColor; 6852 ctx.lineWidth = strokeWidth; 6853 ctx.lineCap = 'round'; 6854 ctx.lineJoin = 'round'; 6855 for (var i = 0; i < paths.length; i++) { 6856 var path = paths[i]; 6857 if (path.length < 2) continue; 6858 ctx.beginPath(); 6859 ctx.moveTo(path[0].x, path[0].y); 6860 for (var j = 1; j < path.length; j++) { 6861 ctx.lineTo(path[j].x, path[j].y); 6862 } 6863 ctx.stroke(); 6864 } 6865 } 6866 6867 function loadImage(dataUrl) { 6868 if (!dataUrl) return; 6869 var img = new Image(); 6870 img.onload = function() { 6871 ctx.clearRect(0, 0, canvas.width, canvas.height); 6872 ctx.drawImage(img, 0, 0, canvas.width, canvas.height); 6873 }; 6874 img.src = dataUrl; 6875 } 6876 6877 syncSize(); 6878 6879 if (initialValue) { 6880 loadImage(initialValue); 6881 } 6882 6883 var resizeObserver = new ResizeObserver(function() { syncSize(); }); 6884 resizeObserver.observe(canvas); 6885 6886 function onPointerDown(e) { 6887 if (disabled) return; 6888 drawing = true; 6889 currentPath = [getPointerPos(e)]; 6890 canvas.setPointerCapture(e.pointerId); 6891 e.preventDefault(); 6892 } 6893 6894 function onPointerMove(e) { 6895 if (!drawing || disabled) return; 6896 var pos = getPointerPos(e); 6897 currentPath.push(pos); 6898 6899 ctx.strokeStyle = strokeColor; 6900 ctx.lineWidth = strokeWidth; 6901 ctx.lineCap = 'round'; 6902 ctx.lineJoin = 'round'; 6903 if (currentPath.length >= 2) { 6904 ctx.beginPath(); 6905 ctx.moveTo(currentPath[currentPath.length - 2].x, currentPath[currentPath.length - 2].y); 6906 ctx.lineTo(pos.x, pos.y); 6907 ctx.stroke(); 6908 } 6909 e.preventDefault(); 6910 } 6911 6912 function onPointerUp(e) { 6913 if (!drawing || disabled) return; 6914 drawing = false; 6915 if (currentPath.length > 0) { 6916 paths.push(currentPath); 6917 currentPath = []; 6918 } 6919 try { suppressDisposed(ref.invokeMethodAsync('RadzenSignaturePad.OnStrokeEnd', canvas.toDataURL('image/png'))); } catch (ex) { } 6920 e.preventDefault(); 6921 } 6922 6923 canvas.addEventListener('pointerdown', onPointerDown); 6924 canvas.addEventListener('pointermove', onPointerMove); 6925 canvas.addEventListener('pointerup', onPointerUp); 6926 canvas.addEventListener('pointercancel', onPointerUp); 6927 canvas.style.touchAction = 'none'; 6928 6929 return { 6930 update: function(newStrokeColor, newStrokeWidth, newDisabled) { 6931 strokeColor = newStrokeColor; 6932 strokeWidth = newStrokeWidth; 6933 disabled = newDisabled; 6934 redraw(); 6935 }, 6936 clear: function() { 6937 paths = []; 6938 currentPath = []; 6939 ctx.clearRect(0, 0, canvas.width, canvas.height); 6940 }, 6941 dispose: function() { 6942 resizeObserver.disconnect(); 6943 canvas.removeEventListener('pointerdown', onPointerDown); 6944 canvas.removeEventListener('pointermove', onPointerMove); 6945 canvas.removeEventListener('pointerup', onPointerUp); 6946 canvas.removeEventListener('pointercancel', onPointerUp); 6947 } 6948 }; 6949}; 6950Radzen.itemListKeydown = function (e) { 6951 var el = e.target; 6952 if (!el || !el.classList) return; 6953 var radio = el.classList.contains('rz-radio-button-list'); 6954 var checkbox = el.classList.contains('rz-checkbox-list'); 6955 if (!radio && !checkbox) return; 6956 var key = e.code ? e.code : e.key; 6957 if (key === 'ArrowLeft' || key === 'ArrowRight' || key === 'ArrowUp' || key === 'ArrowDown') { 6958 var horizontal = key === 'ArrowLeft' || key === 'ArrowRight'; 6959 if (radio || el.classList.contains(horizontal ? 'rz-checkbox-list-horizontal' : 'rz-checkbox-list-vertical')) { 6960 e.preventDefault(); 6961 } 6962 } else if (key === 'Home' || key === 'End' || key === 'Space' || key === 'Enter') { 6963 e.preventDefault(); 6964 } 6965}; 6966document.addEventListener('keydown', Radzen.itemListKeydown);
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.