if (!Element.prototype.matches) { Element.prototype.matches = Element.prototype.msMatchesSelector || Element.prototype.webkitMatchesSelector; } if (!Element.prototype.closest) { Element.prototype.closest = function (s) { var el = this; do { if (el.matches(s)) return el; el = el.parentElement || el.parentNode; } while (el !== null && el.nodeType === 1); return null; }; } var resolveCallbacks = []; var rejectCallbacks = []; var radzenRecognition; window.Radzen = { isRTL: function (el) { return el && getComputedStyle(el).direction == 'rtl'; }, throttle: function (callback, delay) { var timeout = null; return function () { var args = arguments; var ctx = this; if (!timeout) { timeout = setTimeout(function () { callback.apply(ctx, args); timeout = null; }, delay); } }; }, downloadFile: function (fileName, data, mimeType) { const blob = new Blob([data], { type: mimeType }); const url = URL.createObjectURL(blob); const a = document.createElement("a"); a.href = url; a.download = fileName; a.click(); URL.revokeObjectURL(url); }, mask: function (id, mask, pattern, characterPattern) { var el = document.getElementById(id); if (el) { var format = function (value, mask, pattern, characterPattern) { var chars = !characterPattern ? value.replace(new RegExp(pattern, "g"), "").split('') : value.match(new RegExp(characterPattern, "g")); var count = 0; var formatted = ''; for (var i = 0; i < mask.length; i++) { const c = mask[i]; if (chars && chars[count]) { if (c === '*' || c == chars[count]) { formatted += chars[count]; count++; } else { formatted += c; } } } return formatted; } if (window.safari !== undefined) { el.onblur = function (e) { el.dispatchEvent(new Event('change')); }; } var start = el.selectionStart != el.value.length ? el.selectionStart : -1; var end = el.selectionEnd != el.value.length ? el.selectionEnd : -1; el.value = format(el.value, mask, pattern, characterPattern); el.selectionStart = start != -1 ? start : el.selectionStart; el.selectionEnd = end != -1 ? end : el.selectionEnd; } }, addContextMenu: function (id, ref) { var el = document.getElementById(id); if (el) { var handler = function (e) { e.stopPropagation(); e.preventDefault(); try { ref.invokeMethodAsync('RadzenComponent.RaiseContextMenu', { ClientX: e.clientX, ClientY: e.clientY, ScreenX: e.screenX, ScreenY: e.screenY, AltKey: e.altKey, ShiftKey: e.shiftKey, CtrlKey: e.ctrlKey, MetaKey: e.metaKey, Button: e.button, Buttons: e.buttons, }); } catch { } return false; }; Radzen[id + 'contextmenu'] = handler; el.addEventListener('contextmenu', handler, false); } }, addMouseEnter: function (id, ref) { var el = document.getElementById(id); if (el) { var handler = function (e) { try { ref.invokeMethodAsync('RadzenComponent.RaiseMouseEnter'); } catch { } }; Radzen[id + 'mouseenter'] = handler; el.addEventListener('mouseenter', handler, false); } }, addMouseLeave: function (id, ref) { var el = document.getElementById(id); if (el) { var handler = function (e) { try { ref.invokeMethodAsync('RadzenComponent.RaiseMouseLeave'); } catch { } }; Radzen[id + 'mouseleave'] = handler; el.addEventListener('mouseleave', handler, false); } }, removeContextMenu: function (id) { var el = document.getElementById(id); if (el && Radzen[id + 'contextmenu']) { el.removeEventListener('contextmenu', Radzen[id + 'contextmenu']); } }, removeMouseEnter: function (id) { var el = document.getElementById(id); if (el && Radzen[id + 'mouseenter']) { el.removeEventListener('mouseenter', Radzen[id + 'mouseenter']); } }, removeMouseLeave: function (id) { var el = document.getElementById(id); if (el && Radzen[id + 'mouseleave']) { el.removeEventListener('mouseleave', Radzen[id + 'mouseleave']); } }, adjustDataGridHeader: function (scrollableHeader, scrollableBody) { if (scrollableHeader && scrollableBody) { scrollableHeader.style.cssText = scrollableBody.clientHeight < scrollableBody.scrollHeight ? 'margin-left:0px;padding-right: ' + (scrollableBody.offsetWidth - scrollableBody.clientWidth) + 'px' : 'margin-left:0px;'; } }, ganttSyncScroll: function (ganttId) { if (!ganttId) { return; } var root = document.getElementById(ganttId); if (!root) { return; } var grid = root.querySelector('.rz-data-grid-data'); var timeline = root.querySelector('.rz-gantt-timeline-scroll'); if (!grid || !timeline) { return; } var header = root.querySelector('.rz-gantt-table thead'); if (header) { root.style.setProperty('--rz-gantt-header-height', header.getBoundingClientRect().height + 'px'); } // Measure timeline group header and set CSS variable so the grid's // thead::before pseudo-row matches it. Also sync overall header height. function syncHeaderHeights() { var gridThead = grid.querySelector('thead'); var timelineThead = timeline.querySelector('thead'); if (!gridThead || !timelineThead) return; var groupRow = timelineThead.querySelector('.rz-gantt-header-group-row'); if (groupRow) { root.style.setProperty('--rz-gantt-header-group-height', groupRow.offsetHeight + 'px'); } else { root.style.setProperty('--rz-gantt-header-group-height', '0px'); } var maxH = Math.max(gridThead.offsetHeight, timelineThead.offsetHeight); root.style.setProperty('--rz-gantt-header-height', maxH + 'px'); } function runSyncAfterLayout() { requestAnimationFrame(function () { requestAnimationFrame(syncHeaderHeights); }); } runSyncAfterLayout(); var key = ganttId + '_ganttScrollSync'; var state = Radzen[key]; if (state && state.grid === grid && state.timeline === timeline) { return; } if (state) { if (state.grid && state.onGrid) { state.grid.removeEventListener('scroll', state.onGrid); } if (state.timeline && state.onTimeline) { state.timeline.removeEventListener('scroll', state.onTimeline); } if (state.grid && state.onGridWheel) { state.grid.removeEventListener('wheel', state.onGridWheel); } } var syncing = false; var onGrid = function () { if (syncing) { return; } syncing = true; timeline.scrollTop = grid.scrollTop; syncing = false; }; var onTimeline = function () { if (syncing) { return; } syncing = true; grid.scrollTop = timeline.scrollTop; syncing = false; }; // The grid has overflow-y: hidden (no native vertical scrollbar). // Forward vertical mouse-wheel events to the timeline so the user // can still scroll vertically while hovering over the grid. var onGridWheel = function (e) { if (e.deltaY) { timeline.scrollTop += e.deltaY; e.preventDefault(); } }; grid.addEventListener('scroll', onGrid); timeline.addEventListener('scroll', onTimeline); grid.addEventListener('wheel', onGridWheel, { passive: false }); var resizeObserver = null; if (typeof ResizeObserver !== 'undefined') { resizeObserver = new ResizeObserver(runSyncAfterLayout); resizeObserver.observe(root); } Radzen[key] = { grid: grid, timeline: timeline, onGrid: onGrid, onTimeline: onTimeline, onGridWheel: onGridWheel, resizeObserver: resizeObserver }; timeline.scrollTop = grid.scrollTop; }, ganttScrollToFirstEvent: function (ganttId) { if (!ganttId) return false; var root = document.getElementById(ganttId); if (!root) return false; var timeline = root.querySelector('.rz-gantt-timeline-scroll'); if (!timeline) return false; var events = timeline.querySelectorAll('.rz-event'); if (!events.length) return false; var timelineRect = timeline.getBoundingClientRect(); var thead = timeline.querySelector('thead'); var headerHeight = thead ? thead.offsetHeight : 0; var bestTop = Infinity; var bestLeft = Infinity; for (var i = 0; i < events.length; i++) { var rect = events[i].getBoundingClientRect(); if (rect.width <= 0) continue; var contentTop = rect.top - timelineRect.top + timeline.scrollTop; var contentLeft = rect.left - timelineRect.left + timeline.scrollLeft; if (contentTop < bestTop || (contentTop === bestTop && contentLeft < bestLeft)) { bestTop = contentTop; bestLeft = contentLeft; } } if (bestTop === Infinity) return false; timeline.scrollTop = Math.max(0, bestTop - headerHeight - 4); timeline.scrollLeft = Math.max(0, bestLeft - 40); return true; }, ganttSyncScrollDispose: function (ganttId) { if (!ganttId) { return; } var key = ganttId + '_ganttScrollSync'; var state = Radzen[key]; if (!state) { return; } if (state.grid && state.onGrid) { state.grid.removeEventListener('scroll', state.onGrid); } if (state.timeline && state.onTimeline) { state.timeline.removeEventListener('scroll', state.onTimeline); } if (state.grid && state.onGridWheel) { state.grid.removeEventListener('wheel', state.onGridWheel); } if (state.resizeObserver) { state.resizeObserver.disconnect(); } delete Radzen[key]; }, ganttInitDragResize: function (containerId, dotnetRef, timelineRangeMs, allowDrag, allowResize, rowHeightPx) { var key = containerId + '_ganttDragResize'; if (Radzen[key]) { Radzen[key].dotnetRef = dotnetRef; Radzen[key].timelineRangeMs = timelineRangeMs; Radzen[key].allowDrag = allowDrag; Radzen[key].allowResize = allowResize; Radzen[key].rowHeightPx = rowHeightPx || 36; return; } var root = document.getElementById(containerId); if (!root) return; var container = root.querySelector('.rz-gantt-timeline-scroll'); if (!container) return; var resizeThreshold = 6; var dragThreshold = 3; var drag = null; var justDragged = false; function getConfig() { return Radzen[key]; } function buildLinkPath(x1, x2, y1, y2, rh, linkType) { var offset = 12; var halfRow = rh * 0.5; var exitRight = linkType === 0 || linkType === 2; var enterRight = linkType === 2 || linkType === 3; var exitDir = exitRight ? 1 : -1; var enterDir = enterRight ? 1 : -1; var exitX = x1 + offset * exitDir; var enterX = x2 + offset * enterDir; var canGoStraight = exitRight !== enterRight ? (exitRight ? x2 - x1 > offset * 2 : x1 - x2 > offset * 2) : (exitRight ? exitX < enterX : exitX > enterX); if (canGoStraight && y1 !== y2) { var midX = (exitX + enterX) / 2; return 'M' + x1 + ',' + y1 + ' L' + midX + ',' + y1 + ' L' + midX + ',' + y2 + ' L' + x2 + ',' + y2; } var midY = y2 > y1 ? y1 + halfRow : (y2 < y1 ? y1 - halfRow : y1 + halfRow); return 'M' + x1 + ',' + y1 + ' L' + exitX + ',' + y1 + ' L' + exitX + ',' + midY + ' L' + enterX + ',' + midY + ' L' + enterX + ',' + y2 + ' L' + x2 + ',' + y2; } function updateConnectedPaths() { if (!drag) return; var svg = container.querySelector('.rz-gantt-links'); if (!svg) return; var config = getConfig(); var rh = config.rowHeightPx; var svgWidth = svg.getBoundingClientRect().width; var idx = drag.index; var paths = svg.querySelectorAll('path[data-from-index="' + idx + '"], path[data-to-index="' + idx + '"]'); for (var i = 0; i < paths.length; i++) { var path = paths[i]; var fromIdx = path.dataset.fromIndex; var toIdx = path.dataset.toIndex; var linkType = parseInt(path.dataset.linkType, 10) || 0; var fromBar = container.querySelector('[data-index="' + fromIdx + '"]'); var toBar = container.querySelector('[data-index="' + toIdx + '"]'); if (!fromBar || !toBar) continue; var fromRow = parseInt(fromBar.dataset.row, 10); var toRow = parseInt(toBar.dataset.row, 10); var fromLeft = parseFloat(fromBar.style.getPropertyValue('inset-inline-start')) || 0; var fromWidth = parseFloat(fromBar.style.width) || 0; var toLeft = parseFloat(toBar.style.getPropertyValue('inset-inline-start')) || 0; var toWidth = parseFloat(toBar.style.width) || 0; var fromIsMilestone = fromBar.classList.contains('rz-gantt-milestone'); var toIsMilestone = toBar.classList.contains('rz-gantt-milestone'); var x1, x2; if (linkType === 1) { x1 = fromLeft; x2 = toLeft; } else if (linkType === 2) { x1 = fromIsMilestone ? fromLeft : fromLeft + fromWidth; x2 = toIsMilestone ? toLeft : toLeft + toWidth; } else if (linkType === 3) { x1 = fromLeft; x2 = toIsMilestone ? toLeft : toLeft + toWidth; } else { x1 = fromIsMilestone ? fromLeft : fromLeft + fromWidth; x2 = toLeft; } var x1px = (x1 / 100) * svgWidth; var x2px = (x2 / 100) * svgWidth; var y1 = (fromRow + 0.5) * rh; var y2 = (toRow + 0.5) * rh; path.setAttribute('d', buildLinkPath(x1px, x2px, y1, y2, rh, linkType)); } } function onMouseDown(e) { var config = getConfig(); if (!config) return; var bar = e.target.closest('.rz-gantt-bar, .rz-gantt-milestone'); if (!bar || e.button !== 0 || !bar.dataset.index) return; var isMilestone = bar.classList.contains('rz-gantt-milestone'); var barRect = bar.getBoundingClientRect(); var offsetX = e.clientX - barRect.left; var mode; if (isMilestone) { if (!config.allowDrag) return; mode = 'move'; } else if (config.allowResize && offsetX <= resizeThreshold) { mode = 'resize-start'; } else if (config.allowResize && barRect.width - offsetX <= resizeThreshold) { mode = 'resize-end'; } else if (config.allowDrag) { mode = 'move'; } else { return; } e.preventDefault(); var containerEl = bar.closest('.rz-gantt-row-container'); var containerWidth = containerEl ? containerEl.getBoundingClientRect().width : 1; drag = { bar: bar, mode: mode, startClientX: e.clientX, containerWidth: containerWidth, originalLeft: parseFloat(bar.style.getPropertyValue('inset-inline-start')) || 0, originalWidth: parseFloat(bar.style.width) || 0, offsetStart: parseFloat(bar.dataset.offsetStart) || 0, offsetEnd: parseFloat(bar.dataset.offsetEnd) || 0, index: parseInt(bar.dataset.index, 10), isMilestone: isMilestone, hasMoved: false }; document.addEventListener('mousemove', onMouseMove); document.addEventListener('mouseup', onMouseUp); } function onMouseMove(e) { if (!drag) return; var deltaX = e.clientX - drag.startClientX; if (!drag.hasMoved && Math.abs(deltaX) < dragThreshold) return; drag.hasMoved = true; var percentDelta = (deltaX / drag.containerWidth) * 100; if (drag.mode === 'move') { drag.bar.style.setProperty('inset-inline-start', (drag.originalLeft + percentDelta) + '%'); } else if (drag.mode === 'resize-start') { var newWidth = drag.originalWidth - percentDelta; if (newWidth > 0.1) { drag.bar.style.setProperty('inset-inline-start', (drag.originalLeft + percentDelta) + '%'); drag.bar.style.width = newWidth + '%'; } } else if (drag.mode === 'resize-end') { var newWidth = drag.originalWidth + percentDelta; if (newWidth > 0.1) { drag.bar.style.width = newWidth + '%'; } } drag.bar.style.zIndex = '10'; drag.bar.style.opacity = '0.85'; document.body.style.cursor = drag.mode === 'move' ? 'grabbing' : 'ew-resize'; updateConnectedPaths(); } function onMouseUp(e) { if (!drag) return; document.removeEventListener('mousemove', onMouseMove); document.removeEventListener('mouseup', onMouseUp); drag.bar.style.zIndex = ''; drag.bar.style.opacity = ''; document.body.style.cursor = ''; if (drag.hasMoved) { justDragged = true; var deltaX = e.clientX - drag.startClientX; var percentDelta = (deltaX / drag.containerWidth) * 100; var config = getConfig(); var msPerPercent = config.timelineRangeMs / 100; var deltaMs = percentDelta * msPerPercent; var newStartMs, newEndMs; if (drag.mode === 'move') { newStartMs = drag.offsetStart + deltaMs; newEndMs = drag.offsetEnd + deltaMs; } else if (drag.mode === 'resize-start') { newStartMs = drag.offsetStart + deltaMs; newEndMs = drag.offsetEnd; } else { newStartMs = drag.offsetStart; newEndMs = drag.offsetEnd + deltaMs; } var eventType = drag.mode === 'move' ? 'move' : 'resize'; config.dotnetRef.invokeMethodAsync('OnGanttBarInteractionEnd', drag.index, eventType, newStartMs, newEndMs); } drag = null; } function onMouseMoveHover(e) { if (drag) return; var config = getConfig(); if (!config) return; var bar = e.target.closest('.rz-gantt-bar, .rz-gantt-milestone'); if (!bar || !bar.dataset.index) return; if (bar.classList.contains('rz-gantt-milestone')) { bar.style.cursor = config.allowDrag ? 'grab' : ''; return; } var barRect = bar.getBoundingClientRect(); var offsetX = e.clientX - barRect.left; if (config.allowResize && (offsetX <= resizeThreshold || barRect.width - offsetX <= resizeThreshold)) { bar.style.cursor = 'ew-resize'; } else if (config.allowDrag) { bar.style.cursor = 'grab'; } } function onClickCapture(e) { if (justDragged) { e.stopPropagation(); e.preventDefault(); justDragged = false; } } container.addEventListener('mousedown', onMouseDown); container.addEventListener('mousemove', onMouseMoveHover); container.addEventListener('click', onClickCapture, true); Radzen[key] = { container: container, dotnetRef: dotnetRef, timelineRangeMs: timelineRangeMs, allowDrag: allowDrag, allowResize: allowResize, rowHeightPx: rowHeightPx || 36, onMouseDown: onMouseDown, onMouseMoveHover: onMouseMoveHover, onClickCapture: onClickCapture }; }, ganttDisposeDragResize: function (containerId) { var key = containerId + '_ganttDragResize'; var config = Radzen[key]; if (!config) return; config.container.removeEventListener('mousedown', config.onMouseDown); config.container.removeEventListener('mousemove', config.onMouseMoveHover); config.container.removeEventListener('click', config.onClickCapture, true); delete Radzen[key]; }, preventDefaultAndStopPropagation: function (e) { e.preventDefault(); e.stopPropagation(); }, preventArrows: function (el) { var preventDefault = function (e) { if (e.keyCode === 38 || e.keyCode === 40) { e.preventDefault(); return false; } }; if (el) { el.addEventListener('keydown', preventDefault, false); } }, selectTab: function (id, index) { var el = document.getElementById(id); if (el && el.parentNode && el.parentNode.previousElementSibling) { var tablist = el.parentNode.previousElementSibling; var count = el.parentNode.children.length; for (var i = 0; i < count; i++) { var content = el.parentNode.children[i]; if (content) { content.style.display = i == index ? '' : 'none'; content.setAttribute('aria-hidden', i == index ? 'false' : 'true'); } var header = tablist.children[i]; if (header) { var btn = header.querySelector('[role="tab"]') || header; if (i == index) { header.classList.add('rz-tabview-selected'); header.classList.add('rz-state-focused'); btn.setAttribute('aria-selected', 'true'); } else { header.classList.remove('rz-tabview-selected'); header.classList.remove('rz-state-focused'); btn.setAttribute('aria-selected', 'false'); } } } if (tablist.getAttribute && tablist.getAttribute('role') === 'tablist') { var activeBtn = tablist.children[index] && (tablist.children[index].querySelector('[role="tab"]') || tablist.children[index]); if (activeBtn && activeBtn.id) { tablist.setAttribute('aria-activedescendant', activeBtn.id); } } } }, createAccordion: function (el, multiple) { function getItems() { var headers = []; var expanders = []; for (var i = 0; i < el.children.length; i++) { var child = el.children[i]; if (child.classList.contains('rz-accordion-header')) { headers.push(child); } else if (child.classList.contains('rz-expander')) { expanders.push(child); } } return { headers: headers, expanders: expanders }; } function toggleItem(index, expanded) { var items = getItems(); if (index < 0 || index >= items.headers.length) return; if (!multiple) { for (var i = 0; i < items.headers.length; i++) { if (i !== index) { var btn = items.headers[i].querySelector('button'); var icon = items.headers[i].querySelector('.rz-accordion-toggle-icon'); if (btn) btn.setAttribute('aria-expanded', 'false'); if (icon) { icon.classList.remove('rz-state-expanded'); icon.classList.add('rz-state-collapsed'); } items.expanders[i].classList.remove('rz-state-expanded'); items.expanders[i].classList.add('rz-state-collapsed'); items.expanders[i].setAttribute('aria-hidden', 'true'); } } } var button = items.headers[index].querySelector('button'); var toggleIcon = items.headers[index].querySelector('.rz-accordion-toggle-icon'); if (button) button.setAttribute('aria-expanded', expanded ? 'true' : 'false'); if (toggleIcon) { toggleIcon.classList.remove(expanded ? 'rz-state-collapsed' : 'rz-state-expanded'); toggleIcon.classList.add(expanded ? 'rz-state-expanded' : 'rz-state-collapsed'); } items.expanders[index].classList.remove(expanded ? 'rz-state-collapsed' : 'rz-state-expanded'); items.expanders[index].classList.add(expanded ? 'rz-state-expanded' : 'rz-state-collapsed'); items.expanders[index].setAttribute('aria-hidden', expanded ? 'false' : 'true'); } return { toggle: function (index, expanded) { toggleItem(index, expanded); }, setMultiple: function (value) { multiple = value; }, dispose: function () { } }; }, loadGoogleMaps: function (defaultView, apiKey, resolve, reject, language) { resolveCallbacks.push(resolve); rejectCallbacks.push(reject); if (defaultView['rz_map_init']) { return; } defaultView['rz_map_init'] = function () { for (var i = 0; i < resolveCallbacks.length; i++) { resolveCallbacks[i](defaultView.google); } }; var document = defaultView.document; var script = document.createElement('script'); script.src = 'https://maps.googleapis.com/maps/api/js?' + (language ? 'language=' + language + '&' : '') + (apiKey ? 'key=' + apiKey + '&' : '') + 'callback=rz_map_init&libraries=marker'; script.async = true; script.defer = true; script.onerror = function (err) { for (var i = 0; i < rejectCallbacks.length; i++) { rejectCallbacks[i](err); } }; document.body.appendChild(script); }, createMap: function (wrapper, ref, id, apiKey, mapId, zoom, center, markers, options, fitBoundsToMarkersOnUpdate, language) { var api = function () { var defaultView = document.defaultView; return new Promise(function (resolve, reject) { if (defaultView.google && defaultView.google.maps) { return resolve(defaultView.google); } Radzen.loadGoogleMaps(defaultView, apiKey, resolve, reject, language); }); }; api().then(function (google) { Radzen[id] = ref; Radzen[id].google = google; Radzen[id].instance = new google.maps.Map(wrapper, { center: center, zoom: zoom, mapId: mapId }); Radzen[id].instance.addListener('click', function (e) { try { Radzen[id].invokeMethodAsync('RadzenGoogleMap.OnMapClick', { Position: {Lat: e.latLng.lat(), Lng: e.latLng.lng()} }); } catch { } }); Radzen.updateMap(id, apiKey, zoom, center, markers, options, fitBoundsToMarkersOnUpdate, language); }); }, updateMap: function (id, apiKey, zoom, center, markers, options, fitBoundsToMarkersOnUpdate, language) { var api = function () { var defaultView = document.defaultView; return new Promise(function (resolve, reject) { if (defaultView.google && defaultView.google.maps) { return resolve(defaultView.google); } Radzen.loadGoogleMaps(defaultView, apiKey, resolve, reject, language); }); }; api().then(function (google) { let markerBounds = new google.maps.LatLngBounds(); if (Radzen[id] && Radzen[id].instance) { if (Radzen[id].instance.markers && Radzen[id].instance.markers.length) { for (var i = 0; i < Radzen[id].instance.markers.length; i++) { Radzen[id].instance.markers[i].setMap(null); } } if (markers) { Radzen[id].instance.markers = []; markers.forEach(function (m) { var content; if (m.label) { content = document.createElement('span'); content.innerHTML = m.label; } var marker = new this.google.maps.marker.AdvancedMarkerElement({ position: m.position, title: m.title, content: content }); marker.addListener('click', function (e) { try { Radzen[id].invokeMethodAsync('RadzenGoogleMap.OnMarkerClick', { Title: marker.title, Label: marker.content.innerText, Position: marker.position }); } catch { } }); marker.setMap(Radzen[id].instance); Radzen[id].instance.markers.push(marker); markerBounds.extend(marker.position); }); } if (zoom) { Radzen[id].instance.setZoom(zoom); } if (center) { Radzen[id].instance.setCenter(center); } if (options) { Radzen[id].instance.setOptions(options); } if (markers && fitBoundsToMarkersOnUpdate) { Radzen[id].instance.fitBounds(markerBounds); } } }); }, destroyMap: function (id) { if (Radzen[id].instance) { delete Radzen[id].instance; } }, focusSecurityCode: function (el) { if (!el) return; var firstInput = el.querySelector('.rz-security-code-input'); if (firstInput) { setTimeout(function () { firstInput.focus() }, 500); } }, destroySecurityCode: function (id, el) { if (!Radzen[id]) return; var inputs = el.getElementsByTagName('input'); if (Radzen[id].keyPress && Radzen[id].keyDown && Radzen[id].paste) { var isAndroid = navigator.userAgent.match(/Android/i); for (var i = 0; i < inputs.length; i++) { inputs[i].removeEventListener(isAndroid ? 'textInput' : 'keypress', Radzen[id].keyPress); inputs[i].removeEventListener('keydown', Radzen[id].keyDown); inputs[i].removeEventListener('paste', Radzen[id].paste); } delete Radzen[id].keyPress; delete Radzen[id].keyDown; delete Radzen[id].paste; } Radzen[id] = null; }, createSecurityCode: function (id, ref, el, isNumber) { if (!el || !ref) return; var hidden = el.querySelector('input[type="hidden"]'); Radzen[id] = {}; Radzen[id].inputs = [...el.querySelectorAll('.rz-security-code-input')]; var isAndroid = navigator.userAgent.match(/Android/i); Radzen[id].paste = function (e) { if (e.clipboardData) { var value = e.clipboardData.getData('text'); if (value) { for (var i = 0; i < Math.min(value.length, Radzen[id].inputs.length); i++) { if (isNumber && isNaN(+value[i])) { continue; } Radzen[id].inputs[i].value = value[i]; } var code = Radzen[id].inputs.map(i => i.value).join('').trim(); hidden.value = code; try { ref.invokeMethodAsync('RadzenSecurityCode.OnValueChange', code); } catch { } Radzen[id].inputs[Radzen[id].inputs.length - 1].focus(); } e.preventDefault(); } } Radzen[id].keyPress = function (e) { var keyCode = e.data ? e.data.charCodeAt(0) : e.which; var ch = e.data || String.fromCharCode(e.which); if (e.metaKey || e.ctrlKey || keyCode == 9 || keyCode == 8 || keyCode == 13 ) { return; } if (isNumber && (keyCode < 48 || keyCode > 57)) { e.preventDefault(); return; } // Android-specific: prevent default to avoid double input if (isAndroid && e.type === 'textInput') { e.preventDefault(); } if (e.currentTarget.value == ch) { return; } e.currentTarget.value = ch; var value = Radzen[id].inputs.map(i => i.value).join('').trim(); hidden.value = value; try { ref.invokeMethodAsync('RadzenSecurityCode.OnValueChange', value); } catch { } var index = Radzen[id].inputs.indexOf(e.currentTarget); if (index < Radzen[id].inputs.length - 1) { Radzen[id].inputs[index + 1].focus(); } } Radzen[id].keyDown = function (e) { var keyCode = e.which || e.keyCode; if (keyCode == 8) { e.currentTarget.value = ''; var value = Radzen[id].inputs.map(i => i.value).join('').trim(); hidden.value = value; try { ref.invokeMethodAsync('RadzenSecurityCode.OnValueChange', value); } catch { } var index = Radzen[id].inputs.indexOf(e.currentTarget); if (index > 0) { Radzen[id].inputs[index - 1].focus(); } } } for (var i = 0; i < Radzen[id].inputs.length; i++) { Radzen[id].inputs[i].addEventListener(isAndroid ? 'textInput' : 'keypress', Radzen[id].keyPress); Radzen[id].inputs[i].addEventListener('keydown', Radzen[id].keyDown); Radzen[id].inputs[i].addEventListener('paste', Radzen[id].paste); } }, createSlider: function ( id, slider, parent, range, minHandle, maxHandle, min, max, value, step, isVertical ) { Radzen[id] = {}; Radzen[id].mouseMoveHandler = function (e) { e.preventDefault(); var handle = slider.isMin ? minHandle : maxHandle; if (!slider.canChange) return; var offsetX = e.targetTouches && e.targetTouches[0] ? e.targetTouches[0].pageX - e.target.getBoundingClientRect().left : e.pageX - handle.getBoundingClientRect().left; var offsetY = e.targetTouches && e.targetTouches[0] ? e.targetTouches[0].pageY - e.target.getBoundingClientRect().top : e.pageY - handle.getBoundingClientRect().top; var percent = isVertical ? (parent.offsetHeight - handle.offsetTop - offsetY) / parent.offsetHeight : (Radzen.isRTL(handle) ? parent.offsetWidth - handle.offsetLeft - offsetX : handle.offsetLeft + offsetX) / parent.offsetWidth; if (percent > 1) { percent = 1; } else if (percent < 0) { percent = 0; } var newValue = percent * (max - min) + min; if ( slider.canChange && newValue >= min && newValue <= max ) { try { slider.invokeMethodAsync( 'RadzenSlider.OnValueChange', newValue, !!slider.isMin ); } catch { } } }; Radzen[id].mouseDownHandler = function (e) { if (parent.classList.contains('rz-state-disabled')) return; document.addEventListener('mousemove', Radzen[id].mouseMoveHandler); document.addEventListener('touchmove', Radzen[id].mouseMoveHandler, { passive: false, capture: true }); document.addEventListener('mouseup', Radzen[id].mouseUpHandler); document.addEventListener('touchend', Radzen[id].mouseUpHandler, { passive: true }); if (minHandle == e.target || maxHandle == e.target) { slider.canChange = true; slider.isMin = minHandle == e.target; } else { var offsetX = e.targetTouches && e.targetTouches[0] ? e.targetTouches[0].pageX - e.target.getBoundingClientRect().left : e.offsetX; var percent = offsetX / parent.offsetWidth; var newValue = percent * (max - min) + min; var oldValue = range ? value[slider.isMin ? 0 : 1] : value; if (newValue >= min && newValue <= max && newValue != oldValue) { try { slider.invokeMethodAsync( 'RadzenSlider.OnValueChange', newValue, !!slider.isMin ); } catch { } } } }; Radzen[id].mouseUpHandler = function (e) { slider.canChange = false; document.removeEventListener('mousemove', Radzen[id].mouseMoveHandler); document.removeEventListener('touchmove', Radzen[id].mouseMoveHandler, { passive: false, capture: true }); document.removeEventListener('mouseup', Radzen[id].mouseUpHandler); document.removeEventListener('touchend', Radzen[id].mouseUpHandler, { passive: true }); }; parent.addEventListener('mousedown', Radzen[id].mouseDownHandler); parent.addEventListener('touchstart', Radzen[id].mouseDownHandler, { passive: true }); }, destroySlider: function (id, parent) { if (!Radzen[id]) return; if (Radzen[id].mouseMoveHandler) { document.removeEventListener('mousemove', Radzen[id].mouseMoveHandler); document.removeEventListener('touchmove', Radzen[id].mouseMoveHandler); delete Radzen[id].mouseMoveHandler; } if (Radzen[id].mouseUpHandler) { document.removeEventListener('mouseup', Radzen[id].mouseUpHandler); document.removeEventListener('touchend', Radzen[id].mouseUpHandler); delete Radzen[id].mouseUpHandler; } if (Radzen[id].mouseDownHandler) { parent.removeEventListener('mousedown', Radzen[id].mouseDownHandler); parent.removeEventListener('touchstart', Radzen[id].mouseDownHandler); delete Radzen[id].mouseDownHandler; } Radzen[id] = null; }, prepareDrag: function (el) { if (el) { el.ondragover = function (e) { e.preventDefault(); }; el.ondragstart = function (e) { e.dataTransfer.setData('', e.target.id); }; } }, focusElement: function (elementId) { var el = document.getElementById(elementId); if (el) { el.focus(); } }, focusNext: function (container, reverse) { if (!container) return; 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])'; var candidates = Array.from(document.querySelectorAll(selector)).filter(function (el) { return (el.offsetWidth > 0 || el.offsetHeight > 0) && el !== container && !container.contains(el); }); if (reverse) { for (var i = candidates.length - 1; i >= 0; i--) { if (container.compareDocumentPosition(candidates[i]) & Node.DOCUMENT_POSITION_PRECEDING) { candidates[i].focus(); return; } } } else { for (var i = 0; i < candidates.length; i++) { if (container.compareDocumentPosition(candidates[i]) & Node.DOCUMENT_POSITION_FOLLOWING) { candidates[i].focus(); return; } } } }, scrollCarouselItem: function (el, duration) { var container = el.parentElement; var target = el.offsetLeft; if (duration == null || duration < 0) { container.scroll(target, 0); return; } if (duration === 0) { container.style.scrollBehavior = 'auto'; container.scroll(target, 0); container.style.scrollBehavior = ''; return; } container.style.scrollBehavior = 'auto'; container.style.scrollSnapType = 'none'; var start = container.scrollLeft; var distance = target - start; var startTime = null; function step(timestamp) { if (!startTime) startTime = timestamp; var elapsed = timestamp - startTime; var progress = Math.min(elapsed / duration, 1); var ease = progress < 0.5 ? 2 * progress * progress : 1 - Math.pow(-2 * progress + 2, 2) / 2; container.scrollLeft = start + distance * ease; if (elapsed < duration) { requestAnimationFrame(step); } else { container.style.scrollBehavior = ''; container.style.scrollSnapType = ''; } } requestAnimationFrame(step); }, createCarousel: function (container, ref) { var scrollTimeout = null; function handler() { if (scrollTimeout) clearTimeout(scrollTimeout); scrollTimeout = setTimeout(function () { var children = container.children; if (!children.length) return; var itemWidth = children[0].offsetWidth; if (itemWidth === 0) return; var index = Math.round(container.scrollLeft / itemWidth); if (index < 0) index = 0; if (index >= children.length) index = children.length - 1; try { ref.invokeMethodAsync('RadzenCarousel.OnScroll', index); } catch { } }, 100); } container.addEventListener('scroll', handler, { passive: true }); return { dispose: function () { container.removeEventListener('scroll', handler); } }; }, scrollIntoViewIfNeeded: function (ref, selector) { var el = selector ? ref.getElementsByClassName(selector)[0] : ref; if (el && el.scrollIntoViewIfNeeded) { el.scrollIntoViewIfNeeded(); } else if (el && el.scrollIntoView) { el.scrollIntoView(); } }, updateActiveDescendant: function (ul, li, index) { if (!ul) return; // The popup is appended to document.body when opened, so ul.closest('[role="combobox"]') // fails once the dropdown is open. Fall back to a reverse lookup via aria-controls. // There can be more than one combobox referencing the same listbox (the trigger and a // filter input inside the popup), so update them all so screen readers announce the // active option regardless of which element currently has focus. var comboboxes = []; var ancestor = ul.closest('[role="combobox"]'); if (ancestor) { comboboxes.push(ancestor); } if (ul.id && window.CSS && CSS.escape) { var escapedId = CSS.escape(ul.id); var matches = document.querySelectorAll( '[aria-controls="' + escapedId + '"][role="combobox"]' ); for (var i = 0; i < matches.length; i++) { if (comboboxes.indexOf(matches[i]) === -1) { comboboxes.push(matches[i]); } } } if (li) { var itemId = ul.id + '-' + index; li.id = itemId; for (var j = 0; j < comboboxes.length; j++) { comboboxes[j].setAttribute('aria-activedescendant', itemId); } } else { for (var k = 0; k < comboboxes.length; k++) { comboboxes[k].removeAttribute('aria-activedescendant'); } } }, selectListItem: function (input, ul, index) { if (!input || !ul) return; var childNodes = ul.getElementsByTagName('LI'); var highlighted = ul.querySelectorAll('.rz-state-highlight'); if (highlighted.length) { for (var i = 0; i < highlighted.length; i++) { highlighted[i].classList.remove('rz-state-highlight'); } } ul.nextSelectedIndex = index; if ( ul.nextSelectedIndex >= 0 && ul.nextSelectedIndex <= childNodes.length - 1 ) { childNodes[ul.nextSelectedIndex].classList.add('rz-state-highlight'); childNodes[ul.nextSelectedIndex].scrollIntoView({block:'nearest'}); Radzen.updateActiveDescendant(ul, childNodes[ul.nextSelectedIndex], ul.nextSelectedIndex); } else { Radzen.updateActiveDescendant(ul, null, -1); } }, focusListItem: function (input, ul, isDown, startIndex) { if (!input || !ul) return; var childNodes = ul.getElementsByTagName('LI'); if (!childNodes || childNodes.length == 0) return; if (startIndex == undefined || startIndex == null) { startIndex = -1; } ul.nextSelectedIndex = startIndex; if (isDown) { while (ul.nextSelectedIndex < childNodes.length - 1) { ul.nextSelectedIndex++; if (!childNodes[ul.nextSelectedIndex].classList.contains('rz-state-disabled')) break; } } else { while (ul.nextSelectedIndex >= 0) { ul.nextSelectedIndex--; if (!childNodes[ul.nextSelectedIndex] || !childNodes[ul.nextSelectedIndex].classList.contains('rz-state-disabled')) break; } } var highlighted = ul.querySelectorAll('.rz-state-highlight'); if (highlighted.length) { for (var i = 0; i < highlighted.length; i++) { highlighted[i].classList.remove('rz-state-highlight'); } } if ( ul.nextSelectedIndex >= 0 && ul.nextSelectedIndex <= childNodes.length - 1 ) { childNodes[ul.nextSelectedIndex].classList.add('rz-state-highlight'); Radzen.scrollIntoViewIfNeeded(childNodes[ul.nextSelectedIndex]); Radzen.updateActiveDescendant(ul, childNodes[ul.nextSelectedIndex], ul.nextSelectedIndex); } else { Radzen.updateActiveDescendant(ul, null, -1); } return ul.nextSelectedIndex; }, focusVirtualListItem: function (ul, absoluteIndex, totalCount) { if (!ul) return; var childNodes = ul.getElementsByTagName('LI'); if (!childNodes || childNodes.length == 0) return; var itemHeight = childNodes[0].offsetHeight; if (itemHeight <= 0) return; var wrapper = ul.parentElement; if (!wrapper) return; // Scroll to make the item at absoluteIndex visible if (absoluteIndex >= 0 && absoluteIndex < totalCount) { var targetTop = absoluteIndex * itemHeight; var targetBottom = targetTop + itemHeight; var viewTop = wrapper.scrollTop; var viewBottom = viewTop + wrapper.clientHeight; if (targetBottom > viewBottom) { wrapper.scrollTop = targetBottom - wrapper.clientHeight; } else if (targetTop < viewTop) { wrapper.scrollTop = targetTop; } } // Highlight the correct item after scroll function highlightItem() { var lis = ul.getElementsByTagName('LI'); if (!lis || lis.length == 0) return; var highlighted = ul.querySelectorAll('.rz-state-highlight'); for (var i = 0; i < highlighted.length; i++) { highlighted[i].classList.remove('rz-state-highlight'); } // Determine the start index of rendered items from the top spacer var startIndex = 0; var spacer = ul.firstElementChild; if (spacer && spacer.tagName !== 'LI' && spacer.style && spacer.style.height) { startIndex = Math.round(parseFloat(spacer.style.height) / itemHeight); } var relativeIndex = absoluteIndex - startIndex; if (relativeIndex >= 0 && relativeIndex < lis.length) { lis[relativeIndex].classList.add('rz-state-highlight'); lis[relativeIndex].scrollIntoView({ block: 'nearest' }); Radzen.updateActiveDescendant(ul, lis[relativeIndex], absoluteIndex); } else { Radzen.updateActiveDescendant(ul, null, -1); } } // Use MutationObserver to wait for Virtualize to re-render after scroll var observer = new MutationObserver(function () { observer.disconnect(); highlightItem(); }); observer.observe(ul, { childList: true, subtree: true }); // Also highlight immediately in case no DOM change is needed highlightItem(); // Disconnect observer after a timeout to avoid memory leaks setTimeout(function () { observer.disconnect(); }, 500); }, clearFocusedHeaderCell: function (gridId) { var grid = document.getElementById(gridId); if (!grid) return; var table = grid.querySelector('.rz-grid-table'); var thead = table.getElementsByTagName("thead")[0]; var highlightedCells = thead.querySelectorAll('.rz-state-focused'); if (highlightedCells.length) { for (var i = 0; i < highlightedCells.length; i++) { highlightedCells[i].classList.remove('rz-state-focused'); } } }, focusTableRow: function (gridId, key, rowIndex, cellIndex, isVirtual) { var grid = document.getElementById(gridId); if (!grid) return; var table = grid.querySelector('.rz-grid-table'); var tbody = table.tBodies[0]; var thead = table.tHead; var rows = (cellIndex != null && thead && thead.rows && thead.rows.length ? [...thead.rows] : []).concat(tbody && tbody.rows && tbody.rows.length ? [...tbody.rows] : []); if (isVirtual && (key == 'ArrowUp' || key == 'ArrowDown' || key == 'PageUp' || key == 'PageDown' || key == 'Home' || key == 'End')) { if (rowIndex == 0 && (key == 'End' || key == 'PageDown')) { var highlightedCells = thead.querySelectorAll('.rz-state-focused'); if (highlightedCells.length) { for (var i = 0; i < highlightedCells.length; i++) { highlightedCells[i].classList.remove('rz-state-focused'); } } } if (key == 'PageUp' || key == 'PageDown') { var rowHeight = rows[rows.length - 1] ? rows[rows.length - 1].offsetHeight : 40; var factor = 10; table.parentNode.scrollTop = table.parentNode.scrollTop + (factor * (key == 'PageDown' ? rowHeight : -rowHeight)); } else if (key == 'Home' || key == 'End') { table.parentNode.scrollTop = key == 'Home' ? 0 : table.parentNode.scrollHeight; } } table.nextSelectedIndex = rowIndex || 0; table.nextSelectedCellIndex = cellIndex || 0; if (key == 'ArrowDown') { while (table.nextSelectedIndex < rows.length - 1) { table.nextSelectedIndex++; if (!rows[table.nextSelectedIndex] || !rows[table.nextSelectedIndex].classList.contains('rz-state-disabled')) break; } } else if (key == 'ArrowUp') { while (table.nextSelectedIndex > 0) { table.nextSelectedIndex--; if (!rows[table.nextSelectedIndex] || !rows[table.nextSelectedIndex].classList.contains('rz-state-disabled')) break; } } else if (key == 'ArrowRight') { while (table.nextSelectedCellIndex < rows[table.nextSelectedIndex].cells.length - 1) { table.nextSelectedCellIndex++; if (!rows[table.nextSelectedIndex] || !rows[table.nextSelectedIndex].cells[table.nextSelectedCellIndex] || !rows[table.nextSelectedIndex].cells[table.nextSelectedCellIndex].classList.contains('rz-state-disabled')) break; } } else if (key == 'ArrowLeft') { while (table.nextSelectedCellIndex > 0) { table.nextSelectedCellIndex--; if (!rows[table.nextSelectedIndex] || !rows[table.nextSelectedIndex].cells[table.nextSelectedCellIndex] || !rows[table.nextSelectedIndex].cells[table.nextSelectedCellIndex].classList.contains('rz-state-disabled')) break; } } else if (isVirtual && (key == 'PageDown' || key == 'End')) { table.nextSelectedIndex = rows.length - 1; } else if (isVirtual && (key == 'PageUp' || key == 'Home')) { table.nextSelectedIndex = 1; } if (isVirtual && (key == 'ArrowDown' || key == 'ArrowUp')) { var minIndex = cellIndex != null ? 0 : 1; if (key == 'ArrowDown' && table.nextSelectedIndex >= rows.length - 1) { var rh = rows[rows.length - 1] ? rows[rows.length - 1].offsetHeight : 40; table.parentNode.scrollTop += rh; table.nextSelectedIndex = rows.length - 1; } else if (key == 'ArrowUp' && table.nextSelectedIndex <= minIndex) { var rh = rows[rows.length - 1] ? rows[rows.length - 1].offsetHeight : 40; table.parentNode.scrollTop -= rh; table.nextSelectedIndex = minIndex; } } var activeId = gridId + '-active-item'; var setActiveDescendant = function (el) { var prev = document.getElementById(activeId); if (prev && prev !== el) { prev.removeAttribute('id'); } if (el && el.id !== activeId) { el.id = activeId; } if (el) { grid.setAttribute('aria-activedescendant', activeId); } }; if (key == 'ArrowLeft' || key == 'ArrowRight' || (key == 'ArrowUp' && cellIndex != null && table.nextSelectedIndex == 0 && table.parentNode.scrollTop == 0)) { var highlightedCells = rows[table.nextSelectedIndex].querySelectorAll('.rz-state-focused'); if (highlightedCells.length) { for (var i = 0; i < highlightedCells.length; i++) { highlightedCells[i].classList.remove('rz-state-focused'); } } if ( table.nextSelectedCellIndex >= 0 && table.nextSelectedCellIndex <= rows[table.nextSelectedIndex].cells.length - 1 ) { var cell = rows[table.nextSelectedIndex].cells[table.nextSelectedCellIndex]; if (!cell.classList.contains('rz-state-focused')) { cell.classList.add('rz-state-focused'); if (!isVirtual && table.parentElement.scrollWidth > table.parentElement.clientWidth) { Radzen.scrollIntoViewIfNeeded(cell); } } setActiveDescendant(cell); } } else if (key == 'ArrowDown' || key == 'ArrowUp') { var highlighted = table.querySelectorAll('.rz-state-focused'); if (highlighted.length) { for (var i = 0; i < highlighted.length; i++) { highlighted[i].classList.remove('rz-state-focused'); } } if (table.nextSelectedIndex >= 0 && table.nextSelectedIndex <= rows.length - 1 ) { var row = rows[table.nextSelectedIndex]; if (!row.classList.contains('rz-state-focused')) { row.classList.add('rz-state-focused'); if (!isVirtual && table.parentElement.scrollHeight > table.parentElement.clientHeight) { Radzen.scrollIntoViewIfNeeded(row); } } setActiveDescendant(row); } } return [table.nextSelectedIndex, table.nextSelectedCellIndex]; }, uploadInputChange: function (e, url, auto, multiple, clear, parameterName, method = 'POST', stream = false) { if (auto) { Radzen.upload(e.target, url, multiple, clear, parameterName, method, stream); e.target.value = ''; } else { Radzen.uploadChange(e.target); } }, uploads: function (uploadComponent, id) { if (!Radzen.uploadComponents) { Radzen.uploadComponents = {}; } Radzen.uploadComponents[id] = uploadComponent; }, uploadChange: function (fileInput) { var files = []; for (var i = 0; i < fileInput.files.length; i++) { var file = fileInput.files[i]; files.push({ Name: file.name, Size: file.size, Url: URL.createObjectURL(file) }); } var uploadComponent = Radzen.uploadComponents && Radzen.uploadComponents[fileInput.id]; if (uploadComponent) { if (uploadComponent.localFiles) { // Clear any previously created preview URL(s) for (var i = 0; i < uploadComponent.localFiles.length; i++) { var file = uploadComponent.localFiles[i]; if (file.Url) { URL.revokeObjectURL(file.Url); } } } uploadComponent.files = Array.from(fileInput.files); uploadComponent.localFiles = files; try { uploadComponent.invokeMethodAsync('RadzenUpload.OnChange', files); } catch { } } for (var i = 0; i < fileInput.files.length; i++) { var file = fileInput.files[i]; if (file.Url) { URL.revokeObjectURL(file.Url); } } }, removeFileFromUpload: function (ref, name, id) { var uploadComponent = (Radzen.uploadComponents && Radzen.uploadComponents[ref]) ?? Radzen.uploadComponents[id]; if (!uploadComponent) return; if (!uploadComponent.files) return; var file = uploadComponent.files.find(function (f) { return f.name == name; }) if (!file) { return; } var localFile = uploadComponent.localFiles.find(function (f) { return f.Name == name; }); if (localFile) { URL.revokeObjectURL(localFile.Url); var localIndex = uploadComponent.localFiles.indexOf(localFile); if (localIndex != -1) { uploadComponent.localFiles.splice(localIndex, 1); } } var index = uploadComponent.files.indexOf(file) if (index != -1) { uploadComponent.files.splice(index, 1); } var fileInput = document.getElementById(id).querySelector('input[type="file"]'); if (fileInput && uploadComponent.files.length == 0) { fileInput.value = ''; } }, removeFileFromFileInput: function (fileInput) { fileInput.value = ''; }, upload: function (fileInput, url, multiple, clear, parameterName, method = 'POST', stream = false) { var uploadComponent = Radzen.uploadComponents && Radzen.uploadComponents[fileInput.id]; if (!uploadComponent) { return; } if (!uploadComponent.files || clear) { uploadComponent.files = Array.from(fileInput.files); } function asFormData() { var data = new FormData(); var files = []; for (var i = 0; i < uploadComponent.files.length; i++) { var file = uploadComponent.files[i]; data.append(parameterName || (multiple ? 'files' : 'file'), file, file.name); files.push({Name: file.name, Size: file.size}); } return {data, files} } function asStream() { if (uploadComponent.files.length > 0) { var file = uploadComponent.files[0]; return {data: file, files: [{Name: file.name, Size: file.size}]}; } return {data: null, files: []} } var cancelled = false; var {data, files} = stream ? asStream() : asFormData(); var xhr = new XMLHttpRequest(); xhr.withCredentials = true; xhr.upload.onprogress = function (e) { if (e.lengthComputable) { var uploadComponent = Radzen.uploadComponents && Radzen.uploadComponents[fileInput.id]; if (uploadComponent) { var progress = parseInt((e.loaded / e.total) * 100); try { uploadComponent.invokeMethodAsync( 'RadzenUpload.OnProgress', progress, e.loaded, e.total, files, cancelled ).then(function (cancel) { if (cancel) { cancelled = true; xhr.abort(); } }); } catch { } } } }; xhr.onreadystatechange = function (e) { if (xhr.readyState === XMLHttpRequest.DONE) { var status = xhr.status; var uploadComponent = Radzen.uploadComponents && Radzen.uploadComponents[fileInput.id]; if (uploadComponent) { if (status === 0 || (status >= 200 && status < 400)) { try { uploadComponent.invokeMethodAsync( 'RadzenUpload.OnComplete', xhr.responseText, cancelled ); } catch { } } else { try { uploadComponent.invokeMethodAsync( 'RadzenUpload.OnError', xhr.responseText ); } catch { } } } } }; try { uploadComponent.invokeMethodAsync('GetHeaders').then(function (headers) { xhr.open(method, url, true); for (var name in headers) { xhr.setRequestHeader(name, headers[name]); } xhr.send(data); }); } catch { } }, getCookie: function (name) { var value = '; ' + decodeURIComponent(document.cookie); var parts = value.split('; ' + name + '='); if (parts.length == 2) return parts.pop().split(';').shift(); }, getCulture: function () { var cultureCookie = Radzen.getCookie('.AspNetCore.Culture'); var uiCulture = cultureCookie ? cultureCookie.split('|').pop().split('=').pop() : null; return uiCulture || 'en-US'; }, numericOnPaste: function (e, min, max, locale = navigator.language) { if (!e.clipboardData) return; let value = e.clipboardData.getData("text"); if (!value) { e.preventDefault(); return; } value = String(value).trim(); const parts = new Intl.NumberFormat(locale).formatToParts(1234567.89); let group = ","; let decimal = "."; for (const p of parts) { if (p.type === "group") group = p.value; if (p.type === "decimal") decimal = p.value; } value = value.replace(/[\u00A0\u202F]/g, " "); if (group) { const escapedGroup = group.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); value = value.replace(new RegExp(escapedGroup, "g"), ""); } if (group === " ") { value = value.replace(/ /g, ""); } if (decimal !== ".") { const escapedDecimal = decimal.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); value = value.replace(new RegExp(escapedDecimal, "g"), "."); } if (!/^[+-]?(\d+(\.\d*)?|\.\d+)$/.test(value)) { e.preventDefault(); return; } const numericValue = Number(value); if (!Number.isFinite(numericValue)) { e.preventDefault(); return; } if (min != null && numericValue < min) { e.preventDefault(); return; } if (max != null && numericValue > max) { e.preventDefault(); return; } }, numericOnInput: function (e, min, max, isNullable) { var value = e.target.value; if (!isNullable && value == '' && min != null) { e.target.value = min; } if (value && !isNaN(+value)) { var numericValue = +value; if (min != null && !isNaN(+min) && numericValue < min) { e.target.value = min; } if (max != null && !isNaN(+max) && numericValue > max) { e.target.value = max; } } }, numericKeyPress: function (e, isInteger, decimalSeparator) { if ( e.metaKey || e.ctrlKey || e.keyCode == 9 || e.keyCode == 8 || e.keyCode == 13 ) { return; } if (e.code === 'NumpadDecimal' && !isInteger) { var cursorPosition = e.target.selectionEnd; e.target.value = [e.target.value.slice(0, e.target.selectionStart), decimalSeparator, e.target.value.slice(e.target.selectionEnd)].join(''); e.target.selectionStart = ++cursorPosition; e.target.selectionEnd = cursorPosition; e.preventDefault(); return; } var ch = e.key; if (/\p{Nd}/u.test(ch) || ch === '-' || (!isInteger && ch === decimalSeparator)) { return; } e.preventDefault(); }, openContextMenu: function (x,y,id, instance, callback) { Radzen.closePopup(id); Radzen.openPopup(null, id, false, null, x, y, instance, callback); setTimeout(function () { var popup = document.getElementById(id); if (popup) { var menu = popup.querySelector('.rz-menu'); if (menu) { menu.focus(); } } }, 500); }, openTooltip: function (target, id, delay, duration, position, closeTooltipOnDocumentClick, instance, callback, clientX, clientY) { Radzen.closeTooltip(id); if (clientX != null && clientY != null) { position = null; disableSmartPosition = true; } else { disableSmartPosition = false; } if (target) { target.setAttribute('aria-describedby', id); Radzen[id + 'target'] = target; } if (delay) { Radzen[id + 'delay'] = setTimeout(Radzen.openPopup, delay, target, id, false, position, clientX, clientY, instance, callback, closeTooltipOnDocumentClick, false, disableSmartPosition); } else { Radzen.openPopup(target, id, false, position, clientX, clientY, instance, callback, closeTooltipOnDocumentClick, false, disableSmartPosition); } if (duration) { Radzen[id + 'duration'] = setTimeout(Radzen.closePopup, duration, id, instance, callback); } }, closeTooltip(id) { Radzen.activeElement = null; var target = Radzen[id + 'target']; if (target) { target.removeAttribute('aria-describedby'); Radzen[id + 'target'] = null; } Radzen.closePopup(id); if (Radzen[id + 'delay']) { clearTimeout(Radzen[id + 'delay']); } if (Radzen[id + 'duration']) { clearTimeout(Radzen[id + 'duration']); } }, destroyDatePicker(id) { var el = document.getElementById(id); if (!el) return; var button = el.querySelector('.rz-datepicker-trigger'); if (button) { button.onclick = null; } var input = el.querySelector('.rz-inputtext'); if (input) { input.onclick = null; } }, createDatePicker(el, popupId, instance, callback) { if(!el) return; var handler = function (e, condition) { if (condition) { Radzen.togglePopup(e.currentTarget.parentNode, popupId, false, instance, callback, true, false); } }; var input = el.querySelector('.rz-inputtext'); var button = el.querySelector('.rz-datepicker-trigger'); if (button) { button.onclick = function (e) { handler(e, !e.currentTarget.classList.contains('rz-state-disabled') && (input ? !input.classList.contains('rz-readonly') : true)); }; } if (input) { input.onclick = function (e) { handler(e, e.currentTarget.classList.contains('rz-input-trigger') && !e.currentTarget.classList.contains('rz-readonly')); }; } }, findPopup: function (id) { var popups = []; for (var i = 0; i < document.body.children.length; i++) { if (document.body.children[i].id == id) { popups.push(document.body.children[i]); } } return popups; }, repositionPopup: function (parent, id) { var popup = document.getElementById(id); if (!popup) return; var rect = popup.getBoundingClientRect(); var parentRect = parent ? parent.getBoundingClientRect() : { top: 0, bottom: 0, left: 0, right: 0, width: 0, height: 0 }; if (/Edge/.test(navigator.userAgent)) { var scrollTop = document.body.scrollTop; } else { var scrollTop = document.documentElement.scrollTop; } var top = parentRect.bottom + scrollTop; if (top + rect.height > window.innerHeight + scrollTop && parentRect.top > rect.height) { top = parentRect.top - rect.height + scrollTop; } popup.style.top = top + 'px'; }, setPopupAriaExpanded: function (parent, id, expanded) { if (!parent || !id) return; var control = null; if (parent.getAttribute && parent.getAttribute('aria-controls') === id) { control = parent; } else if (parent.querySelector) { control = parent.querySelector('[aria-controls="' + id + '"]'); } if (!control && parent.getAttribute && parent.getAttribute('role') === 'combobox') { control = parent; } if (control) { control.setAttribute('aria-expanded', expanded ? 'true' : 'false'); } }, openPopup: function (parent, id, syncWidth, position, x, y, instance, callback, closeOnDocumentClick = true, autoFocusFirstElement = false, disableSmartPosition = false) { var popup = document.getElementById(id); if (!popup || popup && popup.style.display == 'block' && popup.classList.contains('rz-autocomplete-panel')) return; Radzen.activeElement = document.activeElement; var parentRect = parent ? parent.getBoundingClientRect() : { top: y || 0, bottom: 0, left: x || 0, right: 0, width: 0, height: 0 }; if (/Edge/.test(navigator.userAgent)) { var scrollLeft = document.body.scrollLeft; var scrollTop = document.body.scrollTop; } else { var scrollLeft = document.documentElement.scrollLeft; var scrollTop = document.documentElement.scrollTop; } var top = y ? y : parentRect.bottom; var left = x ? x : parentRect.left; if (syncWidth) { popup.style.width = parentRect.width + 'px'; if (!popup.style.minWidth) { popup.minWidth = true; popup.style.minWidth = parentRect.width + 'px'; } } if (window.chrome) { var closestFrozenCell = popup.closest('.rz-frozen-cell'); if (closestFrozenCell) { Radzen[id + 'FZL'] = { cell: closestFrozenCell, left: closestFrozenCell.style.left }; closestFrozenCell.style.left = ''; } } popup.style.display = 'block'; popup.style.visibility = 'hidden'; popup.onanimationend = null; popup.classList.remove("rz-close"); Radzen.setPopupAriaExpanded(parent, id, true); var rect = popup.getBoundingClientRect(); rect.width = x ? rect.width + 20 : rect.width; rect.height = y ? rect.height + 20 : rect.height; var isRTL = Radzen.isRTL(popup); if (isRTL && parent && (!position || position == 'bottom' || position == 'top')) { left = parentRect.right - rect.width; } var smartPosition = !position || position == 'bottom'; if (smartPosition && top + rect.height > window.innerHeight && parentRect.top > rect.height) { if (disableSmartPosition !== true) { top = parentRect.top - rect.height; } if (position) { top = top - 40; var tooltipContent = popup.children[0]; var tooltipContentClassName = 'rz-' + position + '-tooltip-content'; if (tooltipContent.classList.contains(tooltipContentClassName)) { tooltipContent.classList.remove(tooltipContentClassName); tooltipContent.classList.add('rz-top-tooltip-content'); position = 'top'; if (instance && callback) { try { instance.invokeMethodAsync(callback, position); } catch { } } } } } if (smartPosition && left + rect.width > window.innerWidth && window.innerWidth > rect.width) { left = !position ? window.innerWidth - rect.width : rect.left; if (position) { top = y || parentRect.top; var tooltipContent = popup.children[0]; var tooltipContentClassName = 'rz-' + position + '-tooltip-content'; if (tooltipContent.classList.contains(tooltipContentClassName)) { tooltipContent.classList.remove(tooltipContentClassName); tooltipContent.classList.add('rz-left-tooltip-content'); position = 'left'; if (instance && callback) { try { instance.invokeMethodAsync(callback, position); } catch { } } } } } if (smartPosition && isRTL && left < 0 && window.innerWidth > rect.width) { left = !position ? 0 : rect.left; if (position) { top = y || parentRect.top; var tooltipContent = popup.children[0]; var tooltipContentClassName = 'rz-' + position + '-tooltip-content'; if (tooltipContent.classList.contains(tooltipContentClassName)) { tooltipContent.classList.remove(tooltipContentClassName); tooltipContent.classList.add('rz-right-tooltip-content'); position = 'right'; if (instance && callback) { try { instance.invokeMethodAsync(callback, position); } catch { } } } } } if (smartPosition) { if (position) { top = top + 20; } } if (position == 'left') { left = parentRect.left - rect.width - 5; top = parentRect.top; } if (position == 'right') { left = parentRect.right + 10; top = parentRect.top; } if (position == 'top') { top = parentRect.top - rect.height + 5; left = isRTL ? parentRect.right - rect.width : parentRect.left; } if (disableSmartPosition && x != null && y != null) { left = x + 10; top = y + 10; var tooltipContent = popup.children[0]; var tooltipContentClassName = 'rz-bottom-tooltip-content'; if (tooltipContent.classList.contains(tooltipContentClassName)) { tooltipContent.classList.remove(tooltipContentClassName); } if (left + rect.width > window.innerWidth && window.innerWidth > rect.width) { top = parentRect.top - rect.height; } if (left + rect.width > window.innerWidth && window.innerWidth > rect.width) { left = window.innerWidth - rect.width; } } popup.style.zIndex = 2000; popup.style.left = left + scrollLeft + 'px'; popup.style.top = top + scrollTop + 'px'; if (!popup.classList.contains('rz-overlaypanel')) { popup.classList.add('rz-popup'); } Radzen[id] = function (e) { var lastPopup = Radzen.popups && Radzen.popups[Radzen.popups.length - 1]; var currentPopup = lastPopup != null && document.getElementById(lastPopup.id) || popup; if (lastPopup) { currentPopup.instance = lastPopup.instance; currentPopup.callback = lastPopup.callback; currentPopup.parent = lastPopup.parent; } if(e.type == 'contextmenu' || !e.target || !closeOnDocumentClick) return; if (!/Android/i.test(navigator.userAgent) && !['input', 'textarea'].includes(document.activeElement ? document.activeElement.tagName.toLowerCase() : '') && e.type == 'resize') { Radzen.closePopup(currentPopup.id, currentPopup.instance, currentPopup.callback, e); return; } var closestLink = e.target.closest && (e.target.closest('.rz-link') || e.target.closest('.rz-navigation-item-link')); if (e.type == 'resize' && !/Android/i.test(navigator.userAgent)) { if (closestLink && closestLink.closest && closestLink.closest('a') && e.button == 0) { closestLink.closest('a').click(); Radzen.closeAllPopups(); } else { Radzen.closeAllPopups(); } } if (currentPopup.parent) { if (e.type == 'mousedown' && !currentPopup.parent.contains(e.target) && !currentPopup.contains(e.target)) { Radzen.closePopup(currentPopup.id, currentPopup.instance, currentPopup.callback, e); } } else { if (e.target.nodeType && !currentPopup.contains(e.target)) { Radzen.closePopup(currentPopup.id, currentPopup.instance, currentPopup.callback, e); } } }; if (!Radzen.popups) { Radzen.popups = []; } Radzen.popups.push({ id, instance, callback, parent }); document.body.appendChild(popup); if (!position) { var popupRect = popup.getBoundingClientRect(); // Clamp into the viewport. If the popup is smaller than the viewport, shift it // so its right/bottom edge fits. If it is larger than the viewport, pin the // top/left corner to the viewport origin so content is at least reachable // (instead of leaving it positioned off-screen at the anchor). if (popupRect.right > window.innerWidth) { popup.style.left = Math.max(scrollLeft, window.innerWidth - popupRect.width + scrollLeft) + 'px'; } if (popupRect.bottom > window.innerHeight) { popup.style.top = Math.max(scrollTop, window.innerHeight - popupRect.height + scrollTop) + 'px'; } } popup.style.visibility = ''; popup.classList.add("rz-open"); document.removeEventListener('mousedown', Radzen[id]); document.addEventListener('mousedown', Radzen[id]); window.removeEventListener('resize', Radzen[id]); window.addEventListener('resize', Radzen[id]); var p = parent; while (p && p != document.body) { if (p.scrollWidth > p.clientWidth || p.scrollHeight > p.clientHeight) { p.removeEventListener('scroll', Radzen.closeAllPopups); p.addEventListener('scroll', Radzen.closeAllPopups); } p = p.parentElement; } if (!parent) { document.removeEventListener('contextmenu', Radzen[id]); document.addEventListener('contextmenu', Radzen[id]); } if (autoFocusFirstElement) { setTimeout(function () { popup.removeEventListener('keydown', Radzen.focusTrap); popup.addEventListener('keydown', Radzen.focusTrap); var focusable = Radzen.getFocusableElements(popup); var firstFocusable = focusable[0]; if (firstFocusable) { firstFocusable.focus(); } }, 200); } if (popup.__escapeHandler) { popup.removeEventListener('keydown', popup.__escapeHandler, true); } popup.__escapeHandler = function (e) { if (e.key === 'Escape' || e.key === 'Esc') { Radzen.closePopup(id, instance, callback, e); } if (e.key === 'Tab' && parent && (popup.classList.contains('rz-dropdown-panel') || popup.classList.contains('rz-multiselect-panel'))) { e.preventDefault(); } if (e.key === 'Tab' && !e.shiftKey) { var timepicker = popup.querySelector('.rz-timepicker'); if (timepicker) { var focusable = Radzen.getFocusableElements(timepicker); var last = focusable[focusable.length - 1]; if (last && document.activeElement === last) { Radzen.closePopup(id, instance, callback, e); } } } }; popup.addEventListener('keydown', popup.__escapeHandler, true); }, closeAllPopups: function (e, id) { if (!Radzen.popups) return; var el = e && e.target || id && documentElement.getElementById(id); var popups = Radzen.popups; for (var i = 0; i < popups.length; i++) { var p = popups[i]; var closestPopup = el && el.closest && (el.closest('.rz-popup') || el.closest('.rz-overlaypanel')); if (closestPopup && closestPopup != p) { return; } Radzen.closePopup(p.id, p.instance, p.callback, e); } Radzen.popups = []; }, closePopup: function (id, instance, callback, e, preventFocusRestore) { var popup = document.getElementById(id); if (!popup) return; var popupInfo = (Radzen.popups || []).find(function (p) { return p.id === id; }); if (popupInfo && popupInfo.parent) { Radzen.setPopupAriaExpanded(popupInfo.parent, id, false); var combobox = popupInfo.parent.closest('[role="combobox"]'); if (combobox) { combobox.removeAttribute('aria-activedescendant'); } } if (popup.style.display == 'none') { var popups = Radzen.findPopup(id); if (popups.length > 1) { for (var i = 0; i < popups.length; i++) { if (popups[i].style.display == 'none') { popups[i].parentNode.removeChild(popups[i]); } else { popup = popups[i]; } } } else { return; } } if (popup) { if (popup.minWidth) { popup.style.minWidth = ''; } if (window.chrome && Radzen[id + 'FZL']) { Radzen[id + 'FZL'].cell.style.left = Radzen[id + 'FZL'].left; Radzen[id + 'FZL'] = null; } popup.onanimationend = function () { popup.style.display = 'none'; popup.onanimationend = null; } popup.classList.add("rz-close"); popup.classList.remove("rz-open"); } if (popup && popup.__escapeHandler) { popup.removeEventListener('keydown', popup.__escapeHandler, true); delete popup.__escapeHandler; } document.removeEventListener('mousedown', Radzen[id]); window.removeEventListener('resize', Radzen[id]); Radzen[id] = null; if (instance && callback) { if (callback.includes('RadzenTooltip')) { try { instance.invokeMethodAsync(callback, null); } catch { } } else { try { instance.invokeMethodAsync(callback); } catch { } } } Radzen.popups = (Radzen.popups || []).filter(function (obj) { return obj.id !== id; }); if (!preventFocusRestore && (Radzen.activeElement && Radzen.activeElement == document.activeElement || Radzen.activeElement && document.activeElement == document.body || Radzen.activeElement && popup && popup.contains(document.activeElement) || Radzen.activeElement && document.activeElement && (document.activeElement.classList.contains('rz-dropdown-filter') || document.activeElement.classList.contains('rz-lookup-search-input') || document.activeElement.classList.contains('rz-multiselect-filter-container') || document.activeElement.closest('.rz-multiselect-filter-container') !== null))) { setTimeout(function () { if (e && e.target && e.target.tabIndex != -1) { Radzen.activeElement = e.target; } if (Radzen.activeElement) { Radzen.activeElement.focus(); } Radzen.activeElement = null; }, 100); } }, popupOpened: function (id) { var popup = document.getElementById(id); if (popup) { return popup.style.display != 'none'; } return false; }, togglePopup: function (parent, id, syncWidth, instance, callback, closeOnDocumentClick = true, autoFocusFirstElement = false) { var popup = document.getElementById(id); if (!popup) return; if (popup.style.display == 'block') { Radzen.closePopup(id, instance, callback); } else { Radzen.openPopup(parent, id, syncWidth, null, null, null, instance, callback, closeOnDocumentClick, autoFocusFirstElement); } }, destroyPopup: function (id) { var popup = document.getElementById(id); if (popup) { if (popup.__escapeHandler) { popup.removeEventListener('keydown', popup.__escapeHandler, true); delete popup.__escapeHandler; } popup.parentNode.removeChild(popup); } document.removeEventListener('mousedown', Radzen[id]); }, scrollDataGrid: function (e) { var scrollLeft = (e.target.scrollLeft ? '-' + e.target.scrollLeft : 0) + 'px'; e.target.previousElementSibling.style.marginLeft = scrollLeft; e.target.previousElementSibling.firstElementChild.style.paddingRight = e.target.clientHeight < e.target.scrollHeight ? (e.target.offsetWidth - e.target.clientWidth) + 'px' : '0px'; if (e.target.nextElementSibling) { e.target.nextElementSibling.style.marginLeft = scrollLeft; e.target.nextElementSibling.firstElementChild.style.paddingRight = e.target.clientHeight < e.target.scrollHeight ? (e.target.offsetWidth - e.target.clientWidth) + 'px' : '0px'; } for (var i = 0; i < document.body.children.length; i++) { if (document.body.children[i].classList.contains('rz-overlaypanel')) { document.body.children[i].style.display = 'none'; } } }, focusFirstFocusableElement: function (el) { var focusable = Radzen.getFocusableElements(el); if (!focusable || !focusable.length) return; var first = focusable[0]; if (first.classList.contains('rz-html-editor-content')) { var sel = window.getSelection(); var range = document.createRange(); range.setStart(first, 0); range.setEnd(first, 0); sel.removeAllRanges(); sel.addRange(range); first.focus(); } else { first.focus(); } }, openSideDialog: function (options) { setTimeout(function () { if (options.autoFocusFirstElement) { var dialogs = document.querySelectorAll('.rz-dialog-side-content'); if (dialogs.length == 0) return; var lastDialog = dialogs[dialogs.length - 1]; Radzen.focusFirstFocusableElement(lastDialog); } }, 500); }, createSideDialogResizer: function(handle, sideDialog, options) { const normalizeDir = (value) => { if (typeof value === 'string' && value.length) { return value.toLowerCase(); } if (typeof value === 'number') { const positions = ['right', 'left', 'top', 'bottom']; return positions[value] || 'right'; } return 'right'; }; const dir = normalizeDir(options?.position); let start = null; const onDown = (e) => { e.preventDefault(); start = {x: e.clientX, y: e.clientY, w: sideDialog.clientWidth, h: sideDialog.clientHeight}; document.addEventListener('pointermove', onMove); document.addEventListener('pointerup', onUp, {once: true}); document.addEventListener('pointercancel', onUp, {once: true}); }; const clamp = (v, min, max) => Math.max(min, Math.min(max, v)); const applyWidth = (w) => { sideDialog.style.width = Math.round(w) + 'px'; }; const applyHeight = (h) => { sideDialog.style.height = `${Math.round(h)}px`; }; const onMove = (e) => { if (!start) return; const dx = e.clientX - start.x; const dy = e.clientY - start.y; switch (dir) { case 'right': applyWidth(clamp(start.w - dx, options.minWidth, Infinity)); break; case 'left': applyWidth(clamp(start.w + dx, options.minWidth, Infinity)); break; case 'bottom': applyHeight(clamp(start.h - dy, options.minHeight, Infinity)); break; case 'top': applyHeight(clamp(start.h + dy, options.minHeight, Infinity)); break; } }; const onUp = (e) => { start = null; document.removeEventListener('pointermove', onMove); }; handle.addEventListener('pointerdown', onDown); return { dispose() { handle.removeEventListener('pointerdown', onDown); document.removeEventListener('pointermove', onMove); } }; }, openDialog: function (options, dialogService, dialog) { if (Radzen.closeAllPopups) { Radzen.closeAllPopups(); } Radzen.dialogService = dialogService; if ( document.documentElement.scrollHeight > document.documentElement.clientHeight ) { document.body.classList.add('no-scroll'); } setTimeout(function () { var dialogs = document.querySelectorAll('.rz-dialog-content'); if (dialogs.length == 0) return; var lastDialog = dialogs[dialogs.length - 1]; if (lastDialog) { lastDialog.options = options; lastDialog.removeEventListener('keydown', Radzen.focusTrap); lastDialog.addEventListener('keydown', Radzen.focusTrap); if (options.resizable) { dialog.offsetWidth = lastDialog.parentElement.offsetWidth; dialog.offsetHeight = lastDialog.parentElement.offsetHeight; var dialogResize = function (e) { if (!dialog) return; if (dialog.offsetWidth != e[0].target.offsetWidth || dialog.offsetHeight != e[0].target.offsetHeight) { dialog.offsetWidth = e[0].target.offsetWidth; dialog.offsetHeight = e[0].target.offsetHeight; dialog.invokeMethodAsync( 'RadzenDialog.OnResize', e[0].target.offsetWidth, e[0].target.offsetHeight ).catch(function () { }); } }; var resizeObserver = new ResizeObserver(dialogResize); resizeObserver.observe(lastDialog.parentElement); Radzen.dialogResizer = resizeObserver; } if (options.draggable) { var dialogTitle = lastDialog.parentElement.querySelector('.rz-dialog-titlebar'); if (dialogTitle) { Radzen[dialogTitle] = function (e) { var rect = lastDialog.parentElement.getBoundingClientRect(); var offsetX = e.clientX - rect.left; var offsetY = e.clientY - rect.top; var move = function (e) { var left = e.clientX - offsetX; var top = e.clientY - offsetY; lastDialog.parentElement.style.left = left + 'px'; lastDialog.parentElement.style.top = top + 'px'; try { dialog.invokeMethodAsync('RadzenDialog.OnDrag', top, left); } catch { } }; var stop = function () { document.removeEventListener('mousemove', move); document.removeEventListener('mouseup', stop); }; document.addEventListener('mousemove', move); document.addEventListener('mouseup', stop); }; dialogTitle.addEventListener('mousedown', Radzen[dialogTitle]); } } if (options.autoFocusFirstElement) { Radzen.focusFirstFocusableElement(lastDialog); } } }, 500); document.removeEventListener('keydown', Radzen.closePopupOrDialog); if (options.closeDialogOnEsc) { document.addEventListener('keydown', Radzen.closePopupOrDialog); } }, closeDialog: function () { if (Radzen.dialogResizer && typeof Radzen.dialogResizer.disconnect === 'function') { Radzen.dialogResizer.disconnect(); } Radzen.dialogResizer = null; document.body.classList.remove('no-scroll'); var dialogs = document.querySelectorAll('.rz-dialog-content'); var lastDialog = dialogs.length && dialogs[dialogs.length - 1]; if (lastDialog) { var dialogTitle = lastDialog.parentElement.querySelector('.rz-dialog-titlebar'); if (dialogTitle) { dialogTitle.removeEventListener('mousedown', Radzen[dialogTitle]); Radzen[dialogTitle] = null; delete Radzen[dialogTitle]; } } if (dialogs.length <= 1) { document.removeEventListener('keydown', Radzen.closePopupOrDialog); delete Radzen.dialogService; } }, disableKeydown: function (e) { e = e || window.event; e.preventDefault(); }, getFocusableElements: function (element) { return [...element.querySelectorAll('a, button, input, textarea, select, details, iframe, embed, object, summary, dialog, audio[controls], video[controls], [contenteditable], [tabindex]')] .filter(el => { if (!el || el.hasAttribute('disabled') || el.offsetParent === null) return false; // If this is inside a .rz-html-editor with tabindex="-1", skip it var editorParent = el.closest('.rz-html-editor'); if (editorParent && editorParent.hasAttribute('tabindex') && editorParent.tabIndex === -1) return false; else if (editorParent) return true; return el.tabIndex > -1; }); }, focusTrap: function (e) { e = e || window.event; var isTab = false; if ("key" in e) { isTab = (e.key === "Tab"); } else { isTab = (e.keyCode === 9); } if (isTab) { var focusable = Radzen.getFocusableElements(e.currentTarget); var firstFocusable = focusable[0]; var lastFocusable = focusable[focusable.length - 1]; if (firstFocusable && lastFocusable && e.shiftKey && document.activeElement === firstFocusable) { e.preventDefault(); lastFocusable.focus(); } else if (firstFocusable && lastFocusable && !e.shiftKey && document.activeElement === lastFocusable) { e.preventDefault(); firstFocusable.focus(); } } }, closePopupOrDialog: function (e) { e = e || window.event; var isEscape = false; if ("key" in e) { isEscape = (e.key === "Escape" || e.key === "Esc"); } else { isEscape = (e.keyCode === 27); } if (isEscape && Radzen.dialogService) { var popups = document.querySelectorAll('.rz-popup,.rz-overlaypanel'); for (var i = 0; i < popups.length; i++) { if (popups[i].style.display != 'none') { return; } } var dialogs = document.querySelectorAll('.rz-dialog-content'); if (dialogs.length == 0) return; var lastDialog = dialogs[dialogs.length - 1]; if (lastDialog && lastDialog.options && lastDialog.options.closeDialogOnEsc) { try { Radzen.dialogService.invokeMethodAsync('DialogService.TryClose', null).then(function(closed) { if (closed && dialogs.length <= 1) { document.removeEventListener('keydown', Radzen.closePopupOrDialog); delete Radzen.dialogService; var layout = document.querySelector('.rz-layout'); if (layout) { layout.removeEventListener('keydown', Radzen.disableKeydown); } } }); } catch (e) { } } } }, getNumericValue: function (arg) { var el = arg instanceof Element || arg instanceof HTMLDocument ? arg : document.getElementById(arg); return el ? Radzen.getInputValue(el.children[0]) : null; }, getInputValue: function (arg) { var input = arg instanceof Element || arg instanceof HTMLDocument ? arg : document.getElementById(arg); return input && input.value != '' ? input.value : null; }, setInputValue: function (arg, value) { var input = arg instanceof Element || arg instanceof HTMLDocument ? arg : document.getElementById(arg); if (input) { input.value = value; } }, blur: function (el, e) { if (el) { e.preventDefault(); el.dispatchEvent(new KeyboardEvent('keydown', { bubbles: true, cancelable: true, keyCode: 9 })); } }, readFileAsBase64: function (fileInput, maxFileSize, maxWidth, maxHeight) { var calculateWidthAndHeight = function (img) { var width = img.width; var height = img.height; // Change the resizing logic if (width > height) { if (width > maxWidth) { height = height * (maxWidth / width); width = maxWidth; } } else { if (height > maxHeight) { width = width * (maxHeight / height); height = maxHeight; } } return { width, height }; }; var readAsDataURL = function (fileInput) { return new Promise(function (resolve, reject) { var reader = new FileReader(); reader.onerror = function () { reader.abort(); reject('Error reading file.'); }; reader.addEventListener( 'load', function () { if (fileInput.files[0] && fileInput.files[0].type.includes('image') && maxWidth > 0 && maxHeight > 0) { var img = document.createElement("img"); img.onload = function (event) { // Dynamically create a canvas element var canvas = document.createElement("canvas"); var res = calculateWidthAndHeight(img); canvas.width = res.width; canvas.height = res.height; var ctx = canvas.getContext("2d"); ctx.drawImage(img, 0, 0, res.width, res.height); resolve(canvas.toDataURL(fileInput.type)); } img.src = reader.result; } else { resolve(reader.result); } }, false ); var file = fileInput.files[0]; if (!file) return; if (file.size <= maxFileSize) { reader.readAsDataURL(file); } else { reject('File too large.'); } }); }; return readAsDataURL(fileInput); }, toggleMenuItem: function (target, event, defaultActive, clickToOpen) { var item = target.closest('.rz-navigation-item'); var active = defaultActive != undefined ? defaultActive : !item.classList.contains('rz-navigation-item-active'); function toggle(active) { item.classList.toggle('rz-navigation-item-active', active); target.classList.toggle('rz-navigation-item-wrapper-active', active); var children = item.querySelector('.rz-navigation-menu'); if (children) { item.setAttribute('aria-expanded', active); if (active) { children.onanimationend = null; children.style.display = ''; children.classList.add('rz-open'); children.classList.remove('rz-close'); var isRtl = getComputedStyle(item).direction === 'rtl'; var el = item.parentElement; var scrollParent = null; while (el && el !== document.body) { var s = getComputedStyle(el); if (s.overflowX === 'auto' || s.overflowX === 'scroll' || s.overflowX === 'hidden') { scrollParent = el; break; } el = el.parentElement; } if (children.hasAttribute('data-flyout')) { children.removeAttribute('data-flyout-flip'); var childRect = children.getBoundingClientRect(); var itemRect = item.getBoundingClientRect(); if (isRtl) { var leftBoundary = scrollParent ? scrollParent.getBoundingClientRect().left : 0; if (itemRect.left - childRect.width < leftBoundary) { children.setAttribute('data-flyout-flip', ''); } } else { var rightBoundary = scrollParent ? scrollParent.getBoundingClientRect().right : document.documentElement.clientWidth; if (itemRect.right + childRect.width > rightBoundary) { children.setAttribute('data-flyout-flip', ''); } } } // Shift dropdown left/right if it overflows the scroll parent or viewport children.style.insetInlineStart = children.style.insetInlineStart || ''; var childRect = children.getBoundingClientRect(); var rightBoundary = scrollParent ? scrollParent.getBoundingClientRect().right : document.documentElement.clientWidth; var leftBoundary = scrollParent ? scrollParent.getBoundingClientRect().left : 0; if (!isRtl && childRect.right > rightBoundary) { var offset = parseFloat(children.style.insetInlineStart) || 0; children.style.insetInlineStart = (offset + rightBoundary - childRect.right) + 'px'; } else if (isRtl && childRect.left < leftBoundary) { var offset = parseFloat(children.style.insetInlineStart) || 0; children.style.insetInlineStart = (offset + leftBoundary - childRect.left) + 'px'; } } else { children.onanimationend = function () { children.style.display = 'none'; children.style.insetInlineStart = ''; children.onanimationend = null; } children.classList.remove('rz-open'); children.classList.add('rz-close'); } } var icon = item.querySelector('.rz-navigation-item-icon-children'); if (icon) { icon.classList.toggle('rz-state-expanded', active); icon.classList.toggle('rz-state-collapsed', !active); } } if (clickToOpen === false && item.parentElement && item.parentElement.closest('.rz-navigation-item') && !defaultActive) { return; }; toggle(active); document.removeEventListener('click', target.clickHandler); target.clickHandler = function (event) { if (item.contains(event.target)) { var child = event.target.closest('.rz-navigation-item'); if (child && child.querySelector('.rz-navigation-menu')) { return; } } toggle(false); } document.addEventListener('click', target.clickHandler); }, destroyChart: function (ref) { if(!ref) return; ref.removeEventListener('mouseleave', ref.mouseLeaveHandler); delete ref.mouseLeaveHandler; ref.removeEventListener('mouseenter', ref.mouseEnterHandler); delete ref.mouseEnterHandler; ref.removeEventListener('mousemove', ref.mouseMoveHandler); delete ref.mouseMoveHandler; ref.removeEventListener('click', ref.clickHandler); delete ref.clickHandler; this.destroyResizable(ref); }, destroyGauge: function (ref) { if (ref._gaugeRTLObserver) { ref._gaugeRTLObserver.disconnect(); delete ref._gaugeRTLObserver; } this.destroyResizable(ref); }, destroyResizable: function (ref) { if (ref.resizeObserver) { ref.resizeObserver.disconnect(); delete ref.resizeObserver; } if (ref.resizeHandler) { window.removeEventListener('resize', ref.resizeHandler); delete ref.resizeHandler; } }, createResizable: function (ref, instance) { ref.resizeHandler = function () { var rect = ref.getBoundingClientRect(); try { instance.invokeMethodAsync('Resize', rect.width, rect.height); } catch { } }; if (window.ResizeObserver) { ref.resizeObserver = new ResizeObserver(ref.resizeHandler); ref.resizeObserver.observe(ref); } else { window.addEventListener('resize', ref.resizeHandler); } var rect = ref.getBoundingClientRect(); return {width: rect.width, height: rect.height}; }, createChart: function (ref, instance) { var inside = false; ref.mouseMoveHandler = this.throttle(function (e) { if (inside) { var rect = ref.getBoundingClientRect(); var x = e.clientX - rect.left; var y = e.clientY - rect.top; try { instance.invokeMethodAsync('MouseMove', x, y); } catch { } } }, 100); ref.mouseEnterHandler = function () { inside = true; }; ref.mouseLeaveHandler = function (e) { if (e.relatedTarget && (e.relatedTarget.matches('.rz-chart-tooltip') || e.relatedTarget.closest('.rz-chart-tooltip'))) { return; } inside = false; try { instance.invokeMethodAsync('MouseMove', -1, -1); } catch { } }; ref.clickHandler = function (e) { var rect = ref.getBoundingClientRect(); var x = e.clientX - rect.left; var y = e.clientY - rect.top; if (!e.target.closest('.rz-marker') && !e.target.closest('.rz-legend-item')) { try { instance.invokeMethodAsync('Click', x, y); } catch { } } }; ref.addEventListener('mouseenter', ref.mouseEnterHandler); ref.addEventListener('mouseleave', ref.mouseLeaveHandler); ref.addEventListener('mousemove', ref.mouseMoveHandler); ref.addEventListener('click', ref.clickHandler); return this.createResizable(ref, instance); }, createGauge: function (ref, instance) { var result = this.createResizable(ref, instance); ref._gaugeRTLObserver = new MutationObserver(function () { try { instance.invokeMethodAsync('SetRTL', document.documentElement.dir === 'rtl'); } catch (e) { } }); ref._gaugeRTLObserver.observe(document.documentElement, { attributes: true, attributeFilter: ['dir'] }); try { instance.invokeMethodAsync('SetRTL', document.documentElement.dir === 'rtl'); } catch (e) { } return result; }, innerHTML: function (ref, value) { if (value != undefined) { if (ref != null) { ref.innerHTML = value; } } else { return ref.innerHTML; } }, execCommand: function (ref, name, value) { if (document.activeElement != ref && ref) { ref.focus(); } document.execCommand(name, false, value); return this.queryCommands(ref); }, queryCommands: function (ref) { return { html: ref != null ? ref.innerHTML : null, fontName: document.queryCommandValue('fontName'), fontSize: document.queryCommandValue('fontSize'), formatBlock: document.queryCommandValue('formatBlock'), bold: document.queryCommandState('bold'), underline: document.queryCommandState('underline'), justifyRight: document.queryCommandState('justifyRight'), justifyLeft: document.queryCommandState('justifyLeft'), justifyCenter: document.queryCommandState('justifyCenter'), justifyFull: document.queryCommandState('justifyFull'), italic: document.queryCommandState('italic'), strikeThrough: document.queryCommandState('strikeThrough'), superscript: document.queryCommandState('superscript'), subscript: document.queryCommandState('subscript'), unlink: document.queryCommandEnabled('unlink'), undo: document.queryCommandEnabled('undo'), redo: document.queryCommandEnabled('redo') }; }, mediaQueries: {}, mediaQuery: function(query, instance) { if (instance) { function callback(event) { try { instance.invokeMethodAsync('OnChange', event.matches); } catch { } }; var query = matchMedia(query); this.mediaQueries[instance._id] = function() { query.removeListener(callback); } query.addListener(callback); return query.matches; } else { instance = query; if (this.mediaQueries[instance._id]) { this.mediaQueries[instance._id](); delete this.mediaQueries[instance._id]; } } }, createEditor: function (ref, uploadUrl, paste, instance, shortcuts) { ref.inputListener = function () { try { instance.invokeMethodAsync('OnChange', ref.innerHTML); } catch { } }; ref.keydownListener = function (e) { var key = ''; if (e.ctrlKey || e.metaKey) { key += 'Ctrl+'; } if (e.altKey) { key += 'Alt+'; } if (e.shiftKey) { key += 'Shift+'; } key += e.code.replace('Key', '').replace('Digit', '').replace('Numpad', ''); if (shortcuts.includes(key)) { e.preventDefault(); try { instance.invokeMethodAsync('ExecuteShortcutAsync', key); } catch { } } }; ref.clickListener = function (e) { if (e.target) { if (e.target.matches('a,button')) { e.preventDefault(); } for (var img of ref.querySelectorAll('img.rz-state-selected')) { img.classList.remove('rz-state-selected'); } if (e.target.matches('img')) { e.target.classList.add('rz-state-selected'); var range = document.createRange(); range.selectNode(e.target); getSelection().removeAllRanges(); getSelection().addRange(range); } } } ref.selectionChangeListener = function () { if (document.activeElement == ref) { try { instance.invokeMethodAsync('OnSelectionChange'); } catch { } } }; ref.handleInsert = function (e, transfer, hasDelegate) { var hasFiles = transfer.files.length > 0; var hasHtml = transfer.types.indexOf('text/html') > -1; var hasText = transfer.types.indexOf('text/plain') > -1; if (hasFiles && !hasHtml && !hasText) { for (const file of transfer.files) { ref.handleFileInsert(e, file, hasDelegate); } } else if (hasDelegate) { ref.handleTextInsert(e, transfer); } }; ref.handleFileInsert = function (event, file, hasDelegate) { event.preventDefault(); if (uploadUrl) { var xhr = new XMLHttpRequest(); var data = new FormData(); data.append("file", file); xhr.onreadystatechange = function (e) { if (xhr.readyState === XMLHttpRequest.DONE) { var status = xhr.status; if (status === 0 || (status >= 200 && status < 400)) { var result = JSON.parse(xhr.responseText); var html = ''; if (hasDelegate) { try { instance.invokeMethodAsync('OnPaste', html) .then(function (html) { document.execCommand("insertHTML", false, html); }); } catch { } } else { document.execCommand("insertHTML", false, ''); } try { instance.invokeMethodAsync('OnUploadComplete', xhr.responseText); } catch { } } else { try { instance.invokeMethodAsync('OnError', xhr.responseText); } catch { } } } } try { instance.invokeMethodAsync('GetHeaders').then(function (headers) { xhr.open('POST', uploadUrl, true); for (var name in headers) { xhr.setRequestHeader(name, headers[name]); } xhr.send(data); }); } catch { } } else { var reader = new FileReader(); reader.onload = function (e) { var html = ''; if (hasDelegate) { try { instance.invokeMethodAsync('OnPaste', html) .then(function (html) { document.execCommand("insertHTML", false, html); }); } catch { } } else { document.execCommand("insertHTML", false, html); } }; reader.readAsDataURL(file); } } ref.handleTextInsert = function (e, transfer) { e.preventDefault(); var data = transfer.getData('text/html') || transfer.getData('text/plain'); const startMarker = ""; const endMarker = ""; const startIndex = data.indexOf(startMarker); const endIndex = data.indexOf(endMarker); // check if the pasted data contains fragment markers if (startIndex != -1 || endIndex != -1 || endIndex > startIndex) { // only paste the fragment data = data.substring(startIndex + startMarker.length, endIndex).trim(); } try { instance.invokeMethodAsync('OnPaste', data) .then(ref.focus()) .then(function (html) { document.execCommand("insertHTML", false, html); }); } catch { } } ref.pasteListener = function (e) { ref.handleInsert(e, e.clipboardData, paste); }; ref.dropListener = function (e) { ref.handleInsert(e, e.dataTransfer, paste); }; ref.addEventListener('input', ref.inputListener); ref.addEventListener('paste', ref.pasteListener); ref.addEventListener('drop', ref.dropListener); ref.addEventListener('keydown', ref.keydownListener); ref.addEventListener('click', ref.clickListener); document.addEventListener('selectionchange', ref.selectionChangeListener); document.execCommand('styleWithCSS', false, true); }, saveSelection: function (ref) { if (!ref) return; var selection = getSelection(); if (selection.rangeCount > 0) { var range = selection.getRangeAt(0); if (ref.contains(range.commonAncestorContainer)) { ref.range = range; } } }, restoreSelection: function (ref) { if (!ref) return; var range = ref.range; if (range) { delete ref.range; if(ref) { ref.focus(); } var selection = getSelection(); selection.removeAllRanges(); selection.addRange(range); } }, selectionAttributes: function (selector, attributes, container) { var selection = getSelection(); var range = selection.rangeCount > 0 && selection.getRangeAt(0); var parent = range && range.commonAncestorContainer; var img = container.querySelector('img.rz-state-selected'); var inside = img && selector == 'img'; while (parent) { if (parent == container) { inside = true; break; } parent = parent.parentNode; } if (!inside) { return {}; } var target = selection.focusNode; var innerHTML; if (img && selector == 'img') { target = img; } else if (target) { if (target.nodeType == 3) { target = target.parentElement; } else { if (img) { target = target.childNodes[range.startOffset] } else { target = target.childNodes[selection.focusOffset]; } if (target) { innerHTML = target.outerHTML; } } if (target && target.matches && !target.matches(selector)) { target = target.closest(selector); } } return attributes.reduce(function (result, name) { if (target) { result[name] = name == 'innerText' ? target[name] : target.getAttribute(name); } return result; }, { innerText: selection.toString(), innerHTML: innerHTML }); }, destroyEditor: function (ref) { if (ref) { ref.removeEventListener('input', ref.inputListener); ref.removeEventListener('paste', ref.pasteListener); ref.removeEventListener('drop', ref.dropListener); ref.removeEventListener('keydown', ref.keydownListener); ref.removeEventListener('click', ref.clickListener); document.removeEventListener('selectionchange', ref.selectionChangeListener); } }, startDrag: function (ref, instance, handler) { if (!ref) { return { left: 0, top: 0, width: 0, height: 0 }; } ref.mouseMoveHandler = function (e) { try { instance.invokeMethodAsync(handler, { clientX: e.clientX, clientY: e.clientY }); } catch { } }; ref.touchMoveHandler = function (e) { if (e.targetTouches[0] && ref.contains(e.targetTouches[0].target)) { try { instance.invokeMethodAsync(handler, { clientX: e.targetTouches[0].clientX, clientY: e.targetTouches[0].clientY }); } catch { } } }; ref.mouseUpHandler = function (e) { Radzen.endDrag(ref); }; document.addEventListener('mousemove', ref.mouseMoveHandler); document.addEventListener('mouseup', ref.mouseUpHandler); document.addEventListener('touchmove', ref.touchMoveHandler, { passive: true, capture: true }) document.addEventListener('touchend', ref.mouseUpHandler, { passive: true }); return Radzen.clientRect(ref); }, submit: function (form) { form.submit(); }, clientRect: function (arg) { var el = arg instanceof Element || arg instanceof HTMLDocument ? arg : document.getElementById(arg); var rect = el.getBoundingClientRect(); return { left: rect.left, top: rect.top, width: rect.width, height: rect.height }; }, outerHTML: function (arg) { var el = arg instanceof Element || arg instanceof HTMLDocument ? arg : document.getElementById(arg); return el ? el.outerHTML : ''; }, endDrag: function (ref) { document.removeEventListener('mousemove', ref.mouseMoveHandler); document.removeEventListener('mouseup', ref.mouseUpHandler); document.removeEventListener('touchmove', ref.touchMoveHandler) document.removeEventListener('touchend', ref.mouseUpHandler); }, startColumnReorder: function(id, gridId, gridRef) { var grid = document.getElementById(gridId); var el = document.getElementById(id + '-drag'); Radzen[id + 'cell'] = el.parentNode.parentNode; var visual = document.createElement("th"); visual.className = Radzen[id + 'cell'].className + ' rz-column-draggable'; visual.style = Radzen[id + 'cell'].style; visual.style.display = 'none'; visual.style.position = 'absolute'; visual.style.height = Radzen[id + 'cell'].offsetHeight + 'px'; visual.style.width = Radzen[id + 'cell'].offsetWidth + 'px'; visual.style.zIndex = 2000; visual.style.pointerEvents = 'none'; visual.innerHTML = Radzen[id + 'cell'].firstChild.outerHTML; visual.id = id + 'visual'; document.body.appendChild(visual); var resizers = Radzen[id + 'cell'].parentNode.querySelectorAll('.rz-column-resizer'); for (let i = 0; i < resizers.length; i++) { resizers[i].style.display = 'none'; } Radzen[id + 'lastTouchX'] = null; Radzen[id + 'lastTouchY'] = null; Radzen[id + 'end'] = function (e) { var triggeredByTouch = e && (e.type === 'touchend' || e.type === 'touchcancel'); var touchX = Radzen[id + 'lastTouchX']; var touchY = Radzen[id + 'lastTouchY']; if (triggeredByTouch && e.changedTouches && e.changedTouches[0]) { touchX = e.changedTouches[0].clientX; touchY = e.changedTouches[0].clientY; } var el = document.getElementById(id + 'visual'); if (el) { document.body.removeChild(el); var resizers = Radzen[id + 'cell'].parentNode.querySelectorAll('.rz-column-resizer'); for (let i = 0; i < resizers.length; i++) { resizers[i].style.display = 'block'; } } grid.removeEventListener('mousemove', Radzen[id + 'move']); grid.removeEventListener('touchmove', Radzen[id + 'touchmove']); grid.removeEventListener('click', Radzen[id + 'end']); document.removeEventListener('mouseup', Radzen[id + 'end']); document.removeEventListener('touchend', Radzen[id + 'end']); document.removeEventListener('touchcancel', Radzen[id + 'end']); Radzen[id + 'end'] = null; Radzen[id + 'move'] = null; Radzen[id + 'touchmove'] = null; Radzen[id + 'lastTouchX'] = null; Radzen[id + 'lastTouchY'] = null; if (triggeredByTouch && gridRef && touchX != null && touchY != null) { var target = document.elementFromPoint(touchX, touchY); if (target && grid.contains(target)) { var groupHeader = target.closest('.rz-group-header'); if (groupHeader && grid.contains(groupHeader)) { try { gridRef.invokeMethodAsync('RadzenGrid.OnColumnDropToGroup'); } catch { } return; } var th = target.closest('th[data-column-index]'); if (th && grid.contains(th)) { var columnIndex = parseInt(th.getAttribute('data-column-index'), 10); if (!isNaN(columnIndex)) { try { gridRef.invokeMethodAsync('RadzenGrid.OnColumnReorderEnded', columnIndex); } catch { } } } } } } grid.removeEventListener('click', Radzen[id + 'end']); grid.addEventListener('click', Radzen[id + 'end']); document.removeEventListener('mouseup', Radzen[id + 'end']); document.addEventListener('mouseup', Radzen[id + 'end']); document.removeEventListener('touchend', Radzen[id + 'end']); document.addEventListener('touchend', Radzen[id + 'end'], { passive: true }); document.removeEventListener('touchcancel', Radzen[id + 'end']); document.addEventListener('touchcancel', Radzen[id + 'end'], { passive: true }); Radzen[id + 'move'] = function (e) { var el = document.getElementById(id + 'visual'); if (el) { el.style.display = 'block'; if (/Edge/.test(navigator.userAgent)) { var scrollLeft = document.body.scrollLeft; var scrollTop = document.body.scrollTop; } else { var scrollLeft = document.documentElement.scrollLeft; var scrollTop = document.documentElement.scrollTop; } el.style.top = e.clientY + scrollTop + 10 + 'px'; el.style.left = e.clientX + scrollLeft + 10 + 'px'; } } grid.removeEventListener('mousemove', Radzen[id + 'move']); grid.addEventListener('mousemove', Radzen[id + 'move']); Radzen[id + 'touchmove'] = function (e) { if (e.touches && e.touches[0]) { Radzen[id + 'lastTouchX'] = e.touches[0].clientX; Radzen[id + 'lastTouchY'] = e.touches[0].clientY; Radzen[id + 'move']({ clientX: e.touches[0].clientX, clientY: e.touches[0].clientY }); if (e.cancelable) { e.preventDefault(); } } } grid.removeEventListener('touchmove', Radzen[id + 'touchmove']); grid.addEventListener('touchmove', Radzen[id + 'touchmove'], { passive: false }); }, stopColumnResize: function (id, grid, columnIndex) { var el = document.getElementById(id + '-resizer'); if(!el) return; var cell = el.parentNode.parentNode; if (!cell) return; if (Radzen[el]) { try { grid.invokeMethodAsync( 'RadzenGrid.OnColumnResized', columnIndex, cell.getBoundingClientRect().width ); } catch { } el.style.width = null; document.removeEventListener('mousemove', Radzen[el].mouseMoveHandler); document.removeEventListener('mouseup', Radzen[el].mouseUpHandler); document.removeEventListener('touchmove', Radzen[el].touchMoveHandler) document.removeEventListener('touchend', Radzen[el].mouseUpHandler); Radzen[el] = null; } }, updateFrozenColumnPositions: function(gridElement) { if (!gridElement) return; // Get frozen cell positions from the header row first, then apply to all rows var headerRow = gridElement.querySelector('thead tr'); if (!headerRow) return; var leftHeaderCells = headerRow.querySelectorAll('.rz-frozen-cell-left, .rz-frozen-cell-left-end, .rz-frozen-cell-left-inner'); var rightHeaderCells = headerRow.querySelectorAll('.rz-frozen-cell-right, .rz-frozen-cell-right-end, .rz-frozen-cell-right-inner'); // Calculate offsets from header widths var leftOffsets = []; var offset = 0; for (var i = 0; i < leftHeaderCells.length; i++) { leftOffsets.push(offset); offset += leftHeaderCells[i].getBoundingClientRect().width; } var rightOffsets = []; offset = 0; for (var i = rightHeaderCells.length - 1; i >= 0; i--) { rightOffsets[i] = offset; offset += rightHeaderCells[i].getBoundingClientRect().width; } // Apply offsets to all rows var rows = gridElement.querySelectorAll('tr'); for (var r = 0; r < rows.length; r++) { var row = rows[r]; var leftCells = row.querySelectorAll('.rz-frozen-cell-left, .rz-frozen-cell-left-end, .rz-frozen-cell-left-inner'); for (var i = 0; i < leftCells.length && i < leftOffsets.length; i++) { leftCells[i].style.setProperty('inset-inline-start', leftOffsets[i] + 'px'); } var rightCells = row.querySelectorAll('.rz-frozen-cell-right, .rz-frozen-cell-right-end, .rz-frozen-cell-right-inner'); for (var i = 0; i < rightCells.length && i < rightOffsets.length; i++) { rightCells[i].style.setProperty('inset-inline-end', rightOffsets[i] + 'px'); } } }, startColumnResize: function(id, grid, columnIndex, clientX) { var el = document.getElementById(id + '-resizer'); var cell = el.parentNode.parentNode; var col = document.getElementById(id + '-col'); var dataCol = document.getElementById(id + '-data-col'); var footerCol = document.getElementById(id + '-footer-col'); var isFrozen = cell.classList.contains('rz-frozen-cell'); var gridElement = isFrozen ? cell.closest('.rz-data-grid') : null; Radzen[el] = { clientX: clientX, width: cell.getBoundingClientRect().width, mouseUpHandler: function (e) { if (Radzen[el]) { try { grid.invokeMethodAsync( 'RadzenGrid.OnColumnResized', columnIndex, cell.getBoundingClientRect().width ); } catch { } el.style.width = null; document.removeEventListener('mousemove', Radzen[el].mouseMoveHandler); document.removeEventListener('mouseup', Radzen[el].mouseUpHandler); document.removeEventListener('touchmove', Radzen[el].touchMoveHandler) document.removeEventListener('touchend', Radzen[el].mouseUpHandler); Radzen[el] = null; } }, mouseMoveHandler: function (e) { if (Radzen[el]) { var widthFloat = (Radzen[el].width - (Radzen.isRTL(cell) ? -1 : 1) * (Radzen[el].clientX - e.clientX)); var minWidth = parseFloat(cell.style.minWidth || 0) var maxWidth = parseFloat(cell.style.maxWidth || 0) if (widthFloat < minWidth) { widthFloat = minWidth; } if (cell.style.maxWidth && widthFloat > maxWidth) { widthFloat = maxWidth; } var width = widthFloat + 'px'; if (cell) { cell.style.width = width; } if (col) { col.style.width = width; } if (dataCol) { dataCol.style.width = width; } if (footerCol) { footerCol.style.width = width; } if (gridElement) { Radzen.updateFrozenColumnPositions(gridElement); } } }, touchMoveHandler: function (e) { if (e.targetTouches[0]) { e.preventDefault(); Radzen[el].mouseMoveHandler(e.targetTouches[0]); } } }; el.style.width = "100%"; document.addEventListener('mousemove', Radzen[el].mouseMoveHandler); document.addEventListener('mouseup', Radzen[el].mouseUpHandler); document.addEventListener('touchmove', Radzen[el].touchMoveHandler, { passive: false }) document.addEventListener('touchend', Radzen[el].mouseUpHandler); }, startSplitterResize: function(id, splitter, paneId, paneNextId, orientation, clientPos, minValue, maxValue, minNextValue, maxNextValue) { var el = document.getElementById(id); var pane = document.getElementById(paneId); var paneNext = document.getElementById(paneNextId); var paneLength; var paneNextLength; var panePerc; var paneNextPerc; var isHOrientation=orientation == 'Horizontal'; var totalLength = 0.0; Array.from(el.children).forEach(element => { totalLength += isHOrientation ? element.getBoundingClientRect().width : element.getBoundingClientRect().height; }); if (pane) { paneLength = isHOrientation ? pane.getBoundingClientRect().width : pane.getBoundingClientRect().height; panePerc = (paneLength / totalLength * 100) + '%'; } if (paneNext) { paneNextLength = isHOrientation ? paneNext.getBoundingClientRect().width : paneNext.getBoundingClientRect().height; paneNextPerc = (paneNextLength / totalLength * 100) + '%'; } function ensurevalue(value) { if (!value) return null; value=value.trim().toLowerCase(); if (value.endsWith("%")) return totalLength*parseFloat(value)/100; if (value.endsWith("px")) return parseFloat(value); throw 'Invalid value'; } minValue=ensurevalue(minValue); maxValue=ensurevalue(maxValue); minNextValue=ensurevalue(minNextValue); maxNextValue=ensurevalue(maxNextValue); Radzen[el] = { clientPos: clientPos, panePerc: parseFloat(panePerc), paneNextPerc: isFinite(parseFloat(paneNextPerc)) ? parseFloat(paneNextPerc) : 0, paneLength: paneLength, paneNextLength: isFinite(paneNextLength) ? paneNextLength : 0, mouseUpHandler: function(e) { if (Radzen[el]) { try { splitter.invokeMethodAsync( 'RadzenSplitter.OnPaneResized', parseInt(pane.getAttribute('data-index')), parseFloat(pane.style.flexBasis), paneNext ? parseInt(paneNext.getAttribute('data-index')) : null, paneNext ? parseFloat(paneNext.style.flexBasis) : null ); } catch { } document.removeEventListener('pointerup', Radzen[el].mouseUpHandler); document.removeEventListener('pointermove', Radzen[el].mouseMoveHandler); el.removeEventListener('touchmove', preventDefaultAndStopPropagation); Radzen[el] = null; } }, mouseMoveHandler: function(e) { if (Radzen[el]) { try { splitter.invokeMethodAsync( 'RadzenSplitter.OnPaneResizing' ); } catch { } var spacePerc = Radzen[el].panePerc + Radzen[el].paneNextPerc; var spaceLength = Radzen[el].paneLength + Radzen[el].paneNextLength; var length = (Radzen[el].paneLength - (isHOrientation && Radzen.isRTL(e.target) ? -1 : 1) * (Radzen[el].clientPos - (isHOrientation ? e.clientX : e.clientY))); if (length > spaceLength) length = spaceLength; if (minValue && length < minValue) length = minValue; if (maxValue && length > maxValue) length = maxValue; if (paneNext) { var nextSpace=spaceLength-length; if (minNextValue && nextSpace < minNextValue) length = spaceLength-minNextValue; if (maxNextValue && nextSpace > maxNextValue) length = spaceLength+maxNextValue; } var perc = length / Radzen[el].paneLength; if (!isFinite(perc)) { perc = 1; Radzen[el].panePerc = 0.1; Radzen[el].paneLength =isHOrientation ? pane.getBoundingClientRect().width : pane.getBoundingClientRect().height; } var newPerc = Radzen[el].panePerc * perc; if (newPerc < 0) newPerc = 0; if (newPerc > 100) newPerc = 100; pane.style.flexBasis = newPerc + '%'; if (paneNext) paneNext.style.flexBasis = (spacePerc - newPerc) + '%'; } }, touchMoveHandler: function(e) { if (e.targetTouches[0]) { Radzen[el].mouseMoveHandler(e.targetTouches[0]); } } }; const preventDefaultAndStopPropagation = (ev) => { ev.preventDefault(); ev.stopPropagation(); }; document.addEventListener('pointerup', Radzen[el].mouseUpHandler); document.addEventListener('pointermove', Radzen[el].mouseMoveHandler); el.addEventListener('touchmove', preventDefaultAndStopPropagation, { passive: false }); }, resizeSplitter(id, e) { var el = document.getElementById(id); if (el && Radzen[el]) { Radzen[el].mouseMoveHandler(e); Radzen[el].mouseUpHandler(e); } }, openWaiting: function() { if (document.documentElement.scrollHeight > document.documentElement.clientHeight) { document.body.classList.add('no-scroll'); } if (Radzen.WaitingIntervalId != null) { clearInterval(Radzen.WaitingIntervalId); } setTimeout(function() { var timerObj = document.getElementsByClassName('rz-waiting-timer'); if (timerObj.length == 0) return; var timerStart = new Date().getTime(); Radzen.WaitingIntervalId = setInterval(function() { if (timerObj == null || timerObj[0] == null) { clearInterval(Radzen.WaitingIntervalId); } else { var time = new Date(new Date().getTime() - timerStart); timerObj[0].innerHTML = Math.floor(time / 1000) + "." + Math.floor((time % 1000) / 100); } }, 100); }, 100); }, closeWaiting: function() { document.body.classList.remove('no-scroll'); if (Radzen.WaitingIntervalId != null) { clearInterval(Radzen.WaitingIntervalId); Radzen.WaitingIntervalId = null; } }, toggleDictation: function (componentRef, language) { function start() { const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition; if (!SpeechRecognition) { return; } radzenRecognition = new SpeechRecognition(); radzenRecognition.componentRef = componentRef; radzenRecognition.continuous = true; if (language) { radzenRecognition.lang = language; } radzenRecognition.onresult = function (event) { if (event.results.length < 1) { return; } let current = event.results[event.results.length - 1][0] let result = current.transcript; try { componentRef.invokeMethodAsync("OnResult", result); } catch { } }; radzenRecognition.onend = function (event) { try { componentRef.invokeMethodAsync("StopRecording"); } catch { } radzenRecognition = null; }; radzenRecognition.start(); } if (radzenRecognition) { if (radzenRecognition.componentRef._id != componentRef._id) { radzenRecognition.addEventListener('end', start); } radzenRecognition.stop(); } else { start(); } }, openChartTooltip: function (chart, x, y, id, instance, callback) { Radzen.closeTooltip(id); var chartRect = chart.getBoundingClientRect(); x = Math.max(2, chartRect.left + x); y = Math.max(2, chartRect.top + y); Radzen.openPopup(chart, id, false, null, x, y, instance, callback, true, false, false); var popup = document.getElementById(id); if (!popup) { return; } var tooltipContent = popup.children[0]; var tooltipContentRect = tooltipContent.getBoundingClientRect(); var tooltipContentClassName = 'rz-top-chart-tooltip'; if (y - tooltipContentRect.height < 0) { tooltipContentClassName = 'rz-bottom-chart-tooltip'; } tooltipContent.classList.remove('rz-top-chart-tooltip'); tooltipContent.classList.remove('rz-bottom-chart-tooltip'); tooltipContent.classList.add(tooltipContentClassName); }, createScrollListener: function (ref, selectors, selector) { let currentSelector; const container = selector ? document.querySelector(selector) : document.documentElement; const elements = selectors.map(document.querySelector, document); let rafId = null; const scrollHandler = () => { if (rafId !== null) { return; } rafId = requestAnimationFrame(() => { rafId = null; const isHtml = !selector || container.tagName === 'HTML'; const threshold = isHtml ? 10 : container.getBoundingClientRect().top + 10; const atBottom = isHtml ? window.scrollY > 0 && (window.innerHeight + window.scrollY) >= document.documentElement.scrollHeight - 2 : container.scrollTop > 0 && (container.scrollTop + container.clientHeight) >= container.scrollHeight - 2; let match; if (atBottom) { for (let i = selectors.length - 1; i >= 0; i--) { if (elements[i]) { match = selectors[i]; break; } } } else { for (let i = elements.length - 1; i >= 0; i--) { const element = elements[i]; if (!element) { continue; } if (element.getBoundingClientRect().top <= threshold) { match = selectors[i]; break; } } } if (match !== currentSelector) { currentSelector = match; try { ref.invokeMethodAsync('ScrollIntoView', currentSelector); } catch { } } }); }; const scrollTarget = selector ? container : window; scrollTarget.addEventListener('scroll', scrollHandler, { passive: true }); window.addEventListener('resize', scrollHandler, { passive: true }); scrollHandler(); return { dispose() { scrollTarget.removeEventListener('scroll', scrollHandler); window.removeEventListener('resize', scrollHandler); } }; }, setTheme: function (href, wcagHref) { const theme = document.getElementById('radzen-theme-link'); if (theme && theme.href != href) { theme.href = href; } let wcagTheme = document.getElementById('radzen-wcag-theme-link'); if (!wcagTheme && wcagHref) { wcagTheme = document.createElement('link'); wcagTheme.id = 'radzen-wcag-theme-link'; wcagTheme.rel = 'stylesheet'; wcagTheme.href = wcagHref; theme.parentNode.insertBefore(wcagTheme, theme.nextSibling); } else if (wcagTheme && wcagTheme.href != wcagHref) { if (!wcagHref) { wcagTheme.parentNode.removeChild(wcagTheme); return; } else { wcagTheme.href = wcagHref; } } }, createDraggable: function(element, ref, onDragStart) { function handleDragStart(e) { e.dataTransfer.setData('', e.target.id); try { ref.invokeMethodAsync(onDragStart); } catch { } } element.draggable = true; element.addEventListener('dragstart', handleDragStart); return { dispose() { element.removeEventListener('dragstart', handleDragStart); } }; } }; Radzen.registerFabMenu = function(element, dotnet){ if(!element) return; if(element.__rzOutsideClickHandler){ document.removeEventListener('click', element.__rzOutsideClickHandler); delete element.__rzOutsideClickHandler; } const handler = function(e){ if(!element.contains(e.target)){ try { dotnet.invokeMethodAsync('CloseAsync'); } catch { } } }; element.__rzOutsideClickHandler = handler; document.addEventListener('click', handler); }; Radzen.unregisterFabMenu = function(element){ if(!element) return; const handler = element.__rzOutsideClickHandler; if(handler){ document.removeEventListener('click', handler); delete element.__rzOutsideClickHandler; } }; Radzen.chatIsNearBottom = function(container, threshold) { if (!container) return true; return container.scrollHeight - container.scrollTop - container.clientHeight <= (threshold || 50); }; Radzen.chatScrollToBottom = function(container) { if (!container) return; container.scrollTop = container.scrollHeight; };