diff --git a/platypush/backend/http/webapp/src/components/File/Editor.vue b/platypush/backend/http/webapp/src/components/File/Editor.vue
index 8b6e3df88b..143d0fd763 100644
--- a/platypush/backend/http/webapp/src/components/File/Editor.vue
+++ b/platypush/backend/http/webapp/src/components/File/Editor.vue
@@ -9,10 +9,15 @@
@@ -54,6 +59,11 @@ export default {
default: false,
},
+ line: {
+ type: [String, Number],
+ default: null,
+ },
+
withSave: {
type: Boolean,
default: true,
@@ -71,6 +81,7 @@ export default {
initialContentHash: 0,
loading: false,
saving: false,
+ selectedLine: null,
type: null,
}
},
@@ -139,6 +150,12 @@ export default {
} finally {
this.loading = false
}
+
+ if (this.selectedLine) {
+ setTimeout(() => {
+ this.scrollToLine(this.selectedLine)
+ }, 1000)
+ }
},
async saveFile() {
@@ -190,6 +207,17 @@ export default {
})
},
+ scrollToLine(line) {
+ const offset = (line - 1) * parseFloat(getComputedStyle(this.$refs.pre).lineHeight)
+ this.$refs.textarea.scrollTo({
+ top: offset,
+ left: 0,
+ behavior: 'smooth',
+ })
+
+ return offset
+ },
+
highlightContent() {
this.highlighting = true
@@ -243,7 +271,7 @@ export default {
},
reset() {
- this.setUrlArgs({file: null})
+ this.setUrlArgs({file: null, line: null})
this.removeBeforeUnload()
this.removeKeyListener()
},
@@ -276,9 +304,36 @@ export default {
this.highlightedContent = this.content
}
},
+
+ selectedLine(line) {
+ line = parseInt(line)
+ if (isNaN(line)) {
+ return
+ }
+
+ const textarea = this.$refs.textarea
+ const lines = this.content.split('\n')
+ const cursor = lines.slice(0, line - 1).join('\n').length + 1
+
+ textarea.setSelectionRange(cursor, cursor)
+ textarea.focus()
+ this.setUrlArgs({line})
+ this.$nextTick(() => {
+ const offset = this.scrollToLine(line)
+ this.$refs.selectedLine.style.top = `${offset}px`
+ })
+ },
},
mounted() {
+ const args = this.getUrlArgs()
+ const line = parseInt(this.line || args.line || 0)
+ if (line) {
+ if (!isNaN(line)) {
+ this.selectedLine = line
+ }
+ }
+
this.loadFile()
this.addBeforeUnload()
this.addKeyListener()
@@ -332,8 +387,10 @@ $line-numbers-width: 2.5em;
}
.editor-body {
+ font-family: $monospace-font;
+
pre, textarea, code, .line-numbers {
- font-family: 'Fira Code', 'Noto Sans Mono', 'Inconsolata', 'Courier New', monospace;
+ font-family: $monospace-font;
position: absolute;
top: 0;
height: 100%;
@@ -341,6 +398,10 @@ $line-numbers-width: 2.5em;
white-space: pre;
}
+ pre, textarea, code {
+ background: transparent;
+ }
+
.line-numbers {
width: $line-numbers-width;
background: $tab-bg;
@@ -356,6 +417,15 @@ $line-numbers-width: 2.5em;
width: 100%;
text-align: right;
padding-right: 0.25em;
+ cursor: pointer;
+
+ &:hover {
+ background: $hover-bg;
+ }
+
+ &.selected {
+ background: $selected-bg;
+ }
}
}
@@ -372,16 +442,32 @@ $line-numbers-width: 2.5em;
background: transparent;
overflow-wrap: normal;
overflow-x: scroll;
- z-index: 1;
+ z-index: 2;
color: rgba(0, 0, 0, 0);
caret-color: black;
border: none;
outline: none;
}
+
+ .selected-line {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 1.5em;
+ background: rgba(110, 255, 160, 0.25);
+ }
}
:deep(.floating-btn) {
z-index: 5;
}
+
+ // Fix for some hljs styles that render white text on white background
+ :deep(code) {
+ .hljs-subst {
+ color: $selected-fg !important;
+ }
+ }
}
diff --git a/platypush/backend/http/webapp/src/components/File/EditorModal.vue b/platypush/backend/http/webapp/src/components/File/EditorModal.vue
index 2891912c2b..3e05db3b2b 100644
--- a/platypush/backend/http/webapp/src/components/File/EditorModal.vue
+++ b/platypush/backend/http/webapp/src/components/File/EditorModal.vue
@@ -8,6 +8,7 @@
@@ -26,10 +27,11 @@
import ConfirmDialog from "@/components/elements/ConfirmDialog";
import FileEditor from "./Editor";
import Modal from "@/components/Modal";
+import Utils from '@/Utils'
export default {
emits: ['close', 'open', 'save'],
- mixins: [Modal],
+ mixins: [Modal, Utils],
components: {
ConfirmDialog,
FileEditor,
@@ -47,6 +49,11 @@ export default {
default: false,
},
+ line: {
+ type: [String, Number],
+ default: null,
+ },
+
withSave: {
type: Boolean,
default: true,
@@ -113,15 +120,28 @@ export default {
onClose() {
this.$refs.fileEditor.reset()
+ this.setUrlArgs({ maximized: null })
this.$emit('close')
},
},
+
+ watch: {
+ maximized() {
+ this.setUrlArgs({ maximized: this.maximized })
+ },
+ },
+
+ mounted() {
+ this.maximized = !!this.getUrlArgs().maximized
+ },
}