|
10 | 10 |
|
11 | 11 | var WIDGET_STYLE_ID = 'knowrithm-widget-style'; |
12 | 12 | var WIDGET_STYLE_HREF = '/styles/chat-widget-custom.css'; |
13 | | - var NAV_ELEMENTS = [ |
14 | | - { id: 'navbar', minWidth: 0, display: 'block', zIndex: 90 }, |
15 | | - { id: 'sidebar', minWidth: 1024, display: 'block', zIndex: 80 }, |
16 | | - { id: 'content-side-layout', minWidth: 1280, display: 'flex', zIndex: 70 }, |
17 | | - { id: 'table-of-contents-layout', minWidth: 1280, display: 'flex', zIndex: 70 }, |
18 | | - { id: 'table-of-contents', minWidth: 1280, display: 'block', zIndex: 70 } |
19 | | - ]; |
20 | | - var navVisibilityGuardAttached = false; |
21 | | - var navMutationObserver = null; |
22 | | - var navElementObservers = {}; |
23 | 13 |
|
24 | | - function observeNavElement(ruleId, element) { |
25 | | - if (typeof MutationObserver === 'undefined' || !element) { |
| 14 | + function ensureWidgetOverridesLoaded() { |
| 15 | + if (typeof document === 'undefined') { |
26 | 16 | return; |
27 | 17 | } |
28 | | - |
29 | | - var existing = navElementObservers[ruleId]; |
30 | | - if (existing && existing.element === element) { |
| 18 | + if (document.getElementById(WIDGET_STYLE_ID)) { |
31 | 19 | return; |
32 | 20 | } |
33 | 21 |
|
34 | | - if (existing && existing.observer) { |
35 | | - existing.observer.disconnect(); |
36 | | - } |
37 | | - |
38 | | - var observer = new MutationObserver(function () { |
39 | | - applyAllNavigationRules(); |
40 | | - }); |
| 22 | + var link = document.createElement('link'); |
| 23 | + link.id = WIDGET_STYLE_ID; |
| 24 | + link.rel = 'stylesheet'; |
| 25 | + link.href = WIDGET_STYLE_HREF; |
| 26 | + link.type = 'text/css'; |
| 27 | + link.media = 'all'; |
| 28 | + link.onerror = function (error) { |
| 29 | + console.error('Failed to load Knowrithm widget override styles:', error); |
| 30 | + }; |
41 | 31 |
|
42 | | - observer.observe(element, { attributes: true, attributeFilter: ['class', 'style', 'hidden'] }); |
43 | | - navElementObservers[ruleId] = { observer: observer, element: element }; |
| 32 | + (document.head || document.body).appendChild(link); |
44 | 33 | } |
45 | 34 |
|
46 | | - function applyNavigationRule(rule) { |
47 | | - var element = document.getElementById(rule.id); |
48 | | - if (!element) return; |
| 35 | + var NAV_GUARD_TARGETS = [ |
| 36 | + { selector: '#navbar', minWidth: 0, display: 'block', zIndex: 120 }, |
| 37 | + { selector: '#sidebar', minWidth: 1024, display: 'block', zIndex: 80 }, |
| 38 | + { selector: '#content-side-layout', minWidth: 1280, display: 'flex', zIndex: 70 }, |
| 39 | + { selector: '#table-of-contents-layout', minWidth: 1280, display: 'flex', zIndex: 70 }, |
| 40 | + { selector: '#table-of-contents', minWidth: 1280, display: 'block', zIndex: 70 }, |
| 41 | + { selector: '#navbar .relative.hidden.lg\\:flex.items-center.flex-1.justify-center', minWidth: 1024, display: 'flex', zIndex: 110 }, |
| 42 | + { selector: '#navbar .flex-1.relative.hidden.lg\\:flex.items-center.ml-auto.justify-end', minWidth: 1024, display: 'flex', zIndex: 110 }, |
| 43 | + { selector: '#navbar .hidden.lg\\:flex.px-12.h-12', minWidth: 1024, display: 'flex', zIndex: 110 }, |
| 44 | + { selector: '#topbar-cta-button.hidden.lg\\:flex', minWidth: 1024, display: 'flex', zIndex: 110 } |
| 45 | + ]; |
| 46 | + var navGuardAttached = false; |
| 47 | + var navMutationObserver = null; |
| 48 | + var pendingNavFrame = null; |
49 | 49 |
|
50 | | - var meetsBreakpoint = true; |
51 | | - if (rule.minWidth) { |
52 | | - if (typeof window.matchMedia === 'function') { |
53 | | - meetsBreakpoint = window.matchMedia('(min-width: ' + rule.minWidth + 'px)').matches; |
54 | | - } else { |
55 | | - meetsBreakpoint = window.innerWidth >= rule.minWidth; |
56 | | - } |
| 50 | + function matchesMinWidth(rule) { |
| 51 | + if (!rule.minWidth) { |
| 52 | + return true; |
| 53 | + } |
| 54 | + if (typeof window === 'undefined') { |
| 55 | + return false; |
| 56 | + } |
| 57 | + if (typeof window.matchMedia === 'function') { |
| 58 | + return window.matchMedia('(min-width: ' + rule.minWidth + 'px)').matches; |
57 | 59 | } |
| 60 | + return window.innerWidth >= rule.minWidth; |
| 61 | + } |
58 | 62 |
|
59 | | - if (meetsBreakpoint) { |
60 | | - var displayValue = rule.display || 'block'; |
61 | | - element.style.setProperty('display', displayValue, 'important'); |
62 | | - element.style.setProperty('visibility', 'visible', 'important'); |
63 | | - element.style.setProperty('opacity', '1', 'important'); |
64 | | - element.style.setProperty('pointer-events', 'auto', 'important'); |
65 | | - if (typeof rule.zIndex === 'number') { |
66 | | - element.style.setProperty('z-index', String(rule.zIndex), 'important'); |
67 | | - } |
68 | | - if (element.hasAttribute('hidden')) { |
69 | | - element.removeAttribute('hidden'); |
70 | | - } |
| 63 | + function applyNavGuardRule(rule) { |
| 64 | + if (typeof document === 'undefined') { |
| 65 | + return; |
| 66 | + } |
| 67 | + var element = document.querySelector(rule.selector); |
| 68 | + if (!element) { |
| 69 | + return; |
| 70 | + } |
71 | 71 |
|
72 | | - // Special handling for navbar removed to ensure layout independence |
73 | | - // and prevent interfering with existing styles (e.g. SVG strokes). |
74 | | - } else { |
| 72 | + if (!matchesMinWidth(rule)) { |
75 | 73 | ['display', 'visibility', 'opacity', 'pointer-events', 'z-index'].forEach(function (prop) { |
76 | 74 | element.style.removeProperty(prop); |
77 | 75 | }); |
| 76 | + return; |
78 | 77 | } |
79 | 78 |
|
80 | | - observeNavElement(rule.id, element); |
| 79 | + if (rule.display) { |
| 80 | + element.style.setProperty('display', rule.display, 'important'); |
| 81 | + } |
| 82 | + element.style.setProperty('visibility', 'visible', 'important'); |
| 83 | + element.style.setProperty('opacity', '1', 'important'); |
| 84 | + element.style.setProperty('pointer-events', 'auto', 'important'); |
| 85 | + if (typeof rule.zIndex === 'number') { |
| 86 | + element.style.setProperty('z-index', String(rule.zIndex), 'important'); |
| 87 | + } |
| 88 | + if (element.hasAttribute('hidden')) { |
| 89 | + element.removeAttribute('hidden'); |
| 90 | + } |
81 | 91 | } |
82 | 92 |
|
83 | | - function applyAllNavigationRules() { |
84 | | - NAV_ELEMENTS.forEach(applyNavigationRule); |
| 93 | + function enforceNavigationGuards() { |
| 94 | + NAV_GUARD_TARGETS.forEach(applyNavGuardRule); |
85 | 95 | } |
86 | 96 |
|
87 | | - function maintainNavigationVisibility() { |
88 | | - if (typeof window === 'undefined' || typeof document === 'undefined') return; |
89 | | - |
90 | | - applyAllNavigationRules(); |
91 | | - |
92 | | - if (navVisibilityGuardAttached) { |
| 97 | + function scheduleNavigationGuard() { |
| 98 | + if (pendingNavFrame || typeof window === 'undefined') { |
93 | 99 | return; |
94 | 100 | } |
95 | | - navVisibilityGuardAttached = true; |
96 | | - |
97 | | - var queries = NAV_ELEMENTS |
98 | | - .filter(function (rule) { return rule.minWidth; }) |
99 | | - .map(function (rule) { return '(min-width: ' + rule.minWidth + 'px)'; }) |
100 | | - .filter(function (query, index, self) { return self.indexOf(query) === index; }); |
| 101 | + pendingNavFrame = window.requestAnimationFrame(function () { |
| 102 | + pendingNavFrame = null; |
| 103 | + enforceNavigationGuards(); |
| 104 | + }); |
| 105 | + } |
101 | 106 |
|
102 | | - function handleViewportChange() { |
103 | | - applyAllNavigationRules(); |
| 107 | + function attachNavigationGuards() { |
| 108 | + if (navGuardAttached || typeof document === 'undefined') { |
| 109 | + return; |
104 | 110 | } |
| 111 | + navGuardAttached = true; |
| 112 | + enforceNavigationGuards(); |
105 | 113 |
|
106 | | - if (queries.length && typeof window.matchMedia === 'function') { |
107 | | - queries.forEach(function (query) { |
108 | | - var mediaQuery = window.matchMedia(query); |
109 | | - if (typeof mediaQuery.addEventListener === 'function') { |
110 | | - mediaQuery.addEventListener('change', handleViewportChange); |
111 | | - } else if (typeof mediaQuery.addListener === 'function') { |
112 | | - mediaQuery.addListener(handleViewportChange); |
113 | | - } |
114 | | - }); |
115 | | - } else { |
116 | | - window.addEventListener('resize', handleViewportChange, { passive: true }); |
| 114 | + if (typeof window !== 'undefined') { |
| 115 | + window.addEventListener('resize', scheduleNavigationGuard, { passive: true }); |
117 | 116 | } |
118 | 117 |
|
119 | | - if (typeof MutationObserver !== 'undefined') { |
120 | | - NAV_ELEMENTS.forEach(function (rule) { |
121 | | - var target = document.getElementById(rule.id); |
122 | | - if (target) { |
123 | | - var observer = new MutationObserver(handleViewportChange); |
124 | | - // For navbar, we need to watch subtree attributes to catch icon style changes |
125 | | - if (rule.id === 'navbar') { |
126 | | - observer.observe(target, { |
127 | | - attributes: true, |
128 | | - attributeFilter: ['class', 'style', 'fill', 'stroke', 'color'], |
129 | | - subtree: true |
130 | | - }); |
131 | | - } else { |
132 | | - observer.observe(target, { attributes: true, attributeFilter: ['class', 'style'] }); |
| 118 | + if (typeof MutationObserver !== 'undefined' && document.body) { |
| 119 | + navMutationObserver = new MutationObserver(function (mutations) { |
| 120 | + for (var i = 0; i < mutations.length; i++) { |
| 121 | + var target = mutations[i].target; |
| 122 | + for (var j = 0; j < NAV_GUARD_TARGETS.length; j++) { |
| 123 | + var rule = NAV_GUARD_TARGETS[j]; |
| 124 | + var element = document.querySelector(rule.selector); |
| 125 | + if (element && (target === element || element.contains(target))) { |
| 126 | + scheduleNavigationGuard(); |
| 127 | + return; |
| 128 | + } |
133 | 129 | } |
134 | 130 | } |
135 | 131 | }); |
136 | | - |
137 | | - if (!navMutationObserver) { |
138 | | - navMutationObserver = new MutationObserver(function () { |
139 | | - applyAllNavigationRules(); |
140 | | - }); |
141 | | - |
142 | | - if (document.body) { |
143 | | - navMutationObserver.observe(document.body, { childList: true, subtree: true }); |
144 | | - } else { |
145 | | - document.addEventListener('DOMContentLoaded', function () { |
146 | | - if (!navMutationObserver) return; |
147 | | - navMutationObserver.observe(document.body, { childList: true, subtree: true }); |
148 | | - }); |
149 | | - } |
150 | | - } |
| 132 | + navMutationObserver.observe(document.body, { |
| 133 | + attributes: true, |
| 134 | + attributeFilter: ['style', 'hidden', 'class'], |
| 135 | + subtree: true |
| 136 | + }); |
151 | 137 | } |
152 | 138 | } |
153 | 139 |
|
|
250 | 236 |
|
251 | 237 | // Wait for DOM to be ready |
252 | 238 | function initWidget() { |
253 | | - maintainNavigationVisibility(); |
| 239 | + ensureWidgetOverridesLoaded(); |
| 240 | + attachNavigationGuards(); |
254 | 241 |
|
255 | 242 | // Fix form autofill issues on initial load |
256 | 243 | fixFormAutofillIssues(); |
|
306 | 293 | } |
307 | 294 | } |
308 | 295 |
|
309 | | - // Ensure the scoped widget stylesheet is loaded once |
310 | | - if (!document.getElementById(WIDGET_STYLE_ID)) { |
311 | | - var link = document.createElement('link'); |
312 | | - link.id = WIDGET_STYLE_ID; |
313 | | - link.rel = 'stylesheet'; |
314 | | - link.href = WIDGET_STYLE_HREF; |
315 | | - link.type = 'text/css'; |
316 | | - link.media = 'all'; |
317 | | - link.onerror = function (error) { |
318 | | - console.error('Failed to load Knowrithm widget styles:', error); |
319 | | - }; |
320 | | - |
321 | | - (document.head || document.body).appendChild(link); |
322 | | - } |
323 | | - |
324 | 296 | // Configure the widget BEFORE loading the script |
325 | 297 | window.AIChatWidget = { |
326 | 298 | agentId: "2b041b45-a585-47e9-abaf-ebaad766bce9", |
|
364 | 336 | script.async = true; |
365 | 337 | script.defer = true; // Defer to avoid blocking page load |
366 | 338 |
|
| 339 | + script.onload = ensureWidgetOverridesLoaded; |
367 | 340 | script.onerror = function (error) { |
368 | 341 | console.error('Failed to load Knowrithm widget script:', error); |
| 342 | + ensureWidgetOverridesLoaded(); |
369 | 343 | }; |
370 | 344 |
|
371 | 345 | // Append to body instead of head to avoid interfering with page initialization |
|
0 commit comments