arcane-os 0.1.0-dev.5
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/CHANGELOG.md +154 -0
- package/COMMERCIAL-LICENSE.md +13 -0
- package/LICENSE +661 -0
- package/NOTICE +70 -0
- package/README.md +448 -0
- package/bin/arcane-test.mjs +741 -0
- package/bin/arcane.mjs +5 -0
- package/docs/architecture.md +234 -0
- package/docs/compatibility.md +36 -0
- package/docs/event-manager.md +166 -0
- package/docs/platform-targets.md +108 -0
- package/docs/publishing.md +203 -0
- package/docs/reference/README.md +117 -0
- package/docs/reference/arcane-ollama.md +288 -0
- package/docs/reference/availability-and-normalization.md +123 -0
- package/docs/reference/behavioral-testing.md +86 -0
- package/docs/reference/cli.md +569 -0
- package/docs/reference/core/README.md +62 -0
- package/docs/reference/core/arcane-ai-contracts.md +873 -0
- package/docs/reference/core/arcane-api.md +601 -0
- package/docs/reference/core/arcane-entities.md +65 -0
- package/docs/reference/core/arcane-events.md +134 -0
- package/docs/reference/core/ollama-module.md +181 -0
- package/docs/reference/core/reference/arcane-api/ai-and-ollama.md +1909 -0
- package/docs/reference/core/reference/arcane-api/applications-terminal-capabilities.md +1057 -0
- package/docs/reference/core/reference/arcane-api/core-and-events.md +320 -0
- package/docs/reference/core/reference/arcane-api/filesystem-storage-preferences-appearance.md +610 -0
- package/docs/reference/core/reference/arcane-api/namespaces.md +1157 -0
- package/docs/reference/core/reference/arcane-api/platform-installation-users-system.md +1423 -0
- package/docs/reference/core/reference/arcane-api/session-provisioning-diagnostics-development.md +315 -0
- package/docs/reference/event-manager.md +957 -0
- package/docs/reference/inventory/package-api.json +2632 -0
- package/docs/reference/inventory/runtime-components.json +934 -0
- package/docs/reference/inventory/runtime-entities.json +26 -0
- package/docs/reference/inventory/runtime-modules.json +1249 -0
- package/docs/reference/protocols.md +242 -0
- package/docs/reference/runtime-components.md +1098 -0
- package/docs/reference/runtime-entities.md +303 -0
- package/docs/reference/runtime-modules.md +2010 -0
- package/docs/reference/sdk-api.md +4901 -0
- package/docs/roadmap.md +79 -0
- package/docs/work-amplification.md +124 -0
- package/node_modules/event-pubsub/CHANGELOG.md +55 -0
- package/node_modules/event-pubsub/MIGRATION.md +70 -0
- package/node_modules/event-pubsub/README.md +363 -0
- package/node_modules/event-pubsub/SECURITY.md +37 -0
- package/node_modules/event-pubsub/index.js +141 -0
- package/node_modules/event-pubsub/licence +21 -0
- package/node_modules/event-pubsub/package.json +59 -0
- package/node_modules/strong-type/README.md +408 -0
- package/node_modules/strong-type/assets/strong-type-header.png +0 -0
- package/node_modules/strong-type/index.js +1151 -0
- package/node_modules/strong-type/licence +21 -0
- package/node_modules/strong-type/node.js +125 -0
- package/node_modules/strong-type/package.json +61 -0
- package/package.json +95 -0
- package/runtime/ARCANE_RUNTIME_RELEASE.json +791 -0
- package/runtime/arcane/components/app-bar.html +468 -0
- package/runtime/arcane/components/assistant-panel.html +715 -0
- package/runtime/arcane/components/calculator.html +8 -0
- package/runtime/arcane/components/chart.html +655 -0
- package/runtime/arcane/components/chat.html +1225 -0
- package/runtime/arcane/components/conversation-view.html +13 -0
- package/runtime/arcane/components/dashboard-config.html +341 -0
- package/runtime/arcane/components/data-maintenance.html +112 -0
- package/runtime/arcane/components/data-view.html +92 -0
- package/runtime/arcane/components/directory-picker.html +197 -0
- package/runtime/arcane/components/document-inspector.html +252 -0
- package/runtime/arcane/components/file-drop.html +264 -0
- package/runtime/arcane/components/file-inspector.html +293 -0
- package/runtime/arcane/components/file-manager.html +1715 -0
- package/runtime/arcane/components/header.html +142 -0
- package/runtime/arcane/components/integration-settings.html +14 -0
- package/runtime/arcane/components/local-ai-status.html +360 -0
- package/runtime/arcane/components/markdown-document.html +1048 -0
- package/runtime/arcane/components/markdown-editor.html +360 -0
- package/runtime/arcane/components/media-embed.html +8 -0
- package/runtime/arcane/components/modal.html +402 -0
- package/runtime/arcane/components/output-panel.html +259 -0
- package/runtime/arcane/components/preferences-form.html +135 -0
- package/runtime/arcane/components/record-timeline.html +105 -0
- package/runtime/arcane/components/relationship-board.html +116 -0
- package/runtime/arcane/components/screen-capture.html +8 -0
- package/runtime/arcane/components/source-code-viewer.html +441 -0
- package/runtime/arcane/components/source-explanation.html +124 -0
- package/runtime/arcane/components/speech.html +365 -0
- package/runtime/arcane/components/summary-strip.html +177 -0
- package/runtime/arcane/components/table.html +77 -0
- package/runtime/arcane/components/task-progress.html +282 -0
- package/runtime/arcane/components/terminal-workspace.html +65 -0
- package/runtime/arcane/components/theme-editor.html +41 -0
- package/runtime/arcane/components/theme-switcher.html +46 -0
- package/runtime/arcane/components/unified-inbox.html +20 -0
- package/runtime/arcane/components/voice-transcription.html +476 -0
- package/runtime/arcane/components/weather-widget.html +8 -0
- package/runtime/arcane/components/web-navigator.html +239 -0
- package/runtime/arcane/css/communications.css +1 -0
- package/runtime/arcane/css/dashboard-config.css +45 -0
- package/runtime/arcane/css/document-site.css +981 -0
- package/runtime/arcane/css/layout.css +438 -0
- package/runtime/arcane/css/primitives.css +321 -0
- package/runtime/arcane/css/theme.css +112 -0
- package/runtime/arcane/css/utility-workspace.css +1 -0
- package/runtime/arcane/entities/ApiModelRecord.js +20 -0
- package/runtime/arcane/entities/Calculation.js +13 -0
- package/runtime/arcane/entities/Chat.js +581 -0
- package/runtime/arcane/entities/CommunicationMessage.js +29 -0
- package/runtime/arcane/entities/CommunicationThread.js +21 -0
- package/runtime/arcane/entities/Document.js +10 -0
- package/runtime/arcane/entities/File.js +143 -0
- package/runtime/arcane/entities/Image.js +135 -0
- package/runtime/arcane/entities/IntentEnvelope.js +834 -0
- package/runtime/arcane/entities/Preference.js +83 -0
- package/runtime/arcane/entities/TWiNPolicyDecision.js +1092 -0
- package/runtime/arcane/entities/TerminalSession.js +46 -0
- package/runtime/arcane/entities/Theme.js +107 -0
- package/runtime/arcane/entities/User.js +1046 -0
- package/runtime/arcane/entities/Weather.js +23 -0
- package/runtime/arcane/img/arcane-os-everywhere.png +0 -0
- package/runtime/arcane/img/arrow-left.png +0 -0
- package/runtime/arcane/img/arrow-right.png +0 -0
- package/runtime/arcane/img/doc.svg +5 -0
- package/runtime/arcane/img/folder.svg +4 -0
- package/runtime/arcane/img/image.svg +5 -0
- package/runtime/arcane/img/refresh.png +0 -0
- package/runtime/arcane/img/send.svg +9 -0
- package/runtime/arcane/img/trash.svg +5 -0
- package/runtime/arcane/img/upload.svg +5 -0
- package/runtime/arcane/modules/AI.js +2048 -0
- package/runtime/arcane/modules/AIPreferenceRuntime.js +32 -0
- package/runtime/arcane/modules/AIPreferenceTuple.js +92 -0
- package/runtime/arcane/modules/AIResponseLength.js +42 -0
- package/runtime/arcane/modules/AIResponseURLPolicy.js +626 -0
- package/runtime/arcane/modules/AnsiText.js +53 -0
- package/runtime/arcane/modules/ApiModelDatabase.js +25 -0
- package/runtime/arcane/modules/AppDataScope.js +245 -0
- package/runtime/arcane/modules/AppearancePreferences.js +28 -0
- package/runtime/arcane/modules/ArcaneCommunicationBridge.js +22 -0
- package/runtime/arcane/modules/ArcaneNavigationPolicy.js +135 -0
- package/runtime/arcane/modules/ArcaneNetworkPolicy.js +255 -0
- package/runtime/arcane/modules/AsyncBoundary.js +161 -0
- package/runtime/arcane/modules/BrowserTestSuite.js +326 -0
- package/runtime/arcane/modules/CalculatorEngine.js +20 -0
- package/runtime/arcane/modules/CaseEvidenceIndexer.js +134 -0
- package/runtime/arcane/modules/ChartLibrary.js +35 -0
- package/runtime/arcane/modules/ChatRecords.js +13 -0
- package/runtime/arcane/modules/CommunicationAppController.js +43 -0
- package/runtime/arcane/modules/CommunicationHub.js +16 -0
- package/runtime/arcane/modules/CommunicationPreferences.js +13 -0
- package/runtime/arcane/modules/CommunicationProviderRegistry.js +16 -0
- package/runtime/arcane/modules/ComponentContracts.js +586 -0
- package/runtime/arcane/modules/ConfiguredAIChatSession.js +288 -0
- package/runtime/arcane/modules/ConversationActionItems.js +488 -0
- package/runtime/arcane/modules/ConversationClosingReport.js +274 -0
- package/runtime/arcane/modules/ConversationTimebox.js +527 -0
- package/runtime/arcane/modules/CoreLocalModelCatalog.js +255 -0
- package/runtime/arcane/modules/DBLS.js +171 -0
- package/runtime/arcane/modules/DBOPFS.js +1154 -0
- package/runtime/arcane/modules/DBOPFSWorker.js +116 -0
- package/runtime/arcane/modules/DataMaintenance.js +91 -0
- package/runtime/arcane/modules/DevelopmentWorkspace.js +74 -0
- package/runtime/arcane/modules/DirectoryPicker.js +109 -0
- package/runtime/arcane/modules/DocumentNavigation.js +223 -0
- package/runtime/arcane/modules/Errors.js +1025 -0
- package/runtime/arcane/modules/GifEncoder.js +29 -0
- package/runtime/arcane/modules/HTMLImport.js +114 -0
- package/runtime/arcane/modules/InMemoryCommunicationProvider.js +14 -0
- package/runtime/arcane/modules/IsolatedModelQuestionRunner.js +275 -0
- package/runtime/arcane/modules/LocalAIReadiness.js +870 -0
- package/runtime/arcane/modules/LocalAIReadinessController.js +156 -0
- package/runtime/arcane/modules/MD.js +111 -0
- package/runtime/arcane/modules/Mail.js +352 -0
- package/runtime/arcane/modules/MailTransport.mjs +180 -0
- package/runtime/arcane/modules/Marked.min.js +71 -0
- package/runtime/arcane/modules/MemoryRecords.js +44 -0
- package/runtime/arcane/modules/MessageAdvisory.js +38 -0
- package/runtime/arcane/modules/ModelDefinition.js +189 -0
- package/runtime/arcane/modules/Ollama.js +74 -0
- package/runtime/arcane/modules/OllamaModelIdentifier.js +21 -0
- package/runtime/arcane/modules/OllamaSettings.js +24 -0
- package/runtime/arcane/modules/OpenMeteoWeatherProvider.js +14 -0
- package/runtime/arcane/modules/PreferenceStore.js +109 -0
- package/runtime/arcane/modules/QRCode.min.js +1 -0
- package/runtime/arcane/modules/Questionnaire.js +61 -0
- package/runtime/arcane/modules/RecordLinkIndex.js +24 -0
- package/runtime/arcane/modules/RecordPassageIndex.js +222 -0
- package/runtime/arcane/modules/RecordReviewStore.js +94 -0
- package/runtime/arcane/modules/RevocableProjectionLedger.js +1623 -0
- package/runtime/arcane/modules/RiskSignalAnalyzer.js +37 -0
- package/runtime/arcane/modules/ScamRiskPolicy.js +62 -0
- package/runtime/arcane/modules/ScopedOPFSCache.js +183 -0
- package/runtime/arcane/modules/ScreenCapture.js +20 -0
- package/runtime/arcane/modules/SpeechPlayback.js +581 -0
- package/runtime/arcane/modules/StaticDocumentCatalog.js +1248 -0
- package/runtime/arcane/modules/SystemAppearance.js +20 -0
- package/runtime/arcane/modules/SystemPlatformPresentation.js +51 -0
- package/runtime/arcane/modules/SystemToolRegistry.js +28 -0
- package/runtime/arcane/modules/TerminalClient.js +52 -0
- package/runtime/arcane/modules/TerminalCommandRegistry.js +50 -0
- package/runtime/arcane/modules/ThemeBootstrap.js +26 -0
- package/runtime/arcane/modules/ThemeManager.js +131 -0
- package/runtime/arcane/modules/TimeGuard.js +149 -0
- package/runtime/arcane/modules/ToolCallRouter.js +83 -0
- package/runtime/arcane/modules/WaitForComponent.js +102 -0
- package/runtime/arcane/modules/YouTubeMedia.js +16 -0
- package/runtime/arcane/modules/uPlot.LICENSE.txt +21 -0
- package/runtime/arcane/modules/uPlot.iife.min.js +2 -0
- package/runtime/arcane/modules/uPlot.min.css +1 -0
- package/runtime/arcane/security/arcane-network-policy.json +6 -0
- package/runtime/strong-type/index.js +352 -0
- package/runtime/strong-type/licence +21 -0
- package/runtime/strong-type/package.json +45 -0
- package/schemas/arcane-app-bundle.schema.json +125 -0
- package/schemas/arcane-app.schema.json +329 -0
- package/schemas/arcane-lock.schema.json +86 -0
- package/schemas/arcane-package.schema.json +224 -0
- package/schemas/cli-event.schema.json +122 -0
- package/schemas/event-stack.schema.json +152 -0
- package/schemas/native-build-plan.schema.json +176 -0
- package/schemas/target-adapter.schema.json +117 -0
- package/src/app-descriptor.mjs +500 -0
- package/src/cli/main.mjs +561 -0
- package/src/constants.mjs +31 -0
- package/src/dev-server.mjs +718 -0
- package/src/doctor.mjs +315 -0
- package/src/dom-event-instrumentation.mjs +594 -0
- package/src/errors.mjs +75 -0
- package/src/event-manager.mjs +1342 -0
- package/src/event-queue.mjs +138 -0
- package/src/events.mjs +219 -0
- package/src/index.mjs +177 -0
- package/src/integrated-provider-loader.mjs +432 -0
- package/src/native-plan.mjs +698 -0
- package/src/native-provider-loader.mjs +1126 -0
- package/src/packager/core.mjs +2691 -0
- package/src/process.mjs +353 -0
- package/src/release-bundle.mjs +2523 -0
- package/src/repository.mjs +90 -0
- package/src/runtime.mjs +452 -0
- package/src/scaffold.mjs +380 -0
- package/src/targets/index.mjs +436 -0
- package/src/templates/assets/app-icon.png +0 -0
- package/src/templates/workspace-template.mjs +388 -0
- package/src/testing-loader.mjs +9 -0
- package/src/testing.mjs +427 -0
- package/src/toolchain.mjs +1335 -0
- package/src/update-check.mjs +307 -0
- package/src/workspace.mjs +449 -0
|
@@ -0,0 +1,441 @@
|
|
|
1
|
+
<link rel="stylesheet" href="./arcane/css/layout.css?v=3">
|
|
2
|
+
<link rel="stylesheet" href="./arcane/css/theme.css?v=1">
|
|
3
|
+
<link rel="stylesheet" href="./arcane/css/primitives.css?v=1">
|
|
4
|
+
|
|
5
|
+
<style>
|
|
6
|
+
:host{
|
|
7
|
+
color:var(--text-color);
|
|
8
|
+
display:block;
|
|
9
|
+
min-width:0;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
[hidden]{
|
|
13
|
+
display:none !important;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.source-viewer{
|
|
17
|
+
min-width:0;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.source-state{
|
|
21
|
+
background:var(--secondary-color);
|
|
22
|
+
border:1px solid var(--border-color);
|
|
23
|
+
border-radius:.5rem;
|
|
24
|
+
color:var(--muted-text-color);
|
|
25
|
+
margin:0;
|
|
26
|
+
padding:1rem;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.source-state[data-state="error"]{
|
|
30
|
+
border-inline-start:.3rem solid var(--danger-color);
|
|
31
|
+
color:var(--text-color);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.source-header{
|
|
35
|
+
align-items:flex-start;
|
|
36
|
+
border-block-end:1px solid var(--border-color);
|
|
37
|
+
display:flex;
|
|
38
|
+
flex-wrap:wrap;
|
|
39
|
+
gap:1rem;
|
|
40
|
+
justify-content:space-between;
|
|
41
|
+
margin-block-end:1rem;
|
|
42
|
+
padding-block-end:1rem;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.source-title{
|
|
46
|
+
font-size:clamp(1.1rem,2vw,1.45rem);
|
|
47
|
+
margin:.15rem 0 0;
|
|
48
|
+
overflow-wrap:anywhere;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.source-path,
|
|
52
|
+
.source-language{
|
|
53
|
+
color:var(--muted-text-color);
|
|
54
|
+
font-family:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace;
|
|
55
|
+
font-size:.82rem;
|
|
56
|
+
margin:0;
|
|
57
|
+
overflow-wrap:anywhere;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.source-language{
|
|
61
|
+
margin-block-start:.35rem;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.repository-link{
|
|
65
|
+
color:var(--focus-color);
|
|
66
|
+
flex:none;
|
|
67
|
+
text-underline-offset:.15em;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.repository-link:focus-visible{
|
|
71
|
+
border-radius:.2rem;
|
|
72
|
+
outline:3px solid var(--focus-color);
|
|
73
|
+
outline-offset:.2rem;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.source-scroll{
|
|
77
|
+
background:var(--secondary-color);
|
|
78
|
+
border:1px solid var(--border-color);
|
|
79
|
+
border-radius:.5rem;
|
|
80
|
+
max-block-size:min(72vh,60rem);
|
|
81
|
+
overflow:auto;
|
|
82
|
+
overscroll-behavior:contain;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.source-lines{
|
|
86
|
+
counter-reset:source-line;
|
|
87
|
+
font-family:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", monospace;
|
|
88
|
+
font-size:.88rem;
|
|
89
|
+
line-height:1.55;
|
|
90
|
+
list-style:none;
|
|
91
|
+
margin:0;
|
|
92
|
+
min-inline-size:max-content;
|
|
93
|
+
padding:.75rem 0;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
.source-line{
|
|
97
|
+
counter-increment:source-line;
|
|
98
|
+
display:grid;
|
|
99
|
+
grid-template-columns:minmax(3.5rem,auto) 1fr;
|
|
100
|
+
min-block-size:1.55em;
|
|
101
|
+
scroll-margin-block:4rem;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
.source-line::before{
|
|
105
|
+
border-inline-end:1px solid var(--border-color);
|
|
106
|
+
color:var(--muted-text-color);
|
|
107
|
+
content:counter(source-line);
|
|
108
|
+
padding-inline:.75rem;
|
|
109
|
+
text-align:end;
|
|
110
|
+
user-select:none;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
.source-line code{
|
|
114
|
+
color:var(--text-color);
|
|
115
|
+
padding-inline:1rem;
|
|
116
|
+
white-space:pre;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
.source-line:focus{
|
|
120
|
+
background:var(--modal-background);
|
|
121
|
+
outline:3px solid var(--focus-color);
|
|
122
|
+
outline-offset:-3px;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
@media (forced-colors:active){
|
|
126
|
+
.source-state,
|
|
127
|
+
.source-header,
|
|
128
|
+
.source-scroll,
|
|
129
|
+
.source-line::before{
|
|
130
|
+
border-color:CanvasText;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
.repository-link:focus-visible,
|
|
134
|
+
.source-line:focus{
|
|
135
|
+
outline-color:Highlight;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
@media (max-width:38rem){
|
|
140
|
+
.source-header{
|
|
141
|
+
align-items:stretch;
|
|
142
|
+
flex-direction:column;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
</style>
|
|
146
|
+
|
|
147
|
+
<section id="viewer" class="source-viewer" part="container" aria-busy="false">
|
|
148
|
+
<p
|
|
149
|
+
id="status"
|
|
150
|
+
class="source-state"
|
|
151
|
+
part="status"
|
|
152
|
+
role="status"
|
|
153
|
+
aria-live="polite"
|
|
154
|
+
aria-atomic="true"
|
|
155
|
+
tabindex="-1"
|
|
156
|
+
></p>
|
|
157
|
+
|
|
158
|
+
<header id="sourceHeader" class="source-header" part="header" hidden>
|
|
159
|
+
<div>
|
|
160
|
+
<p id="sourcePath" class="source-path"></p>
|
|
161
|
+
<h2 id="sourceTitle" class="source-title"></h2>
|
|
162
|
+
<p id="sourceLanguage" class="source-language"></p>
|
|
163
|
+
</div>
|
|
164
|
+
<a
|
|
165
|
+
id="repositoryLink"
|
|
166
|
+
class="repository-link"
|
|
167
|
+
target="_blank"
|
|
168
|
+
rel="noopener noreferrer"
|
|
169
|
+
referrerpolicy="no-referrer"
|
|
170
|
+
hidden
|
|
171
|
+
>View repository source</a>
|
|
172
|
+
</header>
|
|
173
|
+
|
|
174
|
+
<div id="sourceScroll" class="source-scroll" part="source-scroll" hidden>
|
|
175
|
+
<ol id="sourceLines" class="source-lines" part="source-lines"></ol>
|
|
176
|
+
</div>
|
|
177
|
+
</section>
|
|
178
|
+
|
|
179
|
+
<script type="module">
|
|
180
|
+
const host=this;
|
|
181
|
+
host.ready=false;
|
|
182
|
+
|
|
183
|
+
const viewer=host.shadowRoot.querySelector('#viewer');
|
|
184
|
+
const status=host.shadowRoot.querySelector('#status');
|
|
185
|
+
const sourceHeader=host.shadowRoot.querySelector('#sourceHeader');
|
|
186
|
+
const sourcePathElement=host.shadowRoot.querySelector('#sourcePath');
|
|
187
|
+
const sourceTitle=host.shadowRoot.querySelector('#sourceTitle');
|
|
188
|
+
const sourceLanguage=host.shadowRoot.querySelector('#sourceLanguage');
|
|
189
|
+
const repositoryLink=host.shadowRoot.querySelector('#repositoryLink');
|
|
190
|
+
const sourceScroll=host.shadowRoot.querySelector('#sourceScroll');
|
|
191
|
+
const sourceLines=host.shadowRoot.querySelector('#sourceLines');
|
|
192
|
+
|
|
193
|
+
const MAXIMUM_CHARACTERS=1048576;
|
|
194
|
+
const MAXIMUM_LINES=20000;
|
|
195
|
+
const defaultOptions=Object.freeze({
|
|
196
|
+
labels:Object.freeze({
|
|
197
|
+
content:'Source code',
|
|
198
|
+
empty:'Choose a source file from the catalog.',
|
|
199
|
+
error:'This source file could not be displayed.',
|
|
200
|
+
loading:'Loading and verifying source code…',
|
|
201
|
+
repository:'View repository source'
|
|
202
|
+
})
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
let current=Object.freeze({
|
|
206
|
+
language:'text',
|
|
207
|
+
lineCount:0,
|
|
208
|
+
repositoryURL:'',
|
|
209
|
+
sourcePath:'',
|
|
210
|
+
text:'',
|
|
211
|
+
title:''
|
|
212
|
+
});
|
|
213
|
+
let loadSequence=0;
|
|
214
|
+
let options=normalizeOptions({},defaultOptions);
|
|
215
|
+
let state='empty';
|
|
216
|
+
|
|
217
|
+
host.clear=clear;
|
|
218
|
+
host.configure=configure;
|
|
219
|
+
host.fail=fail;
|
|
220
|
+
host.focus=focusSource;
|
|
221
|
+
host.focusLine=focusLine;
|
|
222
|
+
host.load=load;
|
|
223
|
+
host.render=render;
|
|
224
|
+
|
|
225
|
+
Object.defineProperties(host,{
|
|
226
|
+
lineCount:{get:()=>current.lineCount},
|
|
227
|
+
sourcePath:{get:()=>current.sourcePath},
|
|
228
|
+
state:{get:()=>state},
|
|
229
|
+
value:{get:()=>current.text,set:value=>render(value)}
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
function boundedText(value,label,maximum,{optional=false}={}){
|
|
233
|
+
if(optional&&(value===undefined||value===null||value===''))return '';
|
|
234
|
+
if(typeof value!=='string'||!value.trim()||value.length>maximum||/[\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F]/.test(value)){
|
|
235
|
+
throw new TypeError(`${label} must be bounded text.`);
|
|
236
|
+
}
|
|
237
|
+
return value.trim();
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
function safeRepositoryURL(value=''){
|
|
241
|
+
if(value===undefined||value===null||value==='')return '';
|
|
242
|
+
const input=boundedText(value,'Source repositoryURL',2048);
|
|
243
|
+
try{
|
|
244
|
+
const url=new URL(input,document.baseURI);
|
|
245
|
+
if(!['http:','https:'].includes(url.protocol)||url.username||url.password){
|
|
246
|
+
throw new TypeError('Source repositoryURL must use HTTP(S) without credentials.');
|
|
247
|
+
}
|
|
248
|
+
return url.href;
|
|
249
|
+
}catch(error){
|
|
250
|
+
if(error instanceof TypeError&&/repositoryURL/.test(error.message))throw error;
|
|
251
|
+
throw new TypeError('Source repositoryURL must be a valid HTTP(S) URL.');
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
function normalizeOptions(input={},previous=defaultOptions){
|
|
256
|
+
if(!input||typeof input!=='object'||Array.isArray(input)){
|
|
257
|
+
throw new TypeError('Source viewer options must be an object.');
|
|
258
|
+
}
|
|
259
|
+
const labelInput=input.labels===undefined?{}:input.labels;
|
|
260
|
+
if(!labelInput||typeof labelInput!=='object'||Array.isArray(labelInput)){
|
|
261
|
+
throw new TypeError('Source viewer labels must be an object.');
|
|
262
|
+
}
|
|
263
|
+
const labels={...previous.labels};
|
|
264
|
+
for(const name of ['content','empty','error','loading','repository']){
|
|
265
|
+
if(labelInput[name]!==undefined){
|
|
266
|
+
labels[name]=boundedText(labelInput[name],`Source viewer labels.${name}`,160);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
return Object.freeze({labels:Object.freeze(labels)});
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
function normalizeRenderOptions(input={}){
|
|
273
|
+
if(!input||typeof input!=='object'||Array.isArray(input)){
|
|
274
|
+
throw new TypeError('Source render options must be an object.');
|
|
275
|
+
}
|
|
276
|
+
return Object.freeze({
|
|
277
|
+
language:boundedText(input.language||'text','Source language',64).toLowerCase(),
|
|
278
|
+
repositoryURL:safeRepositoryURL(input.repositoryURL),
|
|
279
|
+
sourcePath:boundedText(input.sourcePath||'Source file','Source path',1024),
|
|
280
|
+
title:boundedText(input.title||input.sourcePath||'Source file','Source title',256)
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
function configure(input={}){
|
|
285
|
+
options=normalizeOptions(input,options);
|
|
286
|
+
repositoryLink.textContent=options.labels.repository;
|
|
287
|
+
updateStateDOM();
|
|
288
|
+
return {labels:{...options.labels}};
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
async function load(source='',renderOptions={}){
|
|
292
|
+
const sequence=++loadSequence;
|
|
293
|
+
transition('loading');
|
|
294
|
+
try{
|
|
295
|
+
const pending=typeof source==='function'?source():source;
|
|
296
|
+
const result=await pending;
|
|
297
|
+
if(sequence!==loadSequence)return false;
|
|
298
|
+
if(result&&typeof result==='object'&&!Array.isArray(result)){
|
|
299
|
+
return renderSource(result.text??result.value??'',{
|
|
300
|
+
...renderOptions,
|
|
301
|
+
...result
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
return renderSource(result??'',renderOptions);
|
|
305
|
+
}catch(error){
|
|
306
|
+
if(sequence===loadSequence)showError(error);
|
|
307
|
+
return false;
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
function render(text='',renderOptions={}){
|
|
312
|
+
++loadSequence;
|
|
313
|
+
try{
|
|
314
|
+
return renderSource(text,renderOptions);
|
|
315
|
+
}catch(error){
|
|
316
|
+
showError(error);
|
|
317
|
+
return false;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
function renderSource(text='',renderOptions={}){
|
|
322
|
+
if(typeof text!=='string')throw new TypeError('Source content must be a string.');
|
|
323
|
+
if(text.length>MAXIMUM_CHARACTERS)throw new RangeError('Source content exceeds the viewer character limit.');
|
|
324
|
+
const metadata=normalizeRenderOptions(renderOptions);
|
|
325
|
+
const lines=text.replace(/\r\n?/g,'\n').split('\n');
|
|
326
|
+
if(lines.length>MAXIMUM_LINES)throw new RangeError('Source content exceeds the viewer line limit.');
|
|
327
|
+
|
|
328
|
+
sourceLines.replaceChildren();
|
|
329
|
+
if(!text){
|
|
330
|
+
current=Object.freeze({...metadata,lineCount:0,text:''});
|
|
331
|
+
transition('empty');
|
|
332
|
+
return true;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
const fragment=document.createDocumentFragment();
|
|
336
|
+
lines.forEach((line,index)=>{
|
|
337
|
+
const item=document.createElement('li');
|
|
338
|
+
const code=document.createElement('code');
|
|
339
|
+
const lineNumber=index+1;
|
|
340
|
+
item.className='source-line';
|
|
341
|
+
item.id=`L${lineNumber}`;
|
|
342
|
+
item.tabIndex=-1;
|
|
343
|
+
item.dataset.line=String(lineNumber);
|
|
344
|
+
code.textContent=line||' ';
|
|
345
|
+
item.append(code);
|
|
346
|
+
fragment.append(item);
|
|
347
|
+
});
|
|
348
|
+
sourceLines.replaceChildren(fragment);
|
|
349
|
+
current=Object.freeze({...metadata,lineCount:lines.length,text});
|
|
350
|
+
transition('ready');
|
|
351
|
+
return true;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
function clear(){
|
|
355
|
+
++loadSequence;
|
|
356
|
+
sourceLines.replaceChildren();
|
|
357
|
+
current=Object.freeze({
|
|
358
|
+
language:'text',
|
|
359
|
+
lineCount:0,
|
|
360
|
+
repositoryURL:'',
|
|
361
|
+
sourcePath:'',
|
|
362
|
+
text:'',
|
|
363
|
+
title:''
|
|
364
|
+
});
|
|
365
|
+
transition('empty');
|
|
366
|
+
return true;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
function fail(error){
|
|
370
|
+
++loadSequence;
|
|
371
|
+
showError(error);
|
|
372
|
+
return false;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
function showError(error){
|
|
376
|
+
sourceLines.replaceChildren();
|
|
377
|
+
transition('error',error);
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
function focusSource(){
|
|
381
|
+
const target=state==='ready'?sourceLines.querySelector('.source-line'):status;
|
|
382
|
+
target?.focus({preventScroll:true});
|
|
383
|
+
return Boolean(target);
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
function focusLine(value){
|
|
387
|
+
const line=Number(value);
|
|
388
|
+
if(!Number.isInteger(line)||line<1||line>current.lineCount)return false;
|
|
389
|
+
const target=sourceLines.querySelector(`[data-line="${line}"]`);
|
|
390
|
+
if(!target)return false;
|
|
391
|
+
target.focus({preventScroll:true});
|
|
392
|
+
target.scrollIntoView({block:'center',inline:'nearest'});
|
|
393
|
+
return true;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
function transition(next,error=null){
|
|
397
|
+
state=next;
|
|
398
|
+
updateStateDOM();
|
|
399
|
+
const detail={
|
|
400
|
+
characters:current.text.length,
|
|
401
|
+
language:current.language,
|
|
402
|
+
lines:current.lineCount,
|
|
403
|
+
sourcePath:current.sourcePath,
|
|
404
|
+
state
|
|
405
|
+
};
|
|
406
|
+
if(error)detail.message=String(error?.message||'Source rendering failed.').slice(0,512);
|
|
407
|
+
host.dispatchEvent(new CustomEvent('source-code-viewer-state',{bubbles:true,composed:true,detail}));
|
|
408
|
+
host.dispatchEvent(new CustomEvent(`source-code-viewer-${state}`,{bubbles:true,composed:true,detail}));
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
function updateStateDOM(){
|
|
412
|
+
const visible=state!=='ready';
|
|
413
|
+
viewer.setAttribute('aria-busy',state==='loading'?'true':'false');
|
|
414
|
+
status.hidden=!visible;
|
|
415
|
+
status.dataset.state=state;
|
|
416
|
+
status.textContent={
|
|
417
|
+
empty:options.labels.empty,
|
|
418
|
+
error:options.labels.error,
|
|
419
|
+
loading:options.labels.loading
|
|
420
|
+
}[state]||'';
|
|
421
|
+
sourceHeader.hidden=state!=='ready';
|
|
422
|
+
sourceScroll.hidden=state!=='ready';
|
|
423
|
+
sourceScroll.setAttribute('aria-label',`${options.labels.content}: ${current.sourcePath||current.title}`);
|
|
424
|
+
sourcePathElement.textContent=current.sourcePath;
|
|
425
|
+
sourceTitle.textContent=current.title;
|
|
426
|
+
sourceLanguage.textContent=current.language?`Language: ${current.language}`:'';
|
|
427
|
+
repositoryLink.textContent=options.labels.repository;
|
|
428
|
+
repositoryLink.hidden=!current.repositoryURL;
|
|
429
|
+
if(current.repositoryURL)repositoryLink.href=current.repositoryURL;
|
|
430
|
+
else repositoryLink.removeAttribute('href');
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
repositoryLink.textContent=options.labels.repository;
|
|
434
|
+
transition('empty');
|
|
435
|
+
host.ready=true;
|
|
436
|
+
host.dispatchEvent(new CustomEvent('source-code-viewer-ready',{
|
|
437
|
+
bubbles:true,
|
|
438
|
+
composed:true,
|
|
439
|
+
detail:{component:host,state}
|
|
440
|
+
}));
|
|
441
|
+
</script>
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
<style>
|
|
2
|
+
:host{display:block;color:var(--text-color);font-family:Inter,Segoe UI,sans-serif}
|
|
3
|
+
*{box-sizing:border-box}
|
|
4
|
+
.shell{display:grid;gap:1rem}
|
|
5
|
+
.lede{display:grid;gap:.55rem;padding:.9rem 1rem;border:1px solid var(--border-color);border-left:.38rem solid var(--accent-color);border-radius:.6rem;background:var(--modal-background)}
|
|
6
|
+
.badges{display:flex;gap:.4rem;flex-wrap:wrap}.badge{padding:.22rem .48rem;border:1px solid var(--border-color);border-radius:99rem;font-size:.68rem;font-weight:800}
|
|
7
|
+
h3{margin:0;font-size:1rem}p{margin:0;line-height:1.55}.lede p{font-weight:700}
|
|
8
|
+
.analysis{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:.8rem}
|
|
9
|
+
.section{display:grid;align-content:start;gap:.55rem;padding:.85rem;border:1px solid var(--border-color);border-radius:.55rem;background:var(--modal-background)}
|
|
10
|
+
.section ul{display:grid;gap:.4rem;margin:0;padding-left:1.2rem}.section li,.section p{font-size:.82rem;line-height:1.5}
|
|
11
|
+
.evidence-layout{display:grid;grid-template-columns:minmax(18rem,.85fr) minmax(24rem,1.15fr);gap:.8rem}
|
|
12
|
+
.evidence-list{display:grid;align-content:start;gap:.55rem;max-height:34rem;overflow:auto}
|
|
13
|
+
.evidence{display:grid;gap:.45rem;padding:.7rem;border:1px solid var(--border-color);border-radius:.5rem;background:var(--modal-background)}
|
|
14
|
+
.evidence header{display:flex;justify-content:space-between;gap:.5rem;font-size:.72rem}.evidence header strong{overflow-wrap:anywhere}.evidence header span{flex:0 0 auto;color:var(--platinum)}
|
|
15
|
+
blockquote{margin:0;padding:.65rem;border-left:.25rem solid var(--border-color);background:var(--background);font-size:.78rem;line-height:1.55}
|
|
16
|
+
.original{display:grid;grid-template-rows:auto minmax(28rem,1fr);gap:.45rem;min-width:0}.original-toolbar{display:grid;grid-template-columns:minmax(12rem,.8fr) minmax(12rem,1.2fr);align-items:end;gap:.65rem}.original-toolbar label{display:grid;gap:.25rem;font-size:.72rem;font-weight:800}.original-toolbar select{width:100%;margin:0}.original p{color:var(--platinum);font-size:.75rem}.original iframe{width:100%;height:min(60vh,38rem);min-height:28rem;border:1px solid var(--border-color);border-radius:.5rem;background:rgb(245,245,245)}
|
|
17
|
+
.review{display:grid;grid-template-columns:repeat(3,minmax(10rem,1fr));gap:.7rem;padding:.85rem;border:1px solid var(--border-color);border-radius:.55rem;background:var(--modal-background)}
|
|
18
|
+
.review h3,.review .notes,.save-row{grid-column:1/-1}.review label{display:grid;gap:.3rem;font-size:.75rem;font-weight:800}.review select,.review textarea{width:100%;margin:0}.review textarea{min-height:6rem;resize:vertical}.save-row{display:flex;align-items:center;gap:.8rem}.save-row button{margin:0}.save-state{color:var(--platinum);font-size:.78rem}
|
|
19
|
+
button:focus-visible,select:focus-visible,textarea:focus-visible{outline:.18rem solid var(--focus-color);outline-offset:.12rem}
|
|
20
|
+
.empty{padding:.8rem;border:1px dashed var(--border-color);border-radius:.5rem;color:var(--platinum)}
|
|
21
|
+
@media(max-width:56rem){.analysis,.evidence-layout,.review,.original-toolbar{grid-template-columns:1fr}.review h3,.review .notes,.save-row{grid-column:1}.original{grid-template-rows:auto auto}.original iframe{min-height:24rem}}
|
|
22
|
+
@media(forced-colors:active){.lede,.section,.evidence,.original iframe,.review{border-color:CanvasText}}
|
|
23
|
+
</style>
|
|
24
|
+
|
|
25
|
+
<section class="shell" data-shell>
|
|
26
|
+
<header class="lede"><div class="badges" data-badges></div><h3 data-title>Investigative lead</h3><p data-assessment></p></header>
|
|
27
|
+
<div class="analysis">
|
|
28
|
+
<section class="section"><h3>What the allegation would require</h3><ul data-elements></ul></section>
|
|
29
|
+
<section class="section"><h3>How the cited facts apply</h3><p data-application></p></section>
|
|
30
|
+
<section class="section"><h3>What may weaken or defeat the allegation</h3><ul data-limitations></ul></section>
|
|
31
|
+
<section class="section"><h3>Recommended verification</h3><ul data-next-steps></ul></section>
|
|
32
|
+
</div>
|
|
33
|
+
<section class="section"><h3>Evidence in support</h3><div class="evidence-layout"><div class="evidence-list" data-evidence></div><div class="original"><div class="original-toolbar"><label>Original cited source<select data-original-picker></select></label><p data-original-label aria-live="polite">Select a cited excerpt to inspect the original source page.</p></div><iframe data-original title="Original cited source" hidden></iframe></div></div></section>
|
|
34
|
+
<form class="review" data-review>
|
|
35
|
+
<h3>Investigator decision</h3>
|
|
36
|
+
<label>Alleged actor<select data-actor></select></label>
|
|
37
|
+
<label>Disposition<select data-disposition></select></label>
|
|
38
|
+
<label>Confidence<select data-confidence></select></label>
|
|
39
|
+
<label class="notes">Notes, contrary facts, and follow-up<textarea data-notes maxlength="10000"></textarea></label>
|
|
40
|
+
<div class="save-row"><button type="submit">Save decision</button><span class="save-state" data-save-state aria-live="polite"></span></div>
|
|
41
|
+
</form>
|
|
42
|
+
</section>
|
|
43
|
+
|
|
44
|
+
<script type="module">
|
|
45
|
+
const host=this; const root=host.shadowRoot;
|
|
46
|
+
const title=root.querySelector('[data-title]'); const assessment=root.querySelector('[data-assessment]'); const badges=root.querySelector('[data-badges]');
|
|
47
|
+
const elements=root.querySelector('[data-elements]'); const application=root.querySelector('[data-application]'); const limitations=root.querySelector('[data-limitations]'); const nextSteps=root.querySelector('[data-next-steps]');
|
|
48
|
+
const evidenceList=root.querySelector('[data-evidence]'); const original=root.querySelector('[data-original]'); const originalLabel=root.querySelector('[data-original-label]'); const originalPicker=root.querySelector('[data-original-picker]');
|
|
49
|
+
const reviewForm=root.querySelector('[data-review]'); const actor=root.querySelector('[data-actor]'); const disposition=root.querySelector('[data-disposition]'); const confidence=root.querySelector('[data-confidence]'); const notes=root.querySelector('[data-notes]'); const saveState=root.querySelector('[data-save-state]');
|
|
50
|
+
let finding=null; let sources=[];
|
|
51
|
+
|
|
52
|
+
host.showFinding=showFinding;
|
|
53
|
+
host.populate=(value={},options={})=>showFinding(value,options);
|
|
54
|
+
host.selectSource=selectSource;
|
|
55
|
+
host.markSaved=message=>{saveState.textContent=String(message||'Saved.');};
|
|
56
|
+
|
|
57
|
+
reviewForm.addEventListener('submit',event=>{
|
|
58
|
+
event.preventDefault(); if(!finding) return;
|
|
59
|
+
saveState.textContent='Saving…';
|
|
60
|
+
host.dispatchEvent(new CustomEvent('source-explanation-save',{bubbles:true,composed:true,detail:{recordId:finding.id,classification:actor.value,status:disposition.value,attributes:{confidence:confidence.value},notes:notes.value}}));
|
|
61
|
+
});
|
|
62
|
+
originalPicker.addEventListener('change',()=>showSource(Number(originalPicker.value)));
|
|
63
|
+
|
|
64
|
+
function options(select,values=[]){
|
|
65
|
+
select.replaceChildren(...values.map(value=>{const item=document.createElement('option'); item.value=String(value.value); item.textContent=String(value.label); return item;}));
|
|
66
|
+
}
|
|
67
|
+
function list(target,values=[],emptyLabel){
|
|
68
|
+
target.replaceChildren();
|
|
69
|
+
for(const value of Array.isArray(values)?values:[]){const item=document.createElement('li'); item.textContent=String(value); target.append(item);}
|
|
70
|
+
if(!target.children.length){const item=document.createElement('li'); item.textContent=emptyLabel; target.append(item);}
|
|
71
|
+
}
|
|
72
|
+
function sameOrigin(value=''){
|
|
73
|
+
const url=new URL(String(value),document.baseURI); if(url.origin!==location.origin) throw new TypeError('Original sources must use the current application origin.'); return url;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function showFinding(value={},config={}){
|
|
77
|
+
finding=value&&typeof value==='object'?value:null; if(!finding) throw new TypeError('A finding is required.');
|
|
78
|
+
sources=(Array.isArray(finding.sources)?finding.sources:[]).slice(0,40);
|
|
79
|
+
title.textContent=String(finding.label||'Investigative lead'); assessment.textContent=String(finding.assessment||finding.conclusion||'Human review is required before reliance.');
|
|
80
|
+
badges.replaceChildren();
|
|
81
|
+
for(const value of [finding.allegedActorLabel?`Alleged actor: ${finding.allegedActorLabel}`:'Actor not assigned',finding.kind||'Investigative lead',finding.confidence?`${finding.confidence} confidence`:'Confidence not assigned']){const badge=document.createElement('span'); badge.className='badge'; badge.textContent=value; badges.append(badge);}
|
|
82
|
+
list(elements,finding.elementsToVerify,'No element checklist has been assigned.'); application.textContent=String(finding.application||'The cited passages require investigator comparison to the original sources.');
|
|
83
|
+
list(limitations,finding.limitations,'No contrary evidence has been recorded yet; this does not mean none exists.'); list(nextSteps,finding.nextSteps,'Compare the cited excerpt with the complete original and record contrary facts.');
|
|
84
|
+
evidenceList.replaceChildren();
|
|
85
|
+
for(const [index,source] of sources.entries()){
|
|
86
|
+
const card=document.createElement('article'); card.className='evidence'; const header=document.createElement('header'); const name=document.createElement('strong'); const cite=document.createElement('span');
|
|
87
|
+
name.textContent=String(source.filename||source.title||source.recordId||'Source'); cite.textContent=[source.page?`PDF p. ${source.page}`:'',source.lineStart?`MD lines ${source.lineStart}–${source.lineEnd||source.lineStart}`:''].filter(Boolean).join(' · '); header.append(name,cite);
|
|
88
|
+
const quote=document.createElement('blockquote'); quote.textContent=String(source.excerpt||source.quote||'No excerpt supplied.'); card.append(header,quote);
|
|
89
|
+
evidenceList.append(card);
|
|
90
|
+
}
|
|
91
|
+
if(!sources.length){const empty=document.createElement('p'); empty.className='empty'; empty.textContent='No source excerpt is attached. Do not rely on this lead until a source is added.'; evidenceList.append(empty);}
|
|
92
|
+
originalPicker.replaceChildren(...sources.flatMap((source,index)=>{if(!source?.pdfUrl)return[];const item=document.createElement('option');item.value=String(index);item.textContent=`${source.recordId||'Source'}${source.page?` — PDF page ${source.page}`:''}`;return[item];})); originalPicker.disabled=!originalPicker.options.length;
|
|
93
|
+
original.hidden=true; original.removeAttribute('src'); originalLabel.textContent='Select a cited excerpt to inspect the original source page.';
|
|
94
|
+
options(actor,config.actorOptions||[]); options(disposition,config.dispositionOptions||[]); options(confidence,config.confidenceOptions||[]);
|
|
95
|
+
const review=finding.review&&typeof finding.review==='object'?finding.review:{};
|
|
96
|
+
actor.value=String(review.classification||finding.allegedActor||'unassigned'); disposition.value=String(review.status||'unassessed'); confidence.value=String(review.attributes?.confidence||finding.confidence||'unassigned'); notes.value=String(review.notes||''); saveState.textContent='';
|
|
97
|
+
if(!actor.value&&actor.options.length) actor.selectedIndex=0; if(!disposition.value&&disposition.options.length) disposition.selectedIndex=0; if(!confidence.value&&confidence.options.length) confidence.selectedIndex=0;
|
|
98
|
+
const requestedSourceId=String(config.initialSourceId||'');
|
|
99
|
+
const requestedSourceIndex=requestedSourceId?sources.findIndex(source=>String(source?.id||'')===requestedSourceId):-1;
|
|
100
|
+
const firstSourceIndex=sources.findIndex(source=>source?.pdfUrl);
|
|
101
|
+
const initialSourceIndex=requestedSourceIndex>-1&&sources[requestedSourceIndex]?.pdfUrl?requestedSourceIndex:firstSourceIndex;
|
|
102
|
+
if(initialSourceIndex>-1) showSource(initialSourceIndex);
|
|
103
|
+
return {...finding};
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function selectSource(value=0){
|
|
107
|
+
const index=Number.isInteger(value)?value:sources.findIndex(source=>String(source?.id||'')===String(value||''));
|
|
108
|
+
if(index<0||!sources[index]?.pdfUrl) return false;
|
|
109
|
+
showSource(index); return true;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function showSource(index=0){
|
|
113
|
+
const source=sources[index]; if(!source?.pdfUrl) return null;
|
|
114
|
+
try{
|
|
115
|
+
const url=sameOrigin(source.pdfUrl); if(source.page){url.searchParams.set('arcane-pdf-page',String(Number(source.page)));url.hash=`page=${Number(source.page)}`;}
|
|
116
|
+
originalPicker.value=String(index); original.src=url.href; original.title=`Original cited source: ${source.filename||source.recordId||'document'}${source.page?`, page ${source.page}`:''}`; original.hidden=false;
|
|
117
|
+
originalLabel.textContent=`Original source${source.page?` at PDF page ${source.page}`:''}. Compare the full page before relying on the extracted text.`;
|
|
118
|
+
host.dispatchEvent(new CustomEvent('source-explanation-source-selected',{bubbles:true,composed:true,detail:{index,source:{...source}}}));
|
|
119
|
+
return {...source};
|
|
120
|
+
}catch(error){original.hidden=true; originalLabel.textContent=error.message; return null;}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
host.dispatchEvent(new CustomEvent('source-explanation-ready',{bubbles:true,composed:true}));
|
|
124
|
+
</script>
|