This is an automated email from the ASF dual-hosted git repository.
andy pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/jena.git
The following commit(s) were added to refs/heads/main by this push:
new a3bc7042b3 Update Fuseki Edit view CodeMirror usage * Create
CodeMirror component for abstraction * Replace Edit.vue textarea to CodeMirror
element * Update jena-fuseki-ui package.json to support native legacy mode
languages * Add license header * Add VSCode .gitignore entry * Update
jena-fuseki-ui yarn.lock
a3bc7042b3 is described below
commit a3bc7042b36df477abb8e047a4ae342247d73b2b
Author: AtesComp <[email protected]>
AuthorDate: Tue Dec 16 23:28:25 2025 -0500
Update Fuseki Edit view CodeMirror usage
* Create CodeMirror component for abstraction
* Replace Edit.vue textarea to CodeMirror element
* Update jena-fuseki-ui package.json to support native legacy mode languages
* Add license header
* Add VSCode .gitignore entry
* Update jena-fuseki-ui yarn.lock
---
.gitignore | 3 +
jena-fuseki2/jena-fuseki-ui/package.json | 3 +-
.../src/components/dataset/CodeMirror.vue | 571 +++++++++++++++++++++
.../jena-fuseki-ui/src/views/dataset/Edit.vue | 92 +---
jena-fuseki2/jena-fuseki-ui/yarn.lock | 59 +--
5 files changed, 626 insertions(+), 102 deletions(-)
diff --git a/.gitignore b/.gitignore
index b07be1b34a..e93f7bff2a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -25,6 +25,9 @@ maven-eclipse.xml
*.iml
.idea/
+# Visual Studio Code
+.vscode/
+
# Caches
.scala_dependencies
diff --git a/jena-fuseki2/jena-fuseki-ui/package.json
b/jena-fuseki2/jena-fuseki-ui/package.json
index ca64d416df..3ee152793c 100644
--- a/jena-fuseki2/jena-fuseki-ui/package.json
+++ b/jena-fuseki2/jena-fuseki-ui/package.json
@@ -21,6 +21,8 @@
"serve:offline": "cross-env FUSEKI_PORT=\"${FUSEKI_PORT:=3030}\"
PORT=\"${PORT:=8080}\" concurrently --names 'SERVER,CLIENT' --prefix-colors
'yellow,blue' --success 'first' --kill-others 'yarn run serve:fuseki' 'yarn
wait-on http://localhost:${FUSEKI_PORT}/$/ping && yarn run dev'"
},
"dependencies": {
+ "@codemirror/language": "^6.11.3",
+ "@codemirror/legacy-modes": "^6.5.2",
"@fortawesome/fontawesome-svg-core": "^7.0.0",
"@fortawesome/free-solid-svg-icons": "^7.0.0",
"@fortawesome/vue-fontawesome": "^3.0.3",
@@ -31,7 +33,6 @@
"axios": "^1.6.1",
"bootstrap": "^5.3.2",
"codemirror": "6.0.2",
- "codemirror-lang-turtle": "^0.0.2",
"follow-redirects": "^1.15.4",
"mitt": "^3.0.1",
"qs": "6.14.0",
diff --git a/jena-fuseki2/jena-fuseki-ui/src/components/dataset/CodeMirror.vue
b/jena-fuseki2/jena-fuseki-ui/src/components/dataset/CodeMirror.vue
new file mode 100644
index 0000000000..df7c324b3f
--- /dev/null
+++ b/jena-fuseki2/jena-fuseki-ui/src/components/dataset/CodeMirror.vue
@@ -0,0 +1,571 @@
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<template>
+ <component
+ :is="tag"
+ ref="editor"
+ class="vue-codemirror font-fixed-width"
+ >
+ <aside
+ v-if="$slots.default"
+ style="display: none;"
+ aria-hidden
+ >
+ <slot name="default" />
+ </aside>
+ </component>
+</template>
+
+<script>
+// CodeMirror
+import { basicSetup, minimalSetup } from 'codemirror';
+import { EditorSelection, EditorState, StateEffect } from '@codemirror/state';
+import { EditorView, keymap, lineNumbers, showPanel } from "@codemirror/view";
+import { indentWithTab, history } from '@codemirror/commands';
+import { forceLinting, linter, lintGutter } from '@codemirror/lint';
+import { nextTick } from 'vue';
+
+//import useAppTheme from '@/lib/stateTheme';
+
+// Load Theme Manager...
+//const { isThemeDark } = useAppTheme();
+
+export default {
+ name: 'CodeMirror',
+
+ props: {
+ strValue: {
+ type: String,
+ required: true,
+ },
+ bAllowUpdate: {
+ type: Boolean,
+ required: true,
+ },
+ cmExtender: {
+ type: Object,
+ required: true,
+ /*
+ () => {
+ return {
+ theme: {}, // Object
+ dark: false, // Boolean
+ basic: false, // Boolean
+ minimal: false, // Boolean
+ wrap: false, // Boolean
+ tab: false, // Boolean
+ tabSize: null, // Number
+ lineSeparator: null, // String
+ readonly: false, // Boolean
+ disabled: false, // Boolean
+ extensions: [], // Array of Extensions
+ lang: undefined, // Object
+ linter: undefined, // Function
+ linterConfig: {}, // Object
+ lineNumbers: false, // Boolean
+ lineNumbersConfig: {}, // Object
+ history: false, // Boolean
+ historyConfig: null, // Object
+ gutter: false, // Boolean
+ gutterConfig: {}, // Object
+ panel: false, // Boolean
+ panelFunc: null, // Function
+ };
+ },
+ */
+ },
+ tag: {
+ type: String,
+ default: 'div',
+ },
+ },
+
+ //emits: ['ready', 'update-value', 'update-view', 'focus', 'change',
'destroy'],
+ emits: ['ready', 'update-value', 'destroy'],
+
+ data() {
+ return {
+ isLoaded: false,
+ editor: this.$refs.editor,
+ // CodeMirror Editor View
+ view: null,
+ cmExtenderDefaults: {
+ theme: {}, // Object
+ dark: false, //isThemeDark(), // Boolean
+ basic: false, // Boolean
+ minimal: false, // Boolean
+ wrap: false, // Boolean
+ tab: false, // Boolean
+ tabSize: null, // Number
+ lineSeparator: null, // String
+ readonly: false, // Boolean
+ disabled: false, // Boolean
+ lang: null, // Object
+ linter: null, // Function
+ linterConfig: null, // Object
+ lineNumbers: false, // Boolean
+ lineNumbersConfig: null,// Object
+ history: false, // Boolean
+ historyConfig: null, // Object
+ gutter: false, // Boolean
+ gutterConfig: null, // Object
+ panel: false, // Boolean
+ panelFunc: null, // Function
+ extensions: [], // Array of Extensions
+ },
+ cmExtenderLocal: { ...this.cmExtenderDefaults, ...this.cmExtender },
+ }
+ },
+
+ computed: {
+ // Editor Selection
+ selection: {
+ get() { return (this.view?.state?.selection || null); },
+ set(value) { this.view.dispatch( { selection: value } ); }
+ },
+
+ // Editor State
+ state: {
+ get() { return (this.view?.state || null); },
+ set(value) { this.view.setState(value); }
+ },
+
+ // Cursor Position
+ cursor: {
+ get() { return (this.view?.state?.selection?.main?.head || 0); },
+ set(value) { this.view.dispatch( { selection: { anchor: value } } ); }
+ },
+
+ // Focus
+ focus: {
+ get() { return (this.view?.hasFocus || false) },
+ set(bFocus) {
+ if (bFocus) {
+ this.view.focus();
+ }
+ }
+ },
+
+ // Text length
+ length() { return (this.view?.state?.doc?.length || 0); },
+
+ // Get CodeMirror Extensions...
+ extAll() {
+ let exts = [];
+ if (this.cmExtender) {
+ let objExt = this.cmExtenderLocal;
+ /*
+ console.debug("CM: { " +
+ "basic: " + objExt.basic + ", " +
+ "dark: " + objExt.dark + ", " +
+ "wrap: " + objExt.wrap + ", " +
+ "tab: " + objExt.tab + ", " +
+ "tabSize: " + objExt.tabSize + ", " +
+ "lang: " + objExt.lang + ", " +
+ "linter: " + objExt.linter + ", " +
+ "lineNumbers: " + objExt.lineNumbers + ", " +
+ "gutter: " + objExt.gutter + ", " +
+ "panel: " + objExt.panel + ", " +
+ "panelFunc: " + objExt.panelFunc );
+ */
+ /**
+ * Extensions from props...
+ */
+ // Toggle basic setup...
+ if (objExt.basic) exts.push(basicSetup);
+ // Toggle minimal setup...
+ else if (objExt.minimal) exts.push(minimalSetup);
+ //// Set ViewUpdate event listener...
+ //exts.push(
+ // EditorView.updateListener.of(
+ // (viewUpdate) => this.$emit('update-view', viewUpdate)
+ // )
+ //);
+ // Toggle light / dark mode...
+ exts.push(
+ EditorView.theme( objExt.theme, { dark: objExt.dark } ) );
+ // Toggle line wrapping...
+ if (objExt.wrap) exts.push(EditorView.lineWrapping);
+ // Set Indent with tab...
+ if (objExt.tab) exts.push( keymap.of([indentWithTab]) );
+ // Set Indent tab size...
+ if (objExt.tabSize) exts.push( EditorState.tabSize.of(objExt.tabSize)
);
+ // Set Readonly option...
+ exts.push( EditorState.readOnly.of(objExt.readonly) );
+ // Set Editable option...
+ exts.push( EditorView.editable.of(!objExt.disabled) );
+ // Set Line Break char...
+ if (objExt.lineSeparator) exts.push(
EditorState.lineSeparator.of(objExt.lineSeparator) );
+ // Set Language...
+ if (objExt.lang) exts.push(objExt.lang);
+ // Set Line Numbers Gutter...
+ if (objExt.lineNumbers) {
+ if (objExt.lineNumbersConfig) exts.push(
lineNumbers(objExt.lineNumbersConfig) );
+ else exts.push( lineNumbers() );
+ }
+ if (objExt.history) {
+ if (objExt.historyConfig) exts.push( history(objExt.historyConfig) );
+ else exts.push( history() );
+ }
+ // Set Linter settings...
+ if (objExt.linter) {
+ if (objExt.linterConfig) exts.push( linter( objExt.linter(),
objExt.linterConfig ) );
+ else exts.push( linter( objExt.linter() ) );
+ }
+ // Show 🔴 to error line when linter enabled...
+ if (objExt.linter && objExt.gutter) {
+ if (objExt.gutterConfig) exts.push( lintGutter(objExt.gutterConfig)
);
+ else exts.push( lintGutter() );
+ }
+ // Set Panel Function...
+ if (objExt.panel) exts.push( showPanel.of(objExt.panelFunc) );
+
+ // Append other extensions...
+ // TODO: Ignore previous extension was not changed. Requires a diff.
+ if ( objExt.extensions && Array.isArray(objExt.extensions) &&
objExt.extensions.length > 0 )
+ exts.push( ...objExt.extensions );
+ }
+ return exts;
+ }
+ },
+
+ watch: {
+ strValue(valueNew, valueOld) {
+ if ( ! this.bAllowUpdate ) return;
+ if ( this.view.composing ) return;
+ if ( valueNew === valueOld ) return;
+
+ let trans = {
+ changes: [
+ { from: 0, to: this.view.state.doc.length },
+ { from: 0, insert: valueNew },
+ ],
+ selection: { anchor: 0 }, //this.view.state.selection
+ scrollIntoView: true
+ }
+ this.view.dispatch(trans);
+ },
+
+ cmExtender: {
+ deep: true,
+ handler(objCMExtender) {
+ this.cmExtenderLocal = { ...this.cmExtenderDefaults,
...this.cmExtender };
+ if ( ! objCMExtender ) return;
+ if (this.isLoaded) {
+ this.isLoaded = false;
+ this.view.dispatch( { effects:
StateEffect.reconfigure.of(this.extAll) } );
+ this.isLoaded = true;
+ }
+ else {
+ this.initialize();
+ }
+ }
+ },
+
+ //focus(isFocus) {
+ // this.$emit('focus', isFocus);
+ //},
+ },
+
+ async mounted() {
+ if ( ! this.cmExtender ) return;
+ this.editor = this.$refs.editor;
+ await this.initialize();
+ },
+
+ unmounted() {
+ this.removeView();
+ },
+
+ methods: {
+ async initialize(){
+ if ( ! this.cmExtender ) return;
+ this.isLoaded = false;
+
+ let strValueText = this.strValue;
+ if (this.editor && this.editor.childNodes[0] &&
this.editor.childNodes[0].innerText) {
+ // Overwrite given value when an existing display value is present...
+ let strInner = String( this.editor.childNodes[0].innerText ).trim();
+ if (strInner) {
+ strValueText = strInner;
+ }
+ }
+
+ // Register CodeMirror...
+ this.removeView();
+ this.view = new EditorView(
+ { doc: strValueText,
+ selection: EditorSelection.cursor(0),
+ extensions: this.extAll,
+ parent: this.editor,
+ dispatchTransactions: this.dispatcher,
+ scrollIntoView: true,
+ }
+ );
+
+ await nextTick();
+ this.$emit('ready',
+ { view: this.view,
+ //state: this.view.state, // ...unused
+ //container: this.editor, // ...unused
+ }
+ );
+
+ this.isLoaded = true;
+ },
+
+ dispatcher(aTransacts, view) {
+ //this.view.disp.update([objTransact]);
+ //this.view.dispatch(objTransact);
+ view.update(aTransacts);
+
+ let bTest = aTransacts.some(
+ (objTransact) => {
+ // TODO: Emit lint error event
+ // console.debug("CodeMirror : dispatcher() : Transaction: ",
objTransact);
+ return ( objTransact?.changes && objTransact.changes );
+ }
+ );
+ if (bTest) {
+ // console.debug( "CodeMirror : dispatcher() : Doc Text: ",
view.state.doc.toString() );
+ // Pass text up to parent...
+ this.$emit( 'update-value', view.state.doc.toString() );
+ //this.$emit('change', view.state);
+ }
+ },
+
+ removeView() {
+ if (this.view) {
+ this.view.destroy();
+ this.$emit('destroy');
+ }
+ this.view = null;
+ },
+
+ // Forces any linters configured to run when the view is idle to run right
away.
+ lint() {
+ if (this.cmExtenderLocal.linter) {
+ forceLinting(this.view);
+ }
+ },
+
+ // Force Reconfigure Extension
+ forceReconfigure() {
+ // Deconfigure all Extensions...
+ this.view.dispatch( { effects: StateEffect.reconfigure.of([]) } );
+ // Register extensions...
+ this.view.dispatch( { effects: StateEffect.appendConfig.of(this.extAll)
} );
+ },
+
+ /**
+ * Get the text between the given points in the view
+ *
+ * @param from - start line number
+ * @param to - end line number
+ */
+ getRange(from, to) {
+ return this.view.state.sliceDoc(from, to);
+ },
+ /**
+ * Get the content of line
+ *
+ * @param number - line number
+ */
+ getLine(number) {
+ return this.view.state.doc.line(number + 1).text;
+ },
+ /**
+ * Get the number of lines in the view
+ */
+ lineCount() {
+ return this.view.state.doc.lines;
+ },
+ /**
+ * Get the cursor position.
+ */
+ getCursor() {
+ return this.cursor;
+ },
+ /**
+ * Retrieves a list of all current selections
+ */
+ listSelections() {
+ return this.view.state.selection.ranges;
+ },
+ /**
+ * Get the currently selected text
+ */
+ getSelection() {
+ return this.view.state.sliceDoc(
+ this.view.state.selection.main.from,
+ this.view.state.selection.main.to
+ );
+ },
+ /**
+ * The length of the given array should be the same as the number of
active selections.
+ * Replaces the content of the selections with the strings in the array.
+ */
+ getSelections() {
+ return this.view.state.selection.ranges.map(
+ (range) => { return this.view.state.sliceDoc(range.from, range.to); }
+ );
+ },
+ /**
+ * Return true if any text is selected
+ */
+ isSelected() {
+ return this.view.state.selection.ranges.some(
+ (range) => { return !range.empty; }
+ );
+ },
+
+ /**
+ * Replace the part of the document between from and to with the given
string.
+ *
+ * @param replacement - replacement text
+ * @param from - start string at position
+ * @param to - insert the string at position
+ */
+ replaceRange(replacement, from, to) {
+ this.view.dispatch(
+ { changes: { from, to, insert: replacement } }
+ );
+ },
+ /**
+ * Replace the selection(s) with the given string.
+ * By default, the new selection ends up after the inserted text.
+ *
+ * @param replacement - replacement text
+ */
+ replaceSelection(replacement) {
+ this.view.dispatch( this.view.state.replaceSelection(replacement) );
+ },
+ /**
+ * Set the cursor position.
+ *
+ * @param position - position.
+ */
+ setCursor(position) {
+ this.cursor = position;
+ return this.cursor;
+ },
+ /**
+ * Set a single selection range.
+ *
+ * @param from - start position
+ * @param to - end position
+ */
+ setSelection(from, to) {
+ this.view.dispatch( { selection: { from, to } } );
+ },
+ /**
+ * Sets a new set of selections. There must be at least one selection in
the given array.
+ *
+ * @param ranges - Selection range
+ * @param primary - Primary selection
+ */
+ setSelections(ranges, primary = undefined ) {
+ this.view.dispatch(
+ { selection: EditorSelection.create(ranges, primary) }
+ );
+ },
+ /**
+ * Applies the given function to all existing selections, and calls
extendSelections on the result.
+ *
+ * @param func - Function
+ */
+ extendSelectionsBy(/** @type { Function } */ func) {
+ this.view.dispatch(
+ { selection:
+ EditorSelection.create(
+ this.selection.ranges.map(
+ (range) => range.extend( func(range) )
+ )
+ )
+ }
+ );
+ },
+ },
+
+ /**
+ * Render the template:
+ *
+ * <template>
+ * <sometag ref="editor" class="vue-codemirror">
+ * <aside
+ * v-if="this.$slots.default"
+ * style='display: none;'
+ * aria-hidden
+ * >
+ * <slot />
+ * </aside>
+ * </sometag>
+ * </template>
+ *
+ * where <sometag> is dynamically determined from the parent;
+ * defaults to <div>,
+ *//*
+ render() {
+ // function h ( Tag, Children ) | ( Tag, Data, Children )
+ let tagData = { ref: 'editor', class: 'vue-codemirror' };
+ let tagChild = undefined;
+ if ( this.$slots.default ) {
+ let asideData = { style: 'display: none;', 'aria-hidden': true };
+ let asideChild =
+ ( typeof this.$slots.default == 'function' )
+ ? this.$slots.default()
+ : this.$slots.default;
+ tagChild = h( 'aside', asideData, asideChild );
+ h()
+ }
+ return h( this.tag, tagData, tagChild );
+ },
+ */
+
+ /**
+ * Export component properties
+ */
+ expose: [
+ // props...
+ 'editor',
+ // computed...
+ 'selection',
+ 'state',
+ 'cursor',
+ 'focus',
+ 'length',
+ // methods...
+ 'lint',
+ 'forceReconfigure',
+ 'getRange',
+ 'getLine',
+ 'lineCount',
+ 'getCursor',
+ 'listSelections',
+ 'getSelection',
+ 'getSelections',
+ 'isSelected',
+ 'replaceRange',
+ 'replaceSelection',
+ 'setCursor',
+ 'setSelection',
+ 'setSelections',
+ 'extendSelectionsBy',
+ ]
+};
+</script>
\ No newline at end of file
diff --git a/jena-fuseki2/jena-fuseki-ui/src/views/dataset/Edit.vue
b/jena-fuseki2/jena-fuseki-ui/src/views/dataset/Edit.vue
index d900d9d947..77ce9d42ab 100644
--- a/jena-fuseki2/jena-fuseki-ui/src/views/dataset/Edit.vue
+++ b/jena-fuseki2/jena-fuseki-ui/src/views/dataset/Edit.vue
@@ -88,12 +88,16 @@
disabled
/>
</div>
- <textarea
+ <CodeMirror
ref="graph-editor"
- :value="content"
- @update:modelValue="content = $event"
class="form-control"
- ></textarea>
+ :str-value="content"
+ :b-allow-update="bAllowUpdate"
+ :cm-extender="cmOptions"
+ @ready="(objReady) => { cmView = objReady.view; }"
+ @update-value="(strNew) => { updateChanges(strNew); }"
+ @destroy="() => { cmView = null; }"
+ />
<div class="mt-2 text-right">
<button
@click="discardChanges()"
@@ -128,14 +132,10 @@
<script>
import Menu from '@/components/dataset/Menu.vue'
import TableListing from '@/components/dataset/TableListing.vue'
-import { EditorView, keymap, lineNumbers } from '@codemirror/view'
-import { defaultKeymap, history, historyKeymap } from '@codemirror/commands'
-import { syntaxHighlighting, defaultHighlightStyle } from
'@codemirror/language'
-import { turtle } from 'codemirror-lang-turtle'
-import {
- faTimes,
- faCheck
-} from '@fortawesome/free-solid-svg-icons'
+import CodeMirror from '@/components/dataset/CodeMirror.vue';
+import { StreamLanguage } from '@codemirror/language'
+import { turtle } from "@codemirror/legacy-modes/mode/turtle"
+import { faTimes, faCheck } from '@fortawesome/free-solid-svg-icons'
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'
import { library } from '@fortawesome/fontawesome-svg-core'
import currentDatasetMixin from '@/mixins/current-dataset'
@@ -146,32 +146,13 @@ library.add(faTimes, faCheck)
const MAX_EDITABLE_SIZE = 10000
-/**
- * In CodeMirror 5, the static CodeMirror.fromTextArea was used in Jena UI to
- * sync an area in the page to the CodeMirror editor. That was removed in the
- * 6.x release, https://codemirror.net/docs/migration/.
- *
- * @param textarea
- * @param extensions
- * @returns {EditorView}
- */
-function editorFromTextArea(textarea, extensions) {
- const view = new EditorView({doc: textarea.value, extensions})
- textarea.parentNode.insertBefore(view.dom, textarea)
- textarea.style.display = "none"
- if (textarea.form) textarea.form.addEventListener("submit", () => {
- textarea.value = view.state.doc.toString()
- })
- return view
-}
-
-
export default {
name: 'DatasetEdit',
components: {
Menu,
TableListing,
+ CodeMirror,
FontAwesomeIcon
},
@@ -201,15 +182,13 @@ export default {
}
],
selectedGraph: '',
- content: '',
- code: '',
+ bAllowUpdate: true,
+ content: '', // ...always comes from CodeMirror editor except on initial
load
+ cmView: null, // TODO: Add error message display when CodeMirror view
reports error
cmOptions: {
+ basic: true,
extensions: [
- lineNumbers(),
- history(),
- turtle(),
- syntaxHighlighting(defaultHighlightStyle),
- keymap.of([...defaultKeymap, ...historyKeymap])
+ StreamLanguage.define(turtle)
]
}
}
@@ -233,21 +212,10 @@ export default {
}
},
- created () {
- this.codemirrorEditor = null
- },
-
watch: {
- code (newVal) {
- this.codeChanged(newVal)
- },
services (newVal) {
if (newVal && newVal['gsp-rw'] && Object.keys(newVal['gsp-rw']).length >
0) {
- const element = this.$refs['graph-editor']
- this.codemirrorEditor = editorFromTextArea(element,
this.cmOptions.extensions)
- EditorView.updateListener.of(v => {
- this.content = v.getValue()
- })
+ // ...nothing to do...
}
}
},
@@ -257,19 +225,9 @@ export default {
},
methods: {
- codeChanged (newVal) {
- this.codemirrorEditor.dispatch({
- changes: {
- from: 0,
- to: this.codemirrorEditor.state.doc.length,
- insert: newVal
- }
- })
- },
listCurrentGraphs: async function () {
this.loadingGraphs = true
this.loadingGraph = true
- this.code = ''
this.selectedGraph = ''
try {
this.graphs = await
this.$fusekiService.countGraphsTriples(this.datasetName,
this.services.query['srv.endpoints'][0])
@@ -284,7 +242,7 @@ export default {
const graph = Object.entries(this.graphs)
.find(element => element[0] === graphName)
if (parseInt(graph[1]) > MAX_EDITABLE_SIZE) {
- alert('Sorry, that dataset is too large to load into the editor')
+ alert('The dataset is too large (> ' + MAX_EDITABLE_SIZE + ') for the
editor')
return
}
this.loadingGraph = true
@@ -294,7 +252,8 @@ export default {
this.datasetName,
this.services['gsp-rw']['srv.endpoints'],
graphName)
- this.code = result.data
+ this.bAllowUpdate = true;
+ this.content = result.data // ...reactive update to CodeMirror editor
} catch (error) {
displayError(this, error)
} finally {
@@ -303,7 +262,12 @@ export default {
},
discardChanges: function () {
this.selectedGraph = ''
- this.code = ''
+ this.bAllowUpdate = true;
+ this.content = '' // ...reactive update to CodeMirror editor
+ },
+ updateChanges: function (strNew) {
+ this.bAllowUpdate = false; // ...since the update came from the editor,
don't update itself
+ this.content = strNew; // ...reactive update does NOT change CodeMirror
editor
},
saveGraph: async function () {
if (!this.saveGraphDisabled) {
diff --git a/jena-fuseki2/jena-fuseki-ui/yarn.lock
b/jena-fuseki2/jena-fuseki-ui/yarn.lock
index a276c70409..5a407c22ed 100644
--- a/jena-fuseki2/jena-fuseki-ui/yarn.lock
+++ b/jena-fuseki2/jena-fuseki-ui/yarn.lock
@@ -884,6 +884,25 @@
"@lezer/lr" "^1.0.0"
style-mod "^4.0.0"
+"@codemirror/language@^6.11.3":
+ version "6.11.3"
+ resolved
"https://registry.yarnpkg.com/@codemirror/language/-/language-6.11.3.tgz#8e6632df566a7ed13a1bd307f9837765bb1abfdd"
+ integrity
sha512-9HBM2XnwDj7fnu0551HkGdrUrrqmYq/WC5iv6nbY2WdicXdGbhR/gfbZOH73Aqj4351alY1+aoG9rCNfiwS1RA==
+ dependencies:
+ "@codemirror/state" "^6.0.0"
+ "@codemirror/view" "^6.23.0"
+ "@lezer/common" "^1.1.0"
+ "@lezer/highlight" "^1.0.0"
+ "@lezer/lr" "^1.0.0"
+ style-mod "^4.0.0"
+
+"@codemirror/legacy-modes@^6.5.2":
+ version "6.5.2"
+ resolved
"https://registry.yarnpkg.com/@codemirror/legacy-modes/-/legacy-modes-6.5.2.tgz#7e2976c79007cd3fa9ed8a1d690892184a7f5ecf"
+ integrity
sha512-/jJbwSTazlQEDOQw2FJ8LEEKVS72pU0lx6oM54kGpL8t/NJ2Jda3CZ4pcltiKTdqYSRk3ug1B3pil1gsjA6+8Q==
+ dependencies:
+ "@codemirror/language" "^6.0.0"
+
"@codemirror/lint@^6.0.0":
version "6.8.2"
resolved
"https://registry.yarnpkg.com/@codemirror/lint/-/lint-6.8.2.tgz#7864b03583e9efd18554cff1dd4504da10338ab1"
@@ -2846,15 +2865,6 @@ cliui@^8.0.1:
strip-ansi "^6.0.1"
wrap-ansi "^7.0.0"
-codemirror-lang-turtle@^0.0.2:
- version "0.0.2"
- resolved
"https://registry.yarnpkg.com/codemirror-lang-turtle/-/codemirror-lang-turtle-0.0.2.tgz#2db4e56020b8defbbfa0788a85045404b494c957"
- integrity
sha512-YN9JzdxfUv2DKNHLZa8L7sG5StOri8ZHbMzY/zJhrq6pYR0peJaeN+GyQZaXl6fYmmq8hurf/BOqTYPh7Uzgcw==
- dependencies:
- "@codemirror/language" "^6.0.0"
- "@lezer/highlight" "^1.0.0"
- "@lezer/lr" "^1.0.0"
-
[email protected]:
version "6.0.2"
resolved
"https://registry.yarnpkg.com/codemirror/-/codemirror-6.0.2.tgz#4d3fea1ad60b6753f97ca835f2f48c6936a8946e"
@@ -6942,16 +6952,7 @@ string-hash@~1.1.3:
resolved
"https://registry.yarnpkg.com/string-hash/-/string-hash-1.1.3.tgz#e8aafc0ac1855b4666929ed7dd1275df5d6c811b"
integrity
sha512-kJUvRUFK49aub+a7T1nNE66EJbZBMnBgoC1UbCZ5n6bsZKBRga4KgBRTMn/pFkeCZSYtNeSyMxPDM0AXWELk2A==
-"string-width-cjs@npm:string-width@^4.2.0":
- version "4.2.3"
- resolved
"https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
- integrity
sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
- dependencies:
- emoji-regex "^8.0.0"
- is-fullwidth-code-point "^3.0.0"
- strip-ansi "^6.0.1"
-
-string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
+"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0,
string-width@^4.2.0, string-width@^4.2.3:
version "4.2.3"
resolved
"https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
integrity
sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
@@ -7008,14 +7009,7 @@ string_decoder@^1.3.0:
dependencies:
safe-buffer "~5.2.0"
-"strip-ansi-cjs@npm:strip-ansi@^6.0.1":
- version "6.0.1"
- resolved
"https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
- integrity
sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
- dependencies:
- ansi-regex "^5.0.1"
-
-strip-ansi@^6.0.0, strip-ansi@^6.0.1:
+"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1:
version "6.0.1"
resolved
"https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
integrity
sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
@@ -7787,7 +7781,7 @@ word-wrap@^1.2.5:
resolved
"https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34"
integrity
sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==
-"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0":
+"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0:
version "7.0.0"
resolved
"https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
integrity
sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
@@ -7805,15 +7799,6 @@ wrap-ansi@^6.2.0:
string-width "^4.1.0"
strip-ansi "^6.0.0"
-wrap-ansi@^7.0.0:
- version "7.0.0"
- resolved
"https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
- integrity
sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
- dependencies:
- ansi-styles "^4.0.0"
- string-width "^4.1.0"
- strip-ansi "^6.0.0"
-
wrap-ansi@^8.1.0:
version "8.1.0"
resolved
"https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214"