@ourlu/assistant-sdk 0.2.5 → 0.2.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/iife/engine.v1.19c589a2.js +861 -0
- package/dist/iife/engine.v1.bc9c0b5e.js +838 -0
- package/dist/iife/engine.v1.ec035c58.js +782 -0
- package/dist/iife/engine.v1.js +43 -2
- package/dist/iife/loader.v1.js +5 -1
- package/dist/iife/plu.v1.cc853a2d.js +458 -0
- package/dist/iife/plu.v1.js +458 -0
- package/dist/iife/ui.v1.0caedc90.js +1018 -0
- package/dist/iife/ui.v1.0ccf99d5.js +997 -0
- package/dist/iife/ui.v1.11a41f0d.js +1007 -0
- package/dist/iife/ui.v1.12986798.js +962 -0
- package/dist/iife/ui.v1.15b2cd71.js +986 -0
- package/dist/iife/ui.v1.163772e6.js +962 -0
- package/dist/iife/ui.v1.3a1d08a0.js +1007 -0
- package/dist/iife/ui.v1.3c0cf4da.js +947 -0
- package/dist/iife/ui.v1.3fcff562.js +997 -0
- package/dist/iife/ui.v1.44616ccb.js +986 -0
- package/dist/iife/ui.v1.4e202266.js +1007 -0
- package/dist/iife/ui.v1.7432d2af.js +995 -0
- package/dist/iife/ui.v1.84d77387.js +1003 -0
- package/dist/iife/ui.v1.857a0e8b.js +986 -0
- package/dist/iife/ui.v1.89fbfdd9.js +963 -0
- package/dist/iife/ui.v1.a588a766.js +997 -0
- package/dist/iife/ui.v1.cd72e7c3.js +1006 -0
- package/dist/iife/ui.v1.e8703c6d.js +1006 -0
- package/dist/iife/ui.v1.f6857351.js +995 -0
- package/dist/iife/ui.v1.js +105 -13
- package/dist/iife/widget-manifest.json +3 -2
- package/package.json +2 -1
package/dist/iife/engine.v1.js
CHANGED
|
@@ -51,6 +51,12 @@ function normalizeHexColor(rawValue, fallbackColor) {
|
|
|
51
51
|
var normalized = String(rawValue || "").trim().toLowerCase();
|
|
52
52
|
return /^#[0-9a-f]{6}$/.test(normalized) ? normalized : fallbackColor;
|
|
53
53
|
}
|
|
54
|
+
function normalizeLabelBool(rawValue, fallbackValue) {
|
|
55
|
+
var normalized = String(rawValue || "").trim().toLowerCase();
|
|
56
|
+
if (normalized === "true") return true;
|
|
57
|
+
if (normalized === "false") return false;
|
|
58
|
+
return Boolean(fallbackValue);
|
|
59
|
+
}
|
|
54
60
|
function normalizePosition(rawValue, fallbackValue) {
|
|
55
61
|
var normalized = String(rawValue || "").trim().toLowerCase();
|
|
56
62
|
return normalized === "bottom-left" || normalized === "bottom-right" ? normalized : fallbackValue;
|
|
@@ -129,6 +135,18 @@ function applyThemeConfigToRuntime(config, rawWidgetConfig) {
|
|
|
129
135
|
config.panelBackgroundColor = normalizeHexColor(labels.panel_background_color, config.panelBackgroundColor || "#ffffff");
|
|
130
136
|
config.panelBackgroundAlpha = clampNumericString(labels.panel_background_alpha, config.panelBackgroundAlpha || "1", 0, 1, false);
|
|
131
137
|
config.panelBorderRadius = clampNumericString(labels.panel_border_radius, config.panelBorderRadius || "16", 0, 32, true);
|
|
138
|
+
config.headerGradientEnabled = normalizeLabelBool(labels.header_gradient_enabled, config.headerGradientEnabled !== false);
|
|
139
|
+
config.headerGradientColor2Auto = normalizeLabelBool(labels.header_gradient_color2_auto, config.headerGradientColor2Auto !== false);
|
|
140
|
+
config.headerGradientColor2 = normalizeHexColor(labels.header_gradient_color2, config.headerGradientColor2 || "#0047b3");
|
|
141
|
+
config.userBubbleColor = normalizeHexColor(labels.user_bubble_color, config.userBubbleColor || "");
|
|
142
|
+
config.userBubbleGradientEnabled = normalizeLabelBool(labels.user_bubble_gradient_enabled, config.userBubbleGradientEnabled === true);
|
|
143
|
+
config.userBubbleGradientColor2Auto = normalizeLabelBool(labels.user_bubble_gradient_color2_auto, config.userBubbleGradientColor2Auto !== false);
|
|
144
|
+
config.userBubbleGradientColor2 = normalizeHexColor(labels.user_bubble_gradient_color2, config.userBubbleGradientColor2 || "");
|
|
145
|
+
config.assistantBubbleColor = normalizeHexColor(labels.assistant_bubble_color, config.assistantBubbleColor || "#f0f4f8");
|
|
146
|
+
config.assistantBubbleTextColor = normalizeHexColor(labels.assistant_bubble_text_color, config.assistantBubbleTextColor || "#1a1a2e");
|
|
147
|
+
config.assistantBubbleGradientEnabled = normalizeLabelBool(labels.assistant_bubble_gradient_enabled, config.assistantBubbleGradientEnabled === true);
|
|
148
|
+
config.assistantBubbleGradientColor2Auto = normalizeLabelBool(labels.assistant_bubble_gradient_color2_auto, config.assistantBubbleGradientColor2Auto !== false);
|
|
149
|
+
config.assistantBubbleGradientColor2 = normalizeHexColor(labels.assistant_bubble_gradient_color2, config.assistantBubbleGradientColor2 || "");
|
|
132
150
|
applyMascotLabelColors(config, labels);
|
|
133
151
|
var candidateVersion = normalizeThemeVersion(rawWidgetConfig.theme_updated_at);
|
|
134
152
|
if (candidateVersion > 0) config.themeVersion = candidateVersion;
|
|
@@ -540,6 +558,7 @@ Object.assign(WidgetApiManager.prototype, {
|
|
|
540
558
|
if (eventName === "done" && callbacks.onDone) callbacks.onDone(payload);
|
|
541
559
|
if (eventName === "error" && callbacks.onError) callbacks.onError(payload.message || "Erreur de streaming");
|
|
542
560
|
if (eventName === "module_signalement" && callbacks.onModuleSignalement) callbacks.onModuleSignalement(payload);
|
|
561
|
+
if (eventName === "module_plu" && callbacks.onModulePlu) callbacks.onModulePlu(payload);
|
|
543
562
|
if (eventName === "transcription_draft_delta" && callbacks.onDelta) callbacks.onDelta(payload);
|
|
544
563
|
if (eventName === "transcription_draft_complete" && callbacks.onComplete) callbacks.onComplete(payload);
|
|
545
564
|
if (eventName === "transcription_draft_error" && callbacks.onError) callbacks.onError(payload);
|
|
@@ -575,7 +594,7 @@ Object.assign(WidgetApiManager.prototype, {
|
|
|
575
594
|
return this.consumeSSE(response.body.getReader(), callbacks, allowedEvents);
|
|
576
595
|
},
|
|
577
596
|
streamSession: async function(sessionId, callbacks) {
|
|
578
|
-
return this.openEventStream("stream_session", this.config.chatStreamTemplate, sessionId, callbacks, ["token", "final", "error", "done", "module_signalement"]);
|
|
597
|
+
return this.openEventStream("stream_session", this.config.chatStreamTemplate, sessionId, callbacks, ["token", "final", "error", "done", "module_signalement", "module_plu"]);
|
|
579
598
|
},
|
|
580
599
|
streamAudioDraft: async function(sessionId, callbacks) {
|
|
581
600
|
var self = this;
|
|
@@ -676,6 +695,12 @@ function mountFromScript(scriptTag) {
|
|
|
676
695
|
signalementModule = new SignalementModuleManager(ui.getRoot(), events, api, ui);
|
|
677
696
|
signalementModule.mount(ui.getPanel(), ui.getHeader());
|
|
678
697
|
}
|
|
698
|
+
var pluModule = null;
|
|
699
|
+
var PluModuleManager = runtime.PluModuleManager;
|
|
700
|
+
if (PluModuleManager) {
|
|
701
|
+
pluModule = new PluModuleManager(ui.getRoot(), events, api, ui);
|
|
702
|
+
pluModule.mount();
|
|
703
|
+
}
|
|
679
704
|
var mediaQueryList = null;
|
|
680
705
|
var handleHostThemeChange = null;
|
|
681
706
|
if (typeof window.matchMedia === "function") {
|
|
@@ -690,6 +715,7 @@ function mountFromScript(scriptTag) {
|
|
|
690
715
|
else if (typeof mediaQueryList.addListener === "function") mediaQueryList.addListener(handleHostThemeChange);
|
|
691
716
|
}
|
|
692
717
|
var signalementActive = false;
|
|
718
|
+
var pluActive = false;
|
|
693
719
|
|
|
694
720
|
if (signalementModule) {
|
|
695
721
|
events.on("module:signalement:open", function() { signalementActive = true; });
|
|
@@ -702,6 +728,11 @@ function mountFromScript(scriptTag) {
|
|
|
702
728
|
});
|
|
703
729
|
}
|
|
704
730
|
|
|
731
|
+
if (pluModule) {
|
|
732
|
+
events.on("module:plu:open", function() { pluActive = true; });
|
|
733
|
+
events.on("module:plu:closed", function() { pluActive = false; });
|
|
734
|
+
}
|
|
735
|
+
|
|
705
736
|
async function handleSignalementSubmit() {
|
|
706
737
|
if (!signalementModule || !signalementActive) return;
|
|
707
738
|
state.sending = true;
|
|
@@ -738,20 +769,30 @@ function mountFromScript(scriptTag) {
|
|
|
738
769
|
var sessionId = await api.postMessage(message);
|
|
739
770
|
ui.startAssistantStream();
|
|
740
771
|
var pendingSignalementData = null;
|
|
772
|
+
var pendingPluData = null;
|
|
741
773
|
await api.streamSession(sessionId, {
|
|
742
774
|
onToken: function(token) { ui.appendAssistantToken(token); },
|
|
743
775
|
onModuleSignalement: function(payload) {
|
|
744
776
|
pendingSignalementData = payload || {};
|
|
745
777
|
},
|
|
778
|
+
onModulePlu: function(payload) {
|
|
779
|
+
pendingPluData = payload || {};
|
|
780
|
+
},
|
|
746
781
|
onFinal: function(payload) {
|
|
747
782
|
ui.finalizeAssistantMessage(payload.content || "");
|
|
783
|
+
var streamEl = ui.messages.lastElementChild;
|
|
748
784
|
var sigData = pendingSignalementData || (payload.module_signalement ? payload.module_signalement : null);
|
|
749
785
|
if (signalementModule && sigData) {
|
|
750
|
-
var streamEl = ui.messages.lastElementChild;
|
|
751
786
|
ui.injectSignalementButton(streamEl, function() {
|
|
752
787
|
signalementModule.open(sigData);
|
|
753
788
|
});
|
|
754
789
|
}
|
|
790
|
+
var pluData = pendingPluData || (payload.module_plu ? payload.module_plu : null);
|
|
791
|
+
if (pluModule && pluData) {
|
|
792
|
+
ui.injectPluButton(streamEl, function() {
|
|
793
|
+
pluModule.open();
|
|
794
|
+
});
|
|
795
|
+
}
|
|
755
796
|
},
|
|
756
797
|
onError: function(errorText) { ui.showError(errorText || "Erreur de streaming."); },
|
|
757
798
|
onDone: function() {}
|
package/dist/iife/loader.v1.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
(function() {
|
|
2
2
|
"use strict";
|
|
3
|
-
var __WIDGET_MANIFEST__ = {"ui.v1.js":"ui.v1.
|
|
3
|
+
var __WIDGET_MANIFEST__ = {"ui.v1.js":"ui.v1.0caedc90.js","audio.v1.js":"audio.v1.20858b08.js","signalement.v1.js":"signalement.v1.d321dfde.js","plu.v1.js":"plu.v1.cc853a2d.js","engine.v1.js":"engine.v1.19c589a2.js"};
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
var RUNTIME_NS = "__OurluWidgetRuntimeV1";
|
|
@@ -46,17 +46,21 @@
|
|
|
46
46
|
var uiFileName = resolveManifestFileName("ui.v1.js");
|
|
47
47
|
var audioFileName = resolveManifestFileName("audio.v1.js");
|
|
48
48
|
var signalementFileName = resolveManifestFileName("signalement.v1.js");
|
|
49
|
+
var pluFileName = resolveManifestFileName("plu.v1.js");
|
|
49
50
|
var engineFileName = resolveManifestFileName("engine.v1.js");
|
|
50
51
|
|
|
51
52
|
var uiRuntimeUrl = scriptTag.getAttribute("data-runtime-ui-url") || buildApiRuntimeAssetUrl(scriptTag, uiFileName);
|
|
52
53
|
var audioRuntimeUrl = scriptTag.getAttribute("data-runtime-audio-url") || buildApiRuntimeAssetUrl(scriptTag, audioFileName);
|
|
53
54
|
var signalementRuntimeUrl = scriptTag.getAttribute("data-runtime-signalement-url") || buildApiRuntimeAssetUrl(scriptTag, signalementFileName);
|
|
55
|
+
var pluRuntimeUrl = scriptTag.getAttribute("data-runtime-plu-url") || buildApiRuntimeAssetUrl(scriptTag, pluFileName);
|
|
54
56
|
var engineRuntimeUrl = scriptTag.getAttribute("data-runtime-engine-url") || buildApiRuntimeAssetUrl(scriptTag, engineFileName);
|
|
55
57
|
|
|
56
58
|
window[RUNTIME_FLAG] = loadScript(uiRuntimeUrl).then(function() {
|
|
57
59
|
return loadScript(audioRuntimeUrl);
|
|
58
60
|
}).then(function() {
|
|
59
61
|
return loadScript(signalementRuntimeUrl);
|
|
62
|
+
}).then(function() {
|
|
63
|
+
return loadScript(pluRuntimeUrl);
|
|
60
64
|
}).then(function() {
|
|
61
65
|
return loadScript(engineRuntimeUrl);
|
|
62
66
|
});
|
|
@@ -0,0 +1,458 @@
|
|
|
1
|
+
(function() {
|
|
2
|
+
"use strict";
|
|
3
|
+
var runtime = window.__OurluWidgetRuntimeV1 || (window.__OurluWidgetRuntimeV1 = {});
|
|
4
|
+
|
|
5
|
+
var BAN_API_URL = "https://api-adresse.data.gouv.fr/search/";
|
|
6
|
+
var BAN_DEBOUNCE_MS = 300;
|
|
7
|
+
var BAN_MAX_RESULTS = 5;
|
|
8
|
+
|
|
9
|
+
function PluCssBuilder() {}
|
|
10
|
+
|
|
11
|
+
PluCssBuilder.prototype.build = function() {
|
|
12
|
+
return [
|
|
13
|
+
this.buildContent(), this.buildAddressInput(), this.buildSuggestions(),
|
|
14
|
+
this.buildSearchButton(), this.buildLoading(), this.buildResult(),
|
|
15
|
+
this.buildError(), this.buildPluButton(), this.buildMobileOverrides()
|
|
16
|
+
].join("\n");
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
PluCssBuilder.prototype.buildContent = function() {
|
|
20
|
+
return [
|
|
21
|
+
".cm-tab[data-tab='plu'].hidden{display:none}",
|
|
22
|
+
"#cm-plu-content{display:none;flex-direction:column;flex:1;overflow:hidden}",
|
|
23
|
+
"#cm-plu-content.active{display:flex}",
|
|
24
|
+
".cm-plu-scroll{flex:1;overflow-y:auto;overflow-x:hidden;padding:20px 16px;display:flex;flex-direction:column;gap:16px;min-width:0;width:100%}",
|
|
25
|
+
".cm-plu-scroll::-webkit-scrollbar{width:6px}",
|
|
26
|
+
".cm-plu-scroll::-webkit-scrollbar-thumb{background:rgba(0,0,0,.1);border-radius:3px}",
|
|
27
|
+
".cm-plu-title{display:flex;align-items:center;gap:8px;font-size:16px;font-weight:600;color:#1e293b;margin:0}",
|
|
28
|
+
".cm-plu-title svg{width:20px;height:20px;flex-shrink:0}",
|
|
29
|
+
".cm-plu-desc{font-size:14px;color:#64748b;line-height:1.5;margin:0}"
|
|
30
|
+
].join("\n");
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
PluCssBuilder.prototype.buildAddressInput = function() {
|
|
34
|
+
return [
|
|
35
|
+
".cm-plu-input-wrap{position:relative}",
|
|
36
|
+
".cm-plu-input{width:100%;padding:12px 14px;border:1.5px solid #e2e8f0;border-radius:12px;font-size:14px;font-family:inherit;outline:none;transition:border-color .2s,box-shadow .2s;background:#fff;color:#1e293b;box-sizing:border-box}",
|
|
37
|
+
".cm-plu-input:focus{border-color:#0066ff;box-shadow:0 0 0 3px rgba(0,102,255,.15)}",
|
|
38
|
+
".cm-plu-input::placeholder{color:#9ca3af}"
|
|
39
|
+
].join("\n");
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
PluCssBuilder.prototype.buildSuggestions = function() {
|
|
43
|
+
return [
|
|
44
|
+
".cm-plu-suggestions{position:absolute;top:100%;left:0;right:0;margin-top:4px;background:#fff;border:1.5px solid #e2e8f0;border-radius:10px;box-shadow:0 8px 24px rgba(0,0,0,.12);z-index:10;overflow:hidden;display:none}",
|
|
45
|
+
".cm-plu-suggestions.visible{display:block}",
|
|
46
|
+
".cm-plu-suggestion{padding:10px 14px;font-size:14px;color:#334155;cursor:pointer;transition:background .1s;border-bottom:1px solid #f1f5f9;font-family:inherit}",
|
|
47
|
+
".cm-plu-suggestion:last-child{border-bottom:none}",
|
|
48
|
+
".cm-plu-suggestion:hover,.cm-plu-suggestion.highlighted{background:#eff6ff;color:#1d4ed8}"
|
|
49
|
+
].join("\n");
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
PluCssBuilder.prototype.buildSearchButton = function() {
|
|
53
|
+
return [
|
|
54
|
+
".cm-plu-search-btn{display:flex;align-items:center;justify-content:center;gap:8px;width:100%;padding:12px 20px;border-radius:12px;border:none;background:#0066ff;color:#fff;font-size:14px;font-weight:600;cursor:pointer;transition:all .15s;font-family:inherit}",
|
|
55
|
+
".cm-plu-search-btn svg{width:18px;height:18px;flex-shrink:0}",
|
|
56
|
+
".cm-plu-search-btn:hover:not(:disabled){background:#0052cc;transform:translateY(-1px);box-shadow:0 4px 12px rgba(0,102,255,.3)}",
|
|
57
|
+
".cm-plu-search-btn:active:not(:disabled){transform:scale(0.97)}",
|
|
58
|
+
".cm-plu-search-btn:disabled{opacity:.5;cursor:default}"
|
|
59
|
+
].join("\n");
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
PluCssBuilder.prototype.buildLoading = function() {
|
|
63
|
+
return [
|
|
64
|
+
".cm-plu-loading{display:none;flex-direction:column;align-items:center;gap:12px;padding:24px 16px;text-align:center}",
|
|
65
|
+
".cm-plu-loading.visible{display:flex}",
|
|
66
|
+
".cm-plu-spinner{width:36px;height:36px;border:3px solid #e2e8f0;border-top-color:#0066ff;border-radius:50%;animation:cm-plu-spin 1s linear infinite}",
|
|
67
|
+
"@keyframes cm-plu-spin{to{transform:rotate(360deg)}}",
|
|
68
|
+
".cm-plu-loading-text{font-size:14px;color:#64748b;font-weight:500}",
|
|
69
|
+
".cm-plu-loading-sub{font-size:13px;color:#94a3b8}"
|
|
70
|
+
].join("\n");
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
PluCssBuilder.prototype.buildResult = function() {
|
|
74
|
+
return [
|
|
75
|
+
".cm-plu-result{display:none;flex-direction:column;gap:16px}",
|
|
76
|
+
".cm-plu-result.visible{display:flex}",
|
|
77
|
+
".cm-plu-result-addr{display:flex;align-items:flex-start;gap:8px;font-size:14px;color:#334155;line-height:1.5}",
|
|
78
|
+
".cm-plu-result-addr svg{width:18px;height:18px;flex-shrink:0;color:#0066ff;margin-top:2px}",
|
|
79
|
+
".cm-plu-zone-card{padding:14px 16px;border-radius:12px;background:#eff6ff;border:1.5px solid #bfdbfe;display:flex;flex-direction:column;gap:4px}",
|
|
80
|
+
".cm-plu-zone-code{font-size:18px;font-weight:700;color:#1d4ed8}",
|
|
81
|
+
".cm-plu-zone-label{font-size:14px;color:#3b82f6;font-weight:500}",
|
|
82
|
+
".cm-plu-zone-doc{font-size:12px;color:#64748b;margin-top:2px}",
|
|
83
|
+
".cm-plu-rules-title{font-size:13px;font-weight:600;color:#475569;text-transform:uppercase;letter-spacing:.04em;margin-bottom:4px}",
|
|
84
|
+
".cm-plu-rules-list{list-style:disc;padding-left:20px;margin:0;display:flex;flex-direction:column;gap:6px}",
|
|
85
|
+
".cm-plu-rules-list li{font-size:14px;color:#334155;line-height:1.5}",
|
|
86
|
+
".cm-plu-sources{font-size:12px;color:#94a3b8;margin-top:4px}",
|
|
87
|
+
".cm-plu-disclaimer{display:flex;align-items:flex-start;gap:8px;padding:12px 14px;border-radius:10px;background:#fffbeb;border:1px solid #fde68a;font-size:13px;color:#92400e;line-height:1.5}",
|
|
88
|
+
".cm-plu-disclaimer svg{width:16px;height:16px;flex-shrink:0;margin-top:2px}",
|
|
89
|
+
".cm-plu-new-search-btn{display:flex;align-items:center;justify-content:center;gap:8px;width:100%;padding:10px 20px;border-radius:12px;border:1.5px solid #e2e8f0;background:#fff;color:#475569;font-size:14px;font-weight:500;cursor:pointer;transition:all .15s;font-family:inherit}",
|
|
90
|
+
".cm-plu-new-search-btn:hover{border-color:#94a3b8;background:#f8fafc;color:#334155}"
|
|
91
|
+
].join("\n");
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
PluCssBuilder.prototype.buildError = function() {
|
|
95
|
+
return [
|
|
96
|
+
".cm-plu-error{display:none;flex-direction:column;align-items:center;gap:12px;padding:20px 16px;text-align:center}",
|
|
97
|
+
".cm-plu-error.visible{display:flex}",
|
|
98
|
+
".cm-plu-error-icon{width:40px;height:40px;border-radius:50%;background:#fef2f2;display:flex;align-items:center;justify-content:center}",
|
|
99
|
+
".cm-plu-error-icon svg{width:22px;height:22px;color:#dc2626}",
|
|
100
|
+
".cm-plu-error-msg{font-size:14px;color:#991b1b;font-weight:500;line-height:1.5}",
|
|
101
|
+
".cm-plu-error-code{font-size:12px;color:#94a3b8;font-family:ui-monospace,monospace}",
|
|
102
|
+
".cm-plu-retry-btn{display:flex;align-items:center;justify-content:center;gap:6px;padding:10px 20px;border-radius:12px;border:1.5px solid #fecaca;background:#fef2f2;color:#dc2626;font-size:14px;font-weight:500;cursor:pointer;transition:all .15s;font-family:inherit}",
|
|
103
|
+
".cm-plu-retry-btn:hover{background:#dc2626;color:#fff;border-color:#dc2626}"
|
|
104
|
+
].join("\n");
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
PluCssBuilder.prototype.buildPluButton = function() {
|
|
108
|
+
return [
|
|
109
|
+
".cm-plu-open-btn{display:inline-flex;align-items:center;gap:8px;margin-top:10px;padding:10px 18px;border-radius:12px;border:1.5px solid #0066ff;background:#eff6ff;color:#0066ff;font-size:14px;font-weight:600;cursor:pointer;transition:all .15s;font-family:inherit}",
|
|
110
|
+
".cm-plu-open-btn svg{width:18px;height:18px;flex-shrink:0}",
|
|
111
|
+
".cm-plu-open-btn:hover{background:#0066ff;color:#fff;transform:translateY(-1px);box-shadow:0 4px 12px rgba(0,102,255,.3)}",
|
|
112
|
+
".cm-plu-open-btn:active{transform:scale(0.97)}"
|
|
113
|
+
].join("\n");
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
PluCssBuilder.prototype.buildMobileOverrides = function() {
|
|
117
|
+
return "@media(max-width:600px){.cm-plu-scroll{padding:16px 12px}.cm-plu-zone-card{padding:12px 14px}}";
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
function BanAutocompleteManager(inputEl, suggestionsEl) {
|
|
121
|
+
this.inputEl = inputEl;
|
|
122
|
+
this.suggestionsEl = suggestionsEl;
|
|
123
|
+
this.debounceTimer = null;
|
|
124
|
+
this.highlightedIndex = -1;
|
|
125
|
+
this.results = [];
|
|
126
|
+
this.selectedAddress = null;
|
|
127
|
+
this.onSelect = null;
|
|
128
|
+
this.bindEvents();
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
BanAutocompleteManager.prototype.bindEvents = function() {
|
|
132
|
+
var self = this;
|
|
133
|
+
this.inputEl.addEventListener("input", function() {
|
|
134
|
+
self.selectedAddress = null;
|
|
135
|
+
self.scheduleSearch(self.inputEl.value.trim());
|
|
136
|
+
});
|
|
137
|
+
this.inputEl.addEventListener("keydown", function(e) {
|
|
138
|
+
if (!self.results.length) return;
|
|
139
|
+
if (e.key === "ArrowDown") {
|
|
140
|
+
e.preventDefault();
|
|
141
|
+
self.highlightedIndex = Math.min(self.highlightedIndex + 1, self.results.length - 1);
|
|
142
|
+
self.renderHighlight();
|
|
143
|
+
} else if (e.key === "ArrowUp") {
|
|
144
|
+
e.preventDefault();
|
|
145
|
+
self.highlightedIndex = Math.max(self.highlightedIndex - 1, 0);
|
|
146
|
+
self.renderHighlight();
|
|
147
|
+
} else if (e.key === "Enter") {
|
|
148
|
+
e.preventDefault();
|
|
149
|
+
if (self.highlightedIndex >= 0) self.selectResult(self.results[self.highlightedIndex]);
|
|
150
|
+
} else if (e.key === "Escape") {
|
|
151
|
+
self.hideSuggestions();
|
|
152
|
+
}
|
|
153
|
+
});
|
|
154
|
+
document.addEventListener("click", function(e) {
|
|
155
|
+
if (!self.inputEl.contains(e.target) && !self.suggestionsEl.contains(e.target)) self.hideSuggestions();
|
|
156
|
+
});
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
BanAutocompleteManager.prototype.scheduleSearch = function(query) {
|
|
160
|
+
var self = this;
|
|
161
|
+
clearTimeout(this.debounceTimer);
|
|
162
|
+
if (query.length < 3) { this.hideSuggestions(); return; }
|
|
163
|
+
this.debounceTimer = setTimeout(function() { self.search(query); }, BAN_DEBOUNCE_MS);
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
BanAutocompleteManager.prototype.search = async function(query) {
|
|
167
|
+
var url = BAN_API_URL + "?q=" + encodeURIComponent(query) + "&limit=" + BAN_MAX_RESULTS;
|
|
168
|
+
var response = await fetch(url);
|
|
169
|
+
if (!response.ok) throw new Error("BAN API erreur HTTP " + response.status);
|
|
170
|
+
var data = await response.json();
|
|
171
|
+
this.results = (data.features || []).map(function(f) {
|
|
172
|
+
var props = f.properties || {};
|
|
173
|
+
var coords = f.geometry && f.geometry.coordinates ? f.geometry.coordinates : [0, 0];
|
|
174
|
+
return { label: props.label || "", city: props.city || "", postcode: props.postcode || "", citycode: props.citycode || "", longitude: coords[0], latitude: coords[1] };
|
|
175
|
+
});
|
|
176
|
+
this.highlightedIndex = -1;
|
|
177
|
+
this.renderSuggestions();
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
BanAutocompleteManager.prototype.renderSuggestions = function() {
|
|
181
|
+
var self = this;
|
|
182
|
+
if (!this.results.length) { this.hideSuggestions(); return; }
|
|
183
|
+
this.suggestionsEl.innerHTML = this.results.map(function(r, idx) {
|
|
184
|
+
return '<div class="cm-plu-suggestion" data-idx="' + idx + '">' + self.escapeHtml(r.label) + '</div>';
|
|
185
|
+
}).join("");
|
|
186
|
+
this.suggestionsEl.classList.add("visible");
|
|
187
|
+
this.suggestionsEl.querySelectorAll(".cm-plu-suggestion").forEach(function(el) {
|
|
188
|
+
el.addEventListener("click", function() { self.selectResult(self.results[Number(el.getAttribute("data-idx"))]); });
|
|
189
|
+
});
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
BanAutocompleteManager.prototype.renderHighlight = function() {
|
|
193
|
+
var self = this;
|
|
194
|
+
this.suggestionsEl.querySelectorAll(".cm-plu-suggestion").forEach(function(el, idx) {
|
|
195
|
+
el.classList.toggle("highlighted", idx === self.highlightedIndex);
|
|
196
|
+
});
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
BanAutocompleteManager.prototype.selectResult = function(result) {
|
|
200
|
+
if (!result) return;
|
|
201
|
+
this.selectedAddress = result;
|
|
202
|
+
this.inputEl.value = result.label;
|
|
203
|
+
this.hideSuggestions();
|
|
204
|
+
if (typeof this.onSelect === "function") this.onSelect(result);
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
BanAutocompleteManager.prototype.hideSuggestions = function() {
|
|
208
|
+
this.suggestionsEl.classList.remove("visible");
|
|
209
|
+
this.results = [];
|
|
210
|
+
this.highlightedIndex = -1;
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
BanAutocompleteManager.prototype.escapeHtml = function(str) {
|
|
214
|
+
var div = document.createElement("div");
|
|
215
|
+
div.textContent = str;
|
|
216
|
+
return div.innerHTML;
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
BanAutocompleteManager.prototype.reset = function() {
|
|
220
|
+
this.inputEl.value = "";
|
|
221
|
+
this.selectedAddress = null;
|
|
222
|
+
this.hideSuggestions();
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
var ICON_HOUSE = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M3 9l9-7 9 7v11a2 2 0 01-2 2H5a2 2 0 01-2-2z"/><polyline points="9 22 9 12 15 12 15 22"/></svg>';
|
|
226
|
+
var ICON_PIN = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"><path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0118 0z"/><circle cx="12" cy="10" r="3"/></svg>';
|
|
227
|
+
var ICON_SEARCH = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>';
|
|
228
|
+
var ICON_WARN = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 9v4"/><path d="M12 17h.01"/><path d="M10.29 3.86L1.82 18a2 2 0 001.71 3h16.94a2 2 0 001.71-3L13.71 3.86a2 2 0 00-3.42 0z"/></svg>';
|
|
229
|
+
var ICON_X = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>';
|
|
230
|
+
|
|
231
|
+
function PluModuleManager(rootEl, events, apiManager, uiManager) {
|
|
232
|
+
this.root = rootEl;
|
|
233
|
+
this.events = events;
|
|
234
|
+
this.api = apiManager;
|
|
235
|
+
this.ui = uiManager;
|
|
236
|
+
this.autocomplete = null;
|
|
237
|
+
this.contentEl = null;
|
|
238
|
+
this.stateInputEl = null;
|
|
239
|
+
this.stateLoadingEl = null;
|
|
240
|
+
this.stateResultEl = null;
|
|
241
|
+
this.stateErrorEl = null;
|
|
242
|
+
this.searchBtnEl = null;
|
|
243
|
+
this.mounted = false;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
PluModuleManager.prototype.injectCSS = function() {
|
|
247
|
+
var styleEl = document.createElement("style");
|
|
248
|
+
styleEl.id = "cm-plu-css";
|
|
249
|
+
styleEl.textContent = new PluCssBuilder().build();
|
|
250
|
+
this.root.appendChild(styleEl);
|
|
251
|
+
};
|
|
252
|
+
|
|
253
|
+
PluModuleManager.prototype.mount = function() {
|
|
254
|
+
if (this.mounted) return;
|
|
255
|
+
this.injectCSS();
|
|
256
|
+
var tabsBar = this.root.querySelector("#cm-tabs-bar");
|
|
257
|
+
if (tabsBar) {
|
|
258
|
+
var pluTab = document.createElement("button");
|
|
259
|
+
pluTab.className = "cm-tab hidden";
|
|
260
|
+
pluTab.setAttribute("data-tab", "plu");
|
|
261
|
+
pluTab.type = "button";
|
|
262
|
+
pluTab.innerHTML = ICON_HOUSE + 'Urbanisme<button class="cm-tab-close" type="button" aria-label="Fermer l\'onglet urbanisme">' + ICON_X + '</button>';
|
|
263
|
+
tabsBar.appendChild(pluTab);
|
|
264
|
+
var self = this;
|
|
265
|
+
pluTab.addEventListener("click", function() {
|
|
266
|
+
if (!pluTab.classList.contains("hidden")) self.switchTab("plu");
|
|
267
|
+
});
|
|
268
|
+
var closeBtn = pluTab.querySelector(".cm-tab-close");
|
|
269
|
+
if (closeBtn) closeBtn.addEventListener("click", function(e) { e.stopPropagation(); self.close(); });
|
|
270
|
+
}
|
|
271
|
+
var content = document.createElement("div");
|
|
272
|
+
content.id = "cm-plu-content";
|
|
273
|
+
content.innerHTML = this.buildHTML();
|
|
274
|
+
var panel = this.ui.getPanel();
|
|
275
|
+
var formEl = panel.querySelector("#cm-form");
|
|
276
|
+
if (formEl) { panel.insertBefore(content, formEl); } else { panel.appendChild(content); }
|
|
277
|
+
this.contentEl = content;
|
|
278
|
+
this.stateInputEl = content.querySelector(".cm-plu-state-input");
|
|
279
|
+
this.stateLoadingEl = content.querySelector(".cm-plu-loading");
|
|
280
|
+
this.stateResultEl = content.querySelector(".cm-plu-result");
|
|
281
|
+
this.stateErrorEl = content.querySelector(".cm-plu-error");
|
|
282
|
+
this.searchBtnEl = content.querySelector(".cm-plu-search-btn");
|
|
283
|
+
this.autocomplete = new BanAutocompleteManager(content.querySelector(".cm-plu-input"), content.querySelector(".cm-plu-suggestions"));
|
|
284
|
+
this.bindEvents();
|
|
285
|
+
this.mounted = true;
|
|
286
|
+
};
|
|
287
|
+
|
|
288
|
+
PluModuleManager.prototype.buildHTML = function() {
|
|
289
|
+
return [
|
|
290
|
+
'<div class="cm-plu-scroll">',
|
|
291
|
+
'<div class="cm-plu-state-input" style="display:flex;flex-direction:column;gap:16px">',
|
|
292
|
+
'<h3 class="cm-plu-title">' + ICON_HOUSE + ' Recherche PLU</h3>',
|
|
293
|
+
'<p class="cm-plu-desc">Saisissez votre adresse pour conna\u00eetre les r\u00e8gles d\'urbanisme applicables \u00e0 votre parcelle.</p>',
|
|
294
|
+
'<div class="cm-plu-input-wrap"><input class="cm-plu-input" type="text" placeholder="Tapez votre adresse\u2026" autocomplete="off"/><div class="cm-plu-suggestions"></div></div>',
|
|
295
|
+
'<button class="cm-plu-search-btn" type="button" disabled>' + ICON_SEARCH + ' Rechercher</button>',
|
|
296
|
+
'</div>',
|
|
297
|
+
'<div class="cm-plu-loading"><div class="cm-plu-spinner"></div><div class="cm-plu-loading-text">Recherche en cours\u2026</div><div class="cm-plu-loading-sub">Identification de votre parcelle et r\u00e9cup\u00e9ration des r\u00e8gles PLU\u2026</div></div>',
|
|
298
|
+
'<div class="cm-plu-result"></div>',
|
|
299
|
+
'<div class="cm-plu-error"></div>',
|
|
300
|
+
'</div>'
|
|
301
|
+
].join("");
|
|
302
|
+
};
|
|
303
|
+
|
|
304
|
+
PluModuleManager.prototype.bindEvents = function() {
|
|
305
|
+
var self = this;
|
|
306
|
+
this.autocomplete.onSelect = function() { self.searchBtnEl.disabled = false; };
|
|
307
|
+
this.searchBtnEl.addEventListener("click", function() { self.submitQuery(); });
|
|
308
|
+
};
|
|
309
|
+
|
|
310
|
+
PluModuleManager.prototype.switchTab = function(tabName) {
|
|
311
|
+
var isPlu = tabName === "plu";
|
|
312
|
+
var tabsBar = this.root.querySelector("#cm-tabs-bar");
|
|
313
|
+
if (tabsBar) {
|
|
314
|
+
tabsBar.querySelectorAll(".cm-tab").forEach(function(t) {
|
|
315
|
+
t.classList.toggle("active", t.getAttribute("data-tab") === tabName);
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
this.root.querySelectorAll("#cm-messages, #cm-typing, #cm-error, #cm-disclaimer, #cm-transparency").forEach(function(el) { el.style.display = isPlu ? "none" : ""; });
|
|
319
|
+
var sigContent = this.root.querySelector("#cm-signalement-content");
|
|
320
|
+
if (sigContent) { sigContent.style.display = "none"; sigContent.classList.remove("active"); }
|
|
321
|
+
var sigFooter = this.root.querySelector(".cm-sig-footer");
|
|
322
|
+
if (sigFooter) sigFooter.classList.remove("active");
|
|
323
|
+
var chatForm = this.root.querySelector("#cm-form");
|
|
324
|
+
if (chatForm) chatForm.style.display = isPlu ? "none" : "";
|
|
325
|
+
this.contentEl.classList.toggle("active", isPlu);
|
|
326
|
+
this.contentEl.style.display = isPlu ? "flex" : "none";
|
|
327
|
+
};
|
|
328
|
+
|
|
329
|
+
PluModuleManager.prototype.open = function() {
|
|
330
|
+
var tabsBar = this.root.querySelector("#cm-tabs-bar");
|
|
331
|
+
if (tabsBar) {
|
|
332
|
+
var pluTab = tabsBar.querySelector('[data-tab="plu"]');
|
|
333
|
+
if (pluTab) pluTab.classList.remove("hidden");
|
|
334
|
+
tabsBar.classList.add("visible");
|
|
335
|
+
}
|
|
336
|
+
this.switchTab("plu");
|
|
337
|
+
this.showState("input");
|
|
338
|
+
this.events.emit("module:plu:open", {});
|
|
339
|
+
};
|
|
340
|
+
|
|
341
|
+
PluModuleManager.prototype.close = function() {
|
|
342
|
+
var tabsBar = this.root.querySelector("#cm-tabs-bar");
|
|
343
|
+
if (tabsBar) {
|
|
344
|
+
var pluTab = tabsBar.querySelector('[data-tab="plu"]');
|
|
345
|
+
if (pluTab) pluTab.classList.add("hidden");
|
|
346
|
+
}
|
|
347
|
+
this.switchTab("chat");
|
|
348
|
+
this.events.emit("module:plu:closed", {});
|
|
349
|
+
};
|
|
350
|
+
|
|
351
|
+
PluModuleManager.prototype.showState = function(state) {
|
|
352
|
+
this.stateInputEl.style.display = state === "input" ? "flex" : "none";
|
|
353
|
+
this.stateLoadingEl.classList.toggle("visible", state === "loading");
|
|
354
|
+
this.stateResultEl.classList.toggle("visible", state === "result");
|
|
355
|
+
this.stateErrorEl.classList.toggle("visible", state === "error");
|
|
356
|
+
};
|
|
357
|
+
|
|
358
|
+
PluModuleManager.prototype.submitQuery = async function() {
|
|
359
|
+
var address = this.autocomplete.selectedAddress;
|
|
360
|
+
if (!address) return;
|
|
361
|
+
this.showState("loading");
|
|
362
|
+
this.events.emit("module:plu:submitted", address);
|
|
363
|
+
try {
|
|
364
|
+
await this.api.ensureSession();
|
|
365
|
+
var url = this.api.resolveRuntimeUrl("/v1/modules/plu/query");
|
|
366
|
+
var headers = this.api.buildHeaders({ "Content-Type": "application/json" });
|
|
367
|
+
var body = JSON.stringify({
|
|
368
|
+
session_id: this.api.state.sessionId || "",
|
|
369
|
+
address_label: address.label,
|
|
370
|
+
latitude: address.latitude,
|
|
371
|
+
longitude: address.longitude,
|
|
372
|
+
city_insee_code: address.citycode
|
|
373
|
+
});
|
|
374
|
+
var response = await fetch(url, { method: "POST", headers: headers, body: body });
|
|
375
|
+
if (!response.ok) {
|
|
376
|
+
var errText = await response.text().catch(function() { return ""; });
|
|
377
|
+
var errObj = {};
|
|
378
|
+
try { errObj = JSON.parse(errText); } catch (_) {}
|
|
379
|
+
throw { message: errObj.message || errObj.error || "Erreur HTTP " + response.status, code: errObj.error_code || "PLU_HTTP_" + response.status };
|
|
380
|
+
}
|
|
381
|
+
var result = await response.json();
|
|
382
|
+
this.showResult(address, result);
|
|
383
|
+
this.events.emit("module:plu:resolved", result);
|
|
384
|
+
} catch (error) {
|
|
385
|
+
this.showError(
|
|
386
|
+
(error && error.message) || "Impossible de résoudre le PLU pour cette adresse.",
|
|
387
|
+
(error && error.code) || "PLU_UNKNOWN_ERROR"
|
|
388
|
+
);
|
|
389
|
+
this.events.emit("module:plu:error", { message: error && error.message, code: error && error.code });
|
|
390
|
+
}
|
|
391
|
+
};
|
|
392
|
+
|
|
393
|
+
PluModuleManager.prototype.showResult = function(address, data) {
|
|
394
|
+
var rulesHtml = "";
|
|
395
|
+
if (data.rules && data.rules.length) {
|
|
396
|
+
rulesHtml = '<div class="cm-plu-rules-title">Règles applicables :</div><ul class="cm-plu-rules-list">' +
|
|
397
|
+
data.rules.map(function(r) { return "<li>" + escapeHtml(typeof r === "string" ? r : (r.label || r.description || "")) + "</li>"; }).join("") + '</ul>';
|
|
398
|
+
}
|
|
399
|
+
var sourcesText = "";
|
|
400
|
+
if (data.sources && data.sources.length) {
|
|
401
|
+
sourcesText = "Sources : " + data.sources.map(function(s) { return escapeHtml(typeof s === "string" ? s : (s.name || "")); }).join(", ");
|
|
402
|
+
}
|
|
403
|
+
this.stateResultEl.innerHTML = [
|
|
404
|
+
'<h3 class="cm-plu-title">' + ICON_HOUSE + ' Résultat PLU</h3>',
|
|
405
|
+
'<div class="cm-plu-result-addr">' + ICON_PIN + '<div>' + escapeHtml(address.label) + '</div></div>',
|
|
406
|
+
'<div class="cm-plu-zone-card"><div class="cm-plu-zone-code">Zone : ' + escapeHtml(data.zone_code || "N/A") + '</div>',
|
|
407
|
+
'<div class="cm-plu-zone-label">' + escapeHtml(data.zone_label || "") + '</div>',
|
|
408
|
+
data.document_type ? '<div class="cm-plu-zone-doc">Document : ' + escapeHtml(data.document_type) + '</div>' : '',
|
|
409
|
+
'</div>', rulesHtml,
|
|
410
|
+
sourcesText ? '<div class="cm-plu-sources">' + sourcesText + '</div>' : '',
|
|
411
|
+
'<div class="cm-plu-disclaimer">' + ICON_WARN + '<div>' + escapeHtml(data.disclaimer || "Information indicative. Consultez le service urbanisme de votre mairie pour confirmation.") + '</div></div>',
|
|
412
|
+
'<button class="cm-plu-new-search-btn" type="button">' + ICON_SEARCH + ' Nouvelle recherche</button>'
|
|
413
|
+
].join("");
|
|
414
|
+
var self = this;
|
|
415
|
+
var newBtn = this.stateResultEl.querySelector(".cm-plu-new-search-btn");
|
|
416
|
+
if (newBtn) newBtn.addEventListener("click", function() { self.resetToInput(); });
|
|
417
|
+
this.showState("result");
|
|
418
|
+
};
|
|
419
|
+
|
|
420
|
+
PluModuleManager.prototype.showError = function(message, code) {
|
|
421
|
+
this.stateErrorEl.innerHTML = [
|
|
422
|
+
'<div class="cm-plu-error-icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><line x1="15" y1="9" x2="9" y2="15"/><line x1="9" y1="9" x2="15" y2="15"/></svg></div>',
|
|
423
|
+
'<div class="cm-plu-error-msg">' + escapeHtml(message) + '</div>',
|
|
424
|
+
code ? '<div class="cm-plu-error-code">' + escapeHtml(code) + '</div>' : '',
|
|
425
|
+
'<button class="cm-plu-retry-btn" type="button">' + ICON_SEARCH + ' Réessayer</button>'
|
|
426
|
+
].join("");
|
|
427
|
+
var self = this;
|
|
428
|
+
var retryBtn = this.stateErrorEl.querySelector(".cm-plu-retry-btn");
|
|
429
|
+
if (retryBtn) retryBtn.addEventListener("click", function() { self.resetToInput(); });
|
|
430
|
+
this.showState("error");
|
|
431
|
+
};
|
|
432
|
+
|
|
433
|
+
PluModuleManager.prototype.resetToInput = function() {
|
|
434
|
+
this.autocomplete.reset();
|
|
435
|
+
this.searchBtnEl.disabled = true;
|
|
436
|
+
this.showState("input");
|
|
437
|
+
};
|
|
438
|
+
|
|
439
|
+
PluModuleManager.prototype.createOpenButton = function() {
|
|
440
|
+
var btn = document.createElement("button");
|
|
441
|
+
btn.className = "cm-plu-open-btn";
|
|
442
|
+
btn.type = "button";
|
|
443
|
+
btn.innerHTML = ICON_HOUSE + 'Urbanisme';
|
|
444
|
+
var self = this;
|
|
445
|
+
btn.addEventListener("click", function() { self.open(); });
|
|
446
|
+
return btn;
|
|
447
|
+
};
|
|
448
|
+
|
|
449
|
+
function escapeHtml(str) {
|
|
450
|
+
var div = document.createElement("div");
|
|
451
|
+
div.textContent = String(str || "");
|
|
452
|
+
return div.innerHTML;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
runtime.PluModuleManager = PluModuleManager;
|
|
456
|
+
runtime.PluCssBuilder = PluCssBuilder;
|
|
457
|
+
runtime.BanAutocompleteManager = BanAutocompleteManager;
|
|
458
|
+
})();
|