@matdata/yasr 5.20.3 → 6.0.0

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@matdata/yasr",
3
- "description": "Yet Another SPARQL Resultset GUI",
4
- "version": "5.20.3",
3
+ "description": "MatGUI results viewer: a modern SPARQL result set viewer (formerly Yasgui/YASR).",
4
+ "version": "6.0.0",
5
5
  "main": "build/yasr.min.js",
6
6
  "types": "build/ts/src/index.d.ts",
7
7
  "license": "MIT",
@@ -17,18 +17,26 @@
17
17
  "Semantic Web",
18
18
  "Linked Data"
19
19
  ],
20
- "bugs": "https://github.com/Matdata-eu/Yasgui/issues/",
20
+ "bugs": "https://github.com/Matdata-eu/Matgui/issues/",
21
21
  "repository": {
22
22
  "type": "git",
23
- "url": "https://github.com/Matdata-eu/Yasgui.git",
23
+ "url": "https://github.com/Matdata-eu/Matgui.git",
24
24
  "directory": "packages/yasr"
25
25
  },
26
26
  "dependencies": {
27
+ "@codemirror/commands": "^6.11.0",
28
+ "@codemirror/lang-json": "^6.0.2",
29
+ "@codemirror/lang-xml": "^6.1.0",
30
+ "@codemirror/language": "^6.12.4",
31
+ "@codemirror/legacy-modes": "^6.5.3",
32
+ "@codemirror/state": "^6.7.2",
33
+ "@codemirror/view": "^6.43.10",
27
34
  "@fortawesome/free-solid-svg-icons": "^7.1.0",
28
35
  "@json2csv/plainjs": "^7.0.4",
36
+ "@lezer/highlight": "^1.2.3",
29
37
  "@matdata/yasgui-utils": "^4.6.1",
30
38
  "@matdata/yasqe": "^4.6.1",
31
- "codemirror": "^5.51.0",
39
+ "codemirror-lang-turtle": "^0.0.2",
32
40
  "colors": "^1.4.0",
33
41
  "column-resizer": "^1.4.0",
34
42
  "datatables.net": "^2.0.5",
@@ -40,7 +48,6 @@
40
48
  "papaparse": "^5.3.1"
41
49
  },
42
50
  "devDependencies": {
43
- "@types/codemirror": "0.0.100",
44
51
  "@types/jquery": "^3.5.32",
45
52
  "@types/lodash-es": "^4.17.3",
46
53
  "@types/n3": "^1.1.5",
package/src/index.ts CHANGED
@@ -43,6 +43,13 @@ export class Yasr extends EventEmitter {
43
43
  private loadingEl: HTMLDivElement | undefined;
44
44
  private isLoading: boolean = false;
45
45
 
46
+ // Result history
47
+ private static readonly MAX_HISTORY_SIZE = 20;
48
+ private resultHistory: { data: any; duration?: number }[] = [];
49
+ private historyIndex: number = -1;
50
+ private historyBackBtn: HTMLButtonElement | undefined;
51
+ private historyForwardBtn: HTMLButtonElement | undefined;
52
+
46
53
  // Utils
47
54
  public utils = { addScript: addScript, addCSS: addCss, sanitize: sanitize };
48
55
 
@@ -350,6 +357,7 @@ export class Yasr extends EventEmitter {
350
357
  this.drawPluginSelectors();
351
358
  this.drawResponseInfo();
352
359
  this.drawPluginElement();
360
+ this.drawHistoryButtons();
353
361
  this.drawDownloadIcon();
354
362
  this.drawFullscreenButton();
355
363
  if (this.loadingEl) {
@@ -357,6 +365,49 @@ export class Yasr extends EventEmitter {
357
365
  }
358
366
  this.drawDocumentationButton();
359
367
  }
368
+
369
+ private drawHistoryButtons() {
370
+ // Guard: only create buttons once
371
+ if (this.historyBackBtn && this.historyForwardBtn) return;
372
+
373
+ const createBtn = (ariaLabel: string, iconClass: string, title: string): HTMLButtonElement => {
374
+ const btn = document.createElement("button");
375
+ addClass(btn, "yasr_btn", "yasr_btn_history", "btn_icon");
376
+ btn.setAttribute("aria-label", ariaLabel);
377
+ btn.title = title;
378
+ btn.disabled = true;
379
+ const icon = document.createElement("i");
380
+ addClass(icon, "fas", iconClass);
381
+ icon.setAttribute("aria-hidden", "true");
382
+ btn.appendChild(icon);
383
+ return btn;
384
+ };
385
+
386
+ this.historyBackBtn = createBtn("Previous result", "fa-chevron-left", "Previous result");
387
+ this.historyBackBtn.addEventListener("click", () => this.navigateHistory(-1));
388
+
389
+ this.historyForwardBtn = createBtn("Next result", "fa-chevron-right", "Next result");
390
+ this.historyForwardBtn.addEventListener("click", () => this.navigateHistory(1));
391
+
392
+ this.headerEl.appendChild(this.historyBackBtn);
393
+ this.headerEl.appendChild(this.historyForwardBtn);
394
+ }
395
+
396
+ private updateHistoryButtons() {
397
+ if (!this.historyBackBtn || !this.historyForwardBtn) return;
398
+ this.historyBackBtn.disabled = this.historyIndex <= 0;
399
+ this.historyForwardBtn.disabled = this.historyIndex >= this.resultHistory.length - 1;
400
+ }
401
+
402
+ private navigateHistory(direction: -1 | 1) {
403
+ const newIndex = this.historyIndex + direction;
404
+ if (newIndex < 0 || newIndex >= this.resultHistory.length) return;
405
+ this.historyIndex = newIndex;
406
+ const entry = this.resultHistory[this.historyIndex];
407
+ this.results = new Parser(entry.data, entry.duration);
408
+ this.draw();
409
+ this.updateHistoryButtons();
410
+ }
360
411
  private downloadBtn: HTMLAnchorElement | undefined;
361
412
  private drawDownloadIcon() {
362
413
  this.downloadBtn = document.createElement("a");
@@ -519,7 +570,7 @@ export class Yasr extends EventEmitter {
519
570
  const icon = document.createElement("i");
520
571
  addClass(icon, "fas", "fa-circle-question");
521
572
  this.documentationLink.appendChild(icon);
522
- this.documentationLink.href = "https://yasgui-doc.matdata.eu/docs/user-guide";
573
+ this.documentationLink.href = "https://matgui-doc.matdata.eu/docs/user-guide";
523
574
  this.documentationLink.target = "_blank";
524
575
  this.documentationLink.rel = "noopener noreferrer";
525
576
  this.headerEl.appendChild(this.documentationLink); // We can do this as long as the help-element is the last item in the row
@@ -605,7 +656,17 @@ export class Yasr extends EventEmitter {
605
656
  this.hideLoading();
606
657
  this.results = new Parser(data, duration);
607
658
 
659
+ // Truncate any forward history and push new entry
660
+ this.resultHistory = this.resultHistory.slice(0, this.historyIndex + 1);
661
+ this.resultHistory.push({ data, duration });
662
+ // Cap history to avoid unbounded memory growth
663
+ if (this.resultHistory.length > Yasr.MAX_HISTORY_SIZE) {
664
+ this.resultHistory = this.resultHistory.slice(this.resultHistory.length - Yasr.MAX_HISTORY_SIZE);
665
+ }
666
+ this.historyIndex = this.resultHistory.length - 1;
667
+
608
668
  this.draw();
669
+ this.updateHistoryButtons();
609
670
 
610
671
  this.storeResponse();
611
672
  }
@@ -614,7 +675,7 @@ export class Yasr extends EventEmitter {
614
675
  * Execute a background SPARQL query from within a plugin.
615
676
  *
616
677
  * This delegates to the `executeQuery` callback supplied in the Yasr
617
- * configuration (typically wired up by the Yasgui `Tab`). The raw
678
+ * configuration (typically wired up by the Matgui `Tab`). The raw
618
679
  * response is returned so the calling plugin can process it without
619
680
  * replacing the current result display.
620
681
  *
@@ -702,7 +763,7 @@ export interface Config {
702
763
 
703
764
  /**
704
765
  * Optional callback that allows plugins to execute a background SPARQL query.
705
- * When set (e.g. by the Yasgui Tab), plugins can call `yasr.executeQuery(queryString)`
766
+ * When set (e.g. by the Matgui Tab), plugins can call `yasr.executeQuery(queryString)`
706
767
  * to run an arbitrary query and receive the raw response, independently of the
707
768
  * main query editor.
708
769
  *
@@ -731,5 +792,6 @@ Yasr.registerPlugin("response", YasrPluginResponse.default as any);
731
792
  Yasr.registerPlugin("error", YasrPluginError.default as any);
732
793
 
733
794
  export type { Plugin, DownloadInfo } from "./plugins";
795
+ export { buildSubjectOfQuery, buildObjectOfQuery } from "./plugins/response/uriUtils";
734
796
 
735
797
  export default Yasr;
package/src/main.scss CHANGED
@@ -11,6 +11,8 @@
11
11
 
12
12
  .yasr_results {
13
13
  flex: 1;
14
+ min-height: 0;
15
+ overflow: auto;
14
16
  }
15
17
 
16
18
  .yasr_btn {
@@ -164,6 +166,16 @@
164
166
  }
165
167
  }
166
168
 
169
+ .yasr_btn_history {
170
+ border: none;
171
+ background: none;
172
+ color: var(--yasgui-button-text, #505050);
173
+
174
+ &:not([disabled]):hover {
175
+ color: var(--yasgui-button-hover, #337ab7);
176
+ }
177
+ }
178
+
167
179
  .yasr_fullscreenButton {
168
180
  border: none;
169
181
  background: none;
@@ -45,7 +45,7 @@ export default class Error implements Plugin<never> {
45
45
 
46
46
  const cors = document.createElement("li");
47
47
  const firstPart = document.createElement("span");
48
- firstPart.textContent = "Endpoint is not accessible from the YASGUI server and website, and the endpoint is not ";
48
+ firstPart.textContent = "Endpoint is not accessible from the Matgui server and website, and the endpoint is not ";
49
49
  cors.appendChild(firstPart);
50
50
  const secondPart = document.createElement("a");
51
51
  secondPart.textContent = "CORS-enabled";
@@ -1,10 +1,31 @@
1
1
  .yasr {
2
2
  .yasr_results {
3
3
  position: relative;
4
- .CodeMirror {
5
- border: 1px solid #d1d1d1;
4
+ .cm-editor {
5
+ border: 1px solid var(--yasgui-border-color, #d1d1d1);
6
6
  margin-top: 5px;
7
7
  height: 100%;
8
+ position: relative;
9
+ background: var(--yasgui-bg-primary, #fff);
10
+ color: var(--yasgui-text-primary, #000);
11
+ font-size: 13px;
12
+ &.cm-focused {
13
+ outline: none;
14
+ }
15
+ .cm-scroller {
16
+ font-family: monospace;
17
+ line-height: 1.4;
18
+ }
19
+ .cm-gutters {
20
+ background: var(--yasgui-bg-secondary, #f7f7f7);
21
+ border-right: 1px solid var(--yasgui-border-color, #ddd);
22
+ color: var(--yasgui-text-secondary, #999);
23
+ }
24
+ .cm-foldPlaceholder {
25
+ background: var(--yasgui-bg-secondary, #eee);
26
+ border: 1px solid var(--yasgui-border-color, #ddd);
27
+ color: var(--yasgui-text-secondary, #888);
28
+ }
8
29
  &.overflow::before {
9
30
  background: linear-gradient(transparent 0%, #ffffffaa 75%, white 100%);
10
31
  content: "";
@@ -14,6 +35,61 @@
14
35
  position: absolute;
15
36
  pointer-events: none;
16
37
  }
38
+ // Token colors (classHighlighter emits `tok-*` classes). Light theme:
39
+ .tok-string,
40
+ .tok-string2 {
41
+ color: #a11;
42
+ }
43
+ .tok-number,
44
+ .tok-atom,
45
+ .tok-bool {
46
+ color: #164;
47
+ }
48
+ .tok-propertyName,
49
+ .tok-attributeName {
50
+ color: #00c;
51
+ }
52
+ .tok-tagName,
53
+ .tok-keyword {
54
+ color: #170;
55
+ }
56
+ .tok-comment {
57
+ color: #a50;
58
+ }
59
+ .tok-punctuation,
60
+ .tok-angleBracket {
61
+ color: #555;
62
+ }
63
+ // Dark theme
64
+ &.cm-s-yasgui-dark {
65
+ &.overflow::before {
66
+ background: linear-gradient(transparent 0%, #1e1e1eaa 75%, var(--yasgui-bg-primary, #1e1e1e) 100%);
67
+ }
68
+ .tok-string,
69
+ .tok-string2 {
70
+ color: #ce9178;
71
+ }
72
+ .tok-number,
73
+ .tok-atom,
74
+ .tok-bool {
75
+ color: #b5cea8;
76
+ }
77
+ .tok-propertyName,
78
+ .tok-attributeName {
79
+ color: #9cdcfe;
80
+ }
81
+ .tok-tagName,
82
+ .tok-keyword {
83
+ color: #569cd6;
84
+ }
85
+ .tok-comment {
86
+ color: #6a9955;
87
+ }
88
+ .tok-punctuation,
89
+ .tok-angleBracket {
90
+ color: #d4d4d4;
91
+ }
92
+ }
17
93
  }
18
94
  .overlay {
19
95
  width: 100%;
@@ -4,20 +4,22 @@
4
4
  import { Plugin } from "../";
5
5
  import Yasr from "../../";
6
6
  import "./index.scss";
7
- import CodeMirror from "codemirror";
8
- import "codemirror/addon/fold/foldcode.js";
9
- import "codemirror/addon/fold/foldgutter.js";
10
- import "codemirror/addon/fold/xml-fold.js";
11
- import "codemirror/addon/fold/brace-fold.js";
12
-
13
- import "codemirror/addon/edit/matchbrackets.js";
14
- import "codemirror/mode/xml/xml.js";
15
-
16
- import "codemirror/mode/javascript/javascript.js";
17
- import "codemirror/lib/codemirror.css";
18
- import "codemirror/theme/material-palenight.css";
7
+ import { EditorState, Extension } from "@codemirror/state";
8
+ import { EditorView, lineNumbers, highlightSpecialChars } from "@codemirror/view";
9
+ import { foldGutter, bracketMatching, syntaxHighlighting, StreamLanguage } from "@codemirror/language";
10
+ import { classHighlighter } from "@lezer/highlight";
11
+ import { json } from "@codemirror/lang-json";
12
+ import { xml } from "@codemirror/lang-xml";
13
+ import { turtle } from "codemirror-lang-turtle";
14
+ import { javascript } from "@codemirror/legacy-modes/mode/javascript";
19
15
  import { addClass, removeClass } from "@matdata/yasgui-utils";
20
16
  import { DeepReadonly } from "ts-essentials";
17
+ import {
18
+ extractUriAtOffset,
19
+ buildSubjectOfQuery,
20
+ buildObjectOfQuery,
21
+ stripDuplicatePrefixDeclarations,
22
+ } from "./uriUtils";
21
23
 
22
24
  export interface PluginConfig {
23
25
  maxLines: number;
@@ -26,10 +28,12 @@ export default class Response implements Plugin<PluginConfig> {
26
28
  private yasr: Yasr;
27
29
  label = "Response";
28
30
  priority = 2;
29
- helpReference = "https://yasgui-doc.matdata.eu/docs/user-guide#response-plugin";
31
+ helpReference = "https://matgui-doc.matdata.eu/docs/user-guide#response-plugin";
30
32
  private config: DeepReadonly<PluginConfig>;
31
33
  private overLay: HTMLDivElement | undefined;
32
- private cm: CodeMirror.Editor | undefined;
34
+ private cm: EditorView | undefined;
35
+ /** Turtle appended to the response view through Ctrl+Click URI exploration actions. */
36
+ private appendedContent = "";
33
37
  constructor(yasr: Yasr) {
34
38
  this.yasr = yasr;
35
39
  this.config = Response.defaults;
@@ -81,27 +85,185 @@ export default class Response implements Plugin<PluginConfig> {
81
85
 
82
86
  // Detect current theme from document
83
87
  const isDarkTheme = document.documentElement.getAttribute("data-theme") === "dark";
84
- const cmTheme = isDarkTheme ? "material-palenight" : "default";
85
-
86
- const codemirrorOpts: Partial<CodeMirror.EditorConfiguration> = {
87
- readOnly: true,
88
- lineNumbers: true,
89
- lineWrapping: true,
90
- foldGutter: true,
91
- gutters: ["CodeMirror-linenumbers", "CodeMirror-foldgutter"],
92
- value: value,
93
- extraKeys: { Tab: false },
94
- theme: cmTheme,
95
- };
96
- const mode = this.yasr.results?.getType();
97
- if (mode === "json") {
98
- codemirrorOpts.mode = { name: "javascript", json: true };
99
- }
100
88
 
101
- this.cm = CodeMirror(this.yasr.resultsEl, codemirrorOpts);
102
- // Don't show less originally we've already set the value in the codemirrorOpts
89
+ const extensions: Extension[] = [
90
+ EditorState.readOnly.of(true),
91
+ EditorView.editable.of(false),
92
+ lineNumbers(),
93
+ foldGutter(),
94
+ highlightSpecialChars(),
95
+ bracketMatching(),
96
+ EditorView.lineWrapping,
97
+ // Emit stable `tok-*` classes so the theme SCSS controls colors (light & dark)
98
+ syntaxHighlighting(classHighlighter),
99
+ EditorView.editorAttributes.of({ class: `CodeMirror cm-s-${isDarkTheme ? "yasgui-dark" : "default"}` }),
100
+ ];
101
+ const language = this.getLanguageExtension();
102
+ if (language) extensions.push(language);
103
+
104
+ this.destroyEditor();
105
+ // A fresh response replaces any DESCRIBE results appended to the previous one.
106
+ this.appendedContent = "";
107
+ this.cm = new EditorView({
108
+ state: EditorState.create({ doc: value, extensions }),
109
+ parent: this.yasr.resultsEl,
110
+ });
111
+ this.cm.dom.addEventListener("mousedown", this.handleMouseDown);
112
+ // Don't show less originally we've already set the value in the editor state
103
113
  if (lines.length > config.maxLines) this.showLess(false);
104
114
  }
115
+ private getLanguageExtension(): Extension | undefined {
116
+ const type = this.yasr.results?.getType();
117
+ if (type === "json") return json();
118
+ if (type === "xml") return xml();
119
+ if (type === "ttl") return turtle();
120
+ if (type === "n-triples") return turtle();
121
+ const contentType = this.yasr.results?.getContentType() || "";
122
+ if (contentType.indexOf("json") >= 0) return json();
123
+ if (contentType.indexOf("xml") >= 0 || contentType.indexOf("html") >= 0) return xml();
124
+ if (contentType.indexOf("javascript") >= 0) return StreamLanguage.define(javascript);
125
+ return undefined;
126
+ }
127
+ private destroyEditor() {
128
+ if (this.cm) {
129
+ this.cm.dom.removeEventListener("mousedown", this.handleMouseDown);
130
+ this.cm.destroy();
131
+ this.cm = undefined;
132
+ }
133
+ this.overLay?.remove();
134
+ this.overLay = undefined;
135
+ }
136
+
137
+ /**
138
+ * Ctrl/Cmd+Click on a URI runs a CONSTRUCT query for triples where the URI is the subject.
139
+ * Ctrl/Cmd+Shift+Click runs a CONSTRUCT query for triples where the URI is the object.
140
+ */
141
+ private handleMouseDown = (event: MouseEvent) => {
142
+ if (!event.ctrlKey && !event.metaKey) return;
143
+ if (event.button !== 0) return;
144
+ if (!this.cm) return;
145
+ // Only act when the host application wired up a query executor.
146
+ if (!this.yasr.config.executeQuery) return;
147
+
148
+ const pos = this.cm.posAtCoords({ x: event.clientX, y: event.clientY });
149
+ if (pos === null) return;
150
+
151
+ const uri = extractUriAtOffset(this.cm.state.doc.toString(), pos);
152
+ if (!uri) return;
153
+
154
+ event.preventDefault();
155
+ event.stopPropagation();
156
+
157
+ if (event.shiftKey) {
158
+ void this.runObjectOfQuery(uri);
159
+ } else {
160
+ void this.runSubjectOfQuery(uri);
161
+ }
162
+ };
163
+
164
+ private async runSubjectOfQuery(uri: string) {
165
+ if (!this.yasr.config.executeQuery) return;
166
+ const cmAtStart = this.cm;
167
+ if (!cmAtStart) return;
168
+
169
+ const query = buildSubjectOfQuery(uri);
170
+ try {
171
+ this.yasr.showLoading();
172
+ const response = await this.yasr.executeQuery(query, { acceptHeader: this.getConstructAcceptHeader() });
173
+ if (this.cm !== cmAtStart) return;
174
+
175
+ const content = this.getResponseContent(response);
176
+ if (content) {
177
+ this.appendToView(`\n\n# Triples where <${uri}> is subject\n${content.trim()}\n`);
178
+ } else {
179
+ this.appendToView(`\n\n# Triples where <${uri}> is subject: no data\n`);
180
+ }
181
+ } catch (error) {
182
+ if (this.cm !== cmAtStart) return;
183
+
184
+ console.error("Subject-of query failed:", error);
185
+ const message = error instanceof Error ? error.message : String(error);
186
+ this.appendToView(`\n\n# Triples where <${uri}> is subject failed: ${message}\n`);
187
+ } finally {
188
+ if (this.cm === cmAtStart) this.yasr.hideLoading();
189
+ }
190
+ }
191
+
192
+ private async runObjectOfQuery(uri: string) {
193
+ if (!this.yasr.config.executeQuery) return;
194
+ const cmAtStart = this.cm;
195
+ if (!cmAtStart) return;
196
+
197
+ const query = buildObjectOfQuery(uri);
198
+ try {
199
+ this.yasr.showLoading();
200
+ const response = await this.yasr.executeQuery(query, { acceptHeader: this.getConstructAcceptHeader() });
201
+ if (this.cm !== cmAtStart) return;
202
+
203
+ const content = this.getResponseContent(response);
204
+ if (content) {
205
+ this.appendToView(`\n\n# Triples where <${uri}> is object\n${content.trim()}\n`);
206
+ } else {
207
+ this.appendToView(`\n\n# Triples where <${uri}> is object: no data\n`);
208
+ }
209
+ } catch (error) {
210
+ if (this.cm !== cmAtStart) return;
211
+
212
+ console.error("Object-of query failed:", error);
213
+ const message = error instanceof Error ? error.message : String(error);
214
+ this.appendToView(`\n\n# Triples where <${uri}> is object failed: ${message}\n`);
215
+ } finally {
216
+ if (this.cm === cmAtStart) this.yasr.hideLoading();
217
+ }
218
+ }
219
+
220
+ /**
221
+ * Pick an Accept header for follow-up CONSTRUCT requests. When the current response
222
+ * is an RDF graph format, reuse it so the appended triples match what is shown.
223
+ */
224
+ private getConstructAcceptHeader(): string {
225
+ const contentType = this.yasr.results?.getContentType();
226
+ if (contentType) {
227
+ const lower = contentType.toLowerCase();
228
+ if (
229
+ lower.includes("turtle") ||
230
+ lower.includes("trig") ||
231
+ lower.includes("triple") ||
232
+ lower.includes("quad") ||
233
+ lower.includes("rdf")
234
+ ) {
235
+ return contentType.split(";")[0].trim();
236
+ }
237
+ }
238
+ return "text/turtle";
239
+ }
240
+
241
+ private getResponseContent(response: unknown): string {
242
+ if (typeof response === "string") return response;
243
+ if (response && typeof response === "object") {
244
+ const record = response as Record<string, unknown>;
245
+ if (typeof record.content === "string") return record.content;
246
+ if (typeof record.data === "string") return record.data;
247
+ }
248
+ return "";
249
+ }
250
+
251
+ /**
252
+ * Append text (query result or status message) to the response view and make sure
253
+ * the full content is revealed.
254
+ */
255
+ private appendToView(text: string) {
256
+ if (!this.cm || !text) return;
257
+ const existingVisibleContent = (this.yasr.results?.getOriginalResponseAsString() || "") + this.appendedContent;
258
+ this.appendedContent += stripDuplicatePrefixDeclarations(text, existingVisibleContent);
259
+ // Reveal the full response together with the appended DESCRIBE results.
260
+ this.showMore();
261
+ }
262
+
263
+ private setValue(value: string) {
264
+ if (!this.cm) return;
265
+ this.cm.dispatch({ changes: { from: 0, to: this.cm.state.doc.length, insert: value } });
266
+ }
105
267
  private limitData(value: string) {
106
268
  const lines = value.split("\n");
107
269
  if (lines.length > this.config.maxLines) {
@@ -116,7 +278,7 @@ export default class Response implements Plugin<PluginConfig> {
116
278
  showLess(setValue = true) {
117
279
  if (!this.cm) return;
118
280
  // Add overflow
119
- addClass(this.cm.getWrapperElement(), "overflow");
281
+ addClass(this.cm.dom, "overflow");
120
282
 
121
283
  // Remove old instance
122
284
  if (this.overLay) {
@@ -157,9 +319,9 @@ export default class Response implements Plugin<PluginConfig> {
157
319
 
158
320
  overlayContent.appendChild(downloadButton);
159
321
  this.overLay.appendChild(overlayContent);
160
- this.cm.getWrapperElement().appendChild(this.overLay);
322
+ this.cm.dom.appendChild(this.overLay);
161
323
  if (setValue) {
162
- this.cm.setValue(this.limitData(this.yasr.results?.getOriginalResponseAsString() || ""));
324
+ this.setValue(this.limitData(this.yasr.results?.getOriginalResponseAsString() || ""));
163
325
  }
164
326
  }
165
327
  /**
@@ -167,11 +329,13 @@ export default class Response implements Plugin<PluginConfig> {
167
329
  */
168
330
  showMore() {
169
331
  if (!this.cm) return;
170
- removeClass(this.cm.getWrapperElement(), "overflow");
332
+ removeClass(this.cm.dom, "overflow");
171
333
  this.overLay?.remove();
172
334
  this.overLay = undefined;
173
- this.cm.setValue(this.yasr.results?.getOriginalResponseAsString() || "");
174
- this.cm.refresh();
335
+ this.setValue((this.yasr.results?.getOriginalResponseAsString() || "") + this.appendedContent);
336
+ }
337
+ destroy() {
338
+ this.destroyEditor();
175
339
  }
176
340
  public static defaults: PluginConfig = {
177
341
  maxLines: 30,