125 lines
3.3 KiB
TypeScript
125 lines
3.3 KiB
TypeScript
/* eslint-disable vue/no-side-effects-in-computed-properties */
|
|
import { computed, defineComponent, h, ref, watch } from 'vue';
|
|
|
|
import hljs from 'highlight.js/lib/core';
|
|
|
|
const component = defineComponent({
|
|
props: {
|
|
code: {
|
|
type: String,
|
|
required: true,
|
|
},
|
|
language: {
|
|
type: String,
|
|
default: '',
|
|
},
|
|
autodetect: {
|
|
type: Boolean,
|
|
default: true,
|
|
},
|
|
ignoreIllegals: {
|
|
type: Boolean,
|
|
default: true,
|
|
},
|
|
},
|
|
setup(props, { emit }) {
|
|
const language = ref(props.language);
|
|
const ignoreIllegals = ref(props.ignoreIllegals);
|
|
watch(
|
|
() => props.language,
|
|
(newLanguage) => {
|
|
language.value = newLanguage;
|
|
},
|
|
);
|
|
watch(
|
|
() => props.ignoreIllegals,
|
|
(newIgnoreIllegals) => {
|
|
ignoreIllegals.value = newIgnoreIllegals;
|
|
},
|
|
);
|
|
|
|
const autodetect = computed(() => props.autodetect || !language.value);
|
|
const cannotDetectLanguage = computed(
|
|
() => !autodetect.value && !hljs.getLanguage(language.value),
|
|
);
|
|
|
|
const className = computed((): string => {
|
|
return cannotDetectLanguage.value ? '' : `hljs ${language.value}`;
|
|
});
|
|
|
|
const highlightedCode = computed((): string => {
|
|
// No idea what language to use, return raw code
|
|
if (cannotDetectLanguage.value) {
|
|
console.warn(
|
|
`The language "${language.value}" you specified could not be found.`,
|
|
);
|
|
return props.code;
|
|
}
|
|
|
|
if (autodetect.value) {
|
|
const result = hljs.highlightAuto(props.code);
|
|
language.value = result.language ?? '';
|
|
return result.value;
|
|
} else {
|
|
const result = hljs.highlight(props.code, {
|
|
language: language.value,
|
|
ignoreIllegals: props.ignoreIllegals,
|
|
});
|
|
return result.value;
|
|
}
|
|
});
|
|
// const saveSelection = (e: any) => {
|
|
// const selection = window.getSelection();
|
|
// if (selection && selection.rangeCount && selection.rangeCount > 0) {
|
|
// const range = selection.getRangeAt(0);
|
|
// return range;
|
|
// }
|
|
// return null;
|
|
// };
|
|
// const restoreSelection = (range: any, el: any) => {
|
|
// if (range) {
|
|
// const selection = window.getSelection();
|
|
// if (selection) {
|
|
// selection.removeAllRanges();
|
|
// selection.addRange(range);
|
|
// console.log('selection range', range);
|
|
// }
|
|
// }
|
|
// };
|
|
const updateContent = (e: any) => {
|
|
// const range = saveSelection(e)
|
|
const result = hljs.highlight(e.target.innerText, {
|
|
language: language.value,
|
|
ignoreIllegals: props.ignoreIllegals,
|
|
});
|
|
e.target.innerHTML = result.value;
|
|
emit('update:code', e.target.innerText);
|
|
// setTimeout(() => {
|
|
// restoreSelection(range, e.target)
|
|
// }, 0)
|
|
};
|
|
return {
|
|
className,
|
|
highlightedCode,
|
|
updateContent,
|
|
emit,
|
|
};
|
|
},
|
|
render() {
|
|
const updateContent = this.updateContent;
|
|
return h('pre', {}, [
|
|
h('code', {
|
|
class: this.className,
|
|
innerHTML: this.highlightedCode,
|
|
contenteditable: true,
|
|
// onInput(e: any) {},
|
|
onBlur(e: any) {
|
|
updateContent(e);
|
|
},
|
|
}),
|
|
]);
|
|
},
|
|
});
|
|
|
|
export default component;
|