|
|
|
|
|
import { app } from '../../scripts/app.js' |
|
|
|
import * as shared from './comfy_shared.js' |
|
import { infoLogger, successLogger, errorLogger } from './comfy_shared.js' |
|
import { |
|
DEFAULT_CSS, |
|
DEFAULT_HTML, |
|
DEFAULT_MD, |
|
DEFAULT_MODE, |
|
DEFAULT_THEME, |
|
THEMES, |
|
CSS_RESET, |
|
DEMO_CONTENT, |
|
} from './note_plus.constants.js' |
|
import { LocalStorageManager } from './comfy_shared.js' |
|
|
|
const storage = new LocalStorageManager('mtb') |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let useShiki = storage.get('np-use-shiki', false) |
|
|
|
const makeResizable = (dialog) => { |
|
dialog.style.resize = 'both' |
|
dialog.style.transformOrigin = 'top left' |
|
dialog.style.overflow = 'auto' |
|
} |
|
|
|
const makeDraggable = (dialog, handle) => { |
|
let offsetX = 0 |
|
let offsetY = 0 |
|
let isDragging = false |
|
|
|
const onMouseMove = (e) => { |
|
if (isDragging) { |
|
dialog.style.left = `${e.clientX - offsetX}px` |
|
dialog.style.top = `${e.clientY - offsetY}px` |
|
} |
|
} |
|
|
|
const onMouseUp = () => { |
|
isDragging = false |
|
document.removeEventListener('mousemove', onMouseMove) |
|
document.removeEventListener('mouseup', onMouseUp) |
|
} |
|
|
|
handle.addEventListener('mousedown', (e) => { |
|
isDragging = true |
|
offsetX = e.clientX - dialog.offsetLeft |
|
offsetY = e.clientY - dialog.offsetTop |
|
document.addEventListener('mousemove', onMouseMove) |
|
document.addEventListener('mouseup', onMouseUp) |
|
}) |
|
} |
|
|
|
|
|
class NotePlus extends LiteGraph.LGraphNode { |
|
|
|
color = LGraphCanvas.node_colors.yellow.color |
|
bgcolor = LGraphCanvas.node_colors.yellow.bgcolor |
|
groupcolor = LGraphCanvas.node_colors.yellow.groupcolor |
|
|
|
|
|
|
|
|
|
uuid |
|
|
|
|
|
resizeObserver |
|
|
|
|
|
live = true |
|
|
|
calculated_height = 0 |
|
|
|
|
|
_raw_html |
|
|
|
|
|
inner |
|
|
|
|
|
dialog |
|
|
|
|
|
|
|
|
|
html_widget |
|
|
|
|
|
css_widget |
|
edit_mode_widget |
|
theme_widget |
|
|
|
editorsContainer |
|
|
|
html_editor |
|
css_editor |
|
|
|
constructor() { |
|
super() |
|
this.uuid = shared.makeUUID() |
|
|
|
infoLogger('Constructing Note+ instance') |
|
shared.ensureMarkdownParser((_p) => { |
|
this.updateHTML() |
|
}) |
|
|
|
this.collapsable = true |
|
this.isVirtualNode = true |
|
this.shape = LiteGraph.BOX_SHAPE |
|
this.serialize_widgets = true |
|
|
|
|
|
this._raw_html = DEFAULT_MODE === 'html' ? DEFAULT_HTML : DEFAULT_MD |
|
|
|
|
|
this.live = true |
|
this.calculated_height = 0 |
|
|
|
|
|
const cinner = document.createElement('div') |
|
this.inner = document.createElement('div') |
|
|
|
cinner.append(this.inner) |
|
this.inner.classList.add('note-plus-preview') |
|
cinner.style.margin = '0' |
|
cinner.style.padding = '0' |
|
this.html_widget = this.addDOMWidget('HTML', 'html', cinner, { |
|
setValue: (val) => { |
|
this._raw_html = val |
|
}, |
|
getValue: () => this._raw_html, |
|
getMinHeight: () => this.calculated_height, |
|
onDraw: () => { |
|
|
|
this.html_widget.element.style.pointerEvents = 'none' |
|
|
|
|
|
}, |
|
hideOnZoom: false, |
|
}) |
|
|
|
this.setupSerializationWidgets() |
|
this.setupDialog() |
|
this.loadAceEditor() |
|
} |
|
|
|
|
|
|
|
|
|
|
|
onDrawForeground(ctx, _graphcanvas) { |
|
if (this.flags.collapsed) return |
|
this.drawEditIcon(ctx) |
|
this.drawSideHandle(ctx) |
|
|
|
|
|
|
|
|
|
|
|
} |
|
drawSideHandle(ctx) { |
|
const handleRect = this.sideHandleRect |
|
const chamfer = 20 |
|
ctx.beginPath() |
|
|
|
|
|
ctx.moveTo(handleRect.x, handleRect.y + chamfer) |
|
|
|
ctx.lineTo(handleRect.x + handleRect.width, handleRect.y) |
|
|
|
|
|
ctx.lineTo( |
|
handleRect.x + handleRect.width, |
|
handleRect.y + handleRect.height, |
|
) |
|
|
|
ctx.lineTo(handleRect.x, handleRect.y + handleRect.height - chamfer) |
|
ctx.closePath() |
|
|
|
ctx.fillStyle = 'rgba(255, 255, 255, 0.05)' |
|
ctx.fill() |
|
} |
|
|
|
drawEditIcon(ctx) { |
|
const rect = this.iconRect |
|
|
|
|
|
|
|
|
|
const pencilPath = new Path2D( |
|
'M21.28 6.4l-9.54 9.54c-.95.95-3.77 1.39-4.4.76-.63-.63-.2-3.45.75-4.4l9.55-9.55a2.58 2.58 0 1 1 3.64 3.65z', |
|
) |
|
const folderPath = new Path2D( |
|
'M11 4H6a4 4 0 0 0-4 4v10a4 4 0 0 0 4 4h11c2.21 0 3-1.8 3-4v-5', |
|
) |
|
|
|
ctx.save() |
|
ctx.translate(rect.x, rect.y) |
|
ctx.scale(rect.width / 32, rect.height / 32) |
|
ctx.strokeStyle = 'rgba(255,255,255,0.4)' |
|
ctx.lineCap = 'round' |
|
ctx.lineJoin = 'round' |
|
ctx.lineWidth = 2.4 |
|
ctx.stroke(pencilPath) |
|
ctx.stroke(folderPath) |
|
ctx.restore() |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
inRect(x, y, rect) { |
|
rect = rect || this.iconRect |
|
return ( |
|
x >= rect.x && |
|
x <= rect.x + rect.width && |
|
y >= rect.y && |
|
y <= rect.y + rect.height |
|
) |
|
} |
|
get rect() { |
|
return { |
|
x: 0, |
|
y: 0, |
|
width: this.size[0], |
|
height: this.size[1], |
|
} |
|
} |
|
get sideHandleRect() { |
|
const w = this.size[0] |
|
const h = this.size[1] |
|
|
|
const bw = 32 |
|
const bho = 64 |
|
|
|
return { |
|
x: w - bw, |
|
y: bho, |
|
width: bw, |
|
height: h - bho * 1.5, |
|
} |
|
} |
|
get iconRect() { |
|
const iconSize = 32 |
|
const iconMargin = 16 |
|
return { |
|
x: this.size[0] - iconSize - iconMargin, |
|
y: iconMargin * 1.5, |
|
width: iconSize, |
|
height: iconSize, |
|
} |
|
} |
|
onMouseDown(_e, localPos, _graphcanvas) { |
|
if (this.inRect(localPos[0], localPos[1])) { |
|
this.openEditorDialog() |
|
return true |
|
} |
|
return false |
|
} |
|
|
|
|
|
setupSerializationWidgets() { |
|
infoLogger('Setup Serializing widgets') |
|
|
|
this.edit_mode_widget = this.addWidget( |
|
'combo', |
|
'Mode', |
|
DEFAULT_MODE, |
|
(me) => successLogger('Updating edit_mode', me), |
|
{ |
|
values: ['html', 'markdown', 'raw'], |
|
}, |
|
) |
|
this.css_widget = this.addWidget('text', 'CSS', DEFAULT_CSS, (val) => { |
|
successLogger(`Updating css ${val}`) |
|
}) |
|
this.theme_widget = this.addWidget( |
|
'text', |
|
'Theme', |
|
DEFAULT_THEME, |
|
(val) => { |
|
successLogger(`Setting theme ${val}`) |
|
}, |
|
) |
|
|
|
shared.hideWidgetForGood(this, this.edit_mode_widget) |
|
shared.hideWidgetForGood(this, this.css_widget) |
|
shared.hideWidgetForGood(this, this.theme_widget) |
|
} |
|
|
|
setupDialog() { |
|
infoLogger('Setup dialog') |
|
|
|
this.dialog = new app.ui.dialog.constructor() |
|
this.dialog.element.classList.add('comfy-settings') |
|
|
|
Object.assign(this.dialog.element.style, { |
|
position: 'absolute', |
|
boxShadow: 'none', |
|
}) |
|
|
|
const subcontainer = this.dialog.textElement.parentElement |
|
|
|
if (subcontainer) { |
|
Object.assign(subcontainer.style, { |
|
width: '100%', |
|
}) |
|
} |
|
const closeButton = this.dialog.element.querySelector('button') |
|
closeButton.textContent = 'CANCEL' |
|
closeButton.id = 'cancel-editor-dialog' |
|
closeButton.title = |
|
"Cancel the changes since last opened (doesn't support live mode)" |
|
closeButton.disabled = this.live |
|
|
|
closeButton.style.background = this.live |
|
? 'repeating-linear-gradient(45deg,#606dbc,#606dbc 10px,#465298 10px,#465298 20px)' |
|
: '' |
|
|
|
const saveButton = document.createElement('button') |
|
saveButton.textContent = 'SAVE' |
|
saveButton.onclick = () => { |
|
this.closeEditorDialog(true) |
|
} |
|
closeButton.onclick = () => { |
|
this.closeEditorDialog(false) |
|
} |
|
closeButton.before(saveButton) |
|
} |
|
|
|
teardownEditors() { |
|
this.css_editor.destroy() |
|
this.css_editor.container.remove() |
|
|
|
this.html_editor.destroy() |
|
this.html_editor.container.remove() |
|
} |
|
|
|
closeEditorDialog(accept) { |
|
infoLogger('Closing editor dialog', accept) |
|
if (accept && !this.live) { |
|
this.updateHTML(this.html_editor.getValue()) |
|
this.updateCSS(this.css_editor.getValue()) |
|
} |
|
if (this.resizeObserver) { |
|
this.resizeObserver.disconnect() |
|
this.resizeObserver = null |
|
} |
|
this.teardownEditors() |
|
this.dialog.close() |
|
} |
|
|
|
|
|
|
|
|
|
hookResize(elem) { |
|
if (!this.resizeObserver) { |
|
const observer = () => { |
|
this.html_editor.resize() |
|
this.css_editor.resize() |
|
Object.assign(this.editorsContainer.style, { |
|
minHeight: `${(this.dialog.element.clientHeight / 100) * 50}px`, |
|
}) |
|
} |
|
this.resizeObserver = new ResizeObserver(observer).observe(elem) |
|
} |
|
} |
|
openEditorDialog() { |
|
infoLogger(`Current edit mode ${this.edit_mode_widget.value}`) |
|
this.hookResize(this.dialog.element) |
|
const container = document.createElement('div') |
|
Object.assign(container.style, { |
|
display: 'flex', |
|
gap: '10px', |
|
flexDirection: 'column', |
|
}) |
|
|
|
this.editorsContainer = document.createElement('div') |
|
|
|
Object.assign(this.editorsContainer.style, { |
|
display: 'flex', |
|
gap: '10px', |
|
flexDirection: 'row', |
|
minHeight: this.dialog.element.offsetHeight, |
|
width: '100%', |
|
}) |
|
|
|
container.append(this.editorsContainer) |
|
|
|
this.dialog.show('') |
|
this.dialog.textElement.append(container) |
|
|
|
const aceHTML = document.createElement('div') |
|
aceHTML.id = 'noteplus-html-editor' |
|
Object.assign(aceHTML.style, { |
|
width: '100%', |
|
height: '100%', |
|
|
|
minWidth: '300px', |
|
minHeight: 'inherit', |
|
}) |
|
|
|
this.editorsContainer.append(aceHTML) |
|
|
|
const aceCSS = document.createElement('div') |
|
aceCSS.id = 'noteplus-css-editor' |
|
Object.assign(aceCSS.style, { |
|
width: '100%', |
|
height: '100%', |
|
minHeight: 'inherit', |
|
}) |
|
|
|
this.editorsContainer.append(aceCSS) |
|
|
|
const live_edit = document.createElement('input') |
|
live_edit.type = 'checkbox' |
|
live_edit.checked = this.live |
|
live_edit.onchange = () => { |
|
this.live = live_edit.checked |
|
const cancel_button = this.dialog.element.querySelector( |
|
'#cancel-editor-dialog', |
|
) |
|
if (cancel_button) { |
|
cancel_button.disabled = this.live |
|
cancel_button.style.background = this.live |
|
? 'repeating-linear-gradient(45deg,#606dbc,#606dbc 10px,#465298 10px,#465298 20px)' |
|
: '' |
|
} |
|
} |
|
|
|
|
|
const firstButton = this.dialog.element.querySelector('button') |
|
const syncUI = () => { |
|
let convert_to_html = |
|
this.dialog.element.querySelector('#convert-to-html') |
|
if (this.edit_mode_widget.value === 'markdown') { |
|
if (convert_to_html == null) { |
|
convert_to_html = document.createElement('button') |
|
convert_to_html.textContent = 'Convert to HTML (NO UNDO!)' |
|
convert_to_html.id = 'convert-to-html' |
|
convert_to_html.onclick = () => { |
|
const select_mode = this.dialog.element.querySelector('#edit_mode') |
|
|
|
const md = this.html_editor.getValue() |
|
this.edit_mode_widget.value = 'html' |
|
select_mode.value = 'html' |
|
MTB.mdParser.parse(md).then((content) => { |
|
this.html_widget.value = content |
|
this.html_editor.setValue(content) |
|
this.html_editor.session.setMode('ace/mode/html') |
|
this.updateHTML(this.html_widget.value) |
|
convert_to_html.remove() |
|
}) |
|
} |
|
firstButton.before(convert_to_html) |
|
} |
|
} else { |
|
if (convert_to_html != null) { |
|
convert_to_html.remove() |
|
convert_to_html = null |
|
} |
|
} |
|
select_mode.value = this.edit_mode_widget.value |
|
|
|
|
|
const header = document.createElement('div') |
|
header.style.padding = '8px' |
|
header.style.cursor = 'move' |
|
header.style.backgroundColor = 'rgba(0,0,0,0.5)' |
|
header.style.userSelect = 'none' |
|
|
|
header.style.borderBottom = '1px solid #ddd' |
|
header.textContent = 'MTB Note+ Editor' |
|
container.prepend(header) |
|
makeDraggable(this.dialog.element, header) |
|
makeResizable(this.dialog.element) |
|
} |
|
|
|
let theme_select = this.dialog.element.querySelector('#theme_select') |
|
if (!theme_select) { |
|
infoLogger('Creating combobox for select') |
|
theme_select = document.createElement('select') |
|
theme_select.name = 'theme' |
|
theme_select.id = 'theme_select' |
|
|
|
const addOption = (label) => { |
|
const option = document.createElement('option') |
|
option.value = label |
|
option.textContent = label |
|
theme_select.append(option) |
|
} |
|
for (const t of THEMES) { |
|
addOption(t) |
|
} |
|
|
|
theme_select.addEventListener('change', (event) => { |
|
const val = event.target.value |
|
this.setTheme(val) |
|
}) |
|
|
|
container.prepend(theme_select) |
|
} |
|
|
|
theme_select.value = this.theme_widget.value |
|
|
|
let select_mode = this.dialog.element.querySelector('#edit_mode') |
|
|
|
if (!select_mode) { |
|
infoLogger('Creating combobox for select') |
|
select_mode = document.createElement('select') |
|
select_mode.name = 'mode' |
|
select_mode.id = 'edit_mode' |
|
|
|
const addOption = (label) => { |
|
const option = document.createElement('option') |
|
option.value = label |
|
option.textContent = label |
|
select_mode.append(option) |
|
} |
|
addOption('markdown') |
|
addOption('html') |
|
|
|
select_mode.addEventListener('change', (event) => { |
|
const val = event.target.value |
|
this.edit_mode_widget.value = val |
|
if (this.html_editor) { |
|
this.html_editor.session.setMode(`ace/mode/${val}`) |
|
this.updateHTML(this.html_editor.getValue()) |
|
|
|
syncUI() |
|
} |
|
}) |
|
|
|
container.append(select_mode) |
|
} |
|
select_mode.value = this.edit_mode_widget.value |
|
|
|
syncUI() |
|
|
|
const live_edit_label = document.createElement('label') |
|
live_edit_label.textContent = 'Live Edit' |
|
|
|
|
|
live_edit_label.title = |
|
'When this is on, the editor will update the note+ whenever you change the text.' |
|
|
|
live_edit_label.append(live_edit) |
|
|
|
|
|
container.append(live_edit_label) |
|
|
|
this.setupEditors() |
|
} |
|
loadAceEditor() { |
|
shared.loadScript('/mtb_async/ace/ace.js').catch((e) => { |
|
errorLogger(e) |
|
}) |
|
} |
|
onCreate() { |
|
errorLogger('NotePlus onCreate') |
|
} |
|
restoreNodeState(info) { |
|
this.html_widget.element.id = `note-plus-${this.uuid}` |
|
this.setMode(this.edit_mode_widget.value) |
|
this.setTheme(this.theme_widget.value) |
|
this.updateHTML(this.html_widget.value) |
|
this.updateCSS(this.css_widget.value) |
|
if (info?.size) { |
|
this.setSize(info.size) |
|
} |
|
} |
|
configure(info) { |
|
super.configure(info) |
|
infoLogger('Restoring serialized values', info) |
|
this.restoreNodeState(info) |
|
|
|
} |
|
onNodeCreated() { |
|
infoLogger('Node created', this.uuid) |
|
this.restoreNodeState({}) |
|
|
|
|
|
|
|
|
|
|
|
} |
|
onRemoved() { |
|
infoLogger('Node removed', this.uuid) |
|
} |
|
getExtraMenuOptions() { |
|
const currentMode = this.edit_mode_widget.value |
|
const newMode = currentMode === 'html' ? 'markdown' : 'html' |
|
|
|
const debugItems = window.MTB?.DEBUG |
|
? [ |
|
{ |
|
content: 'Replace with demo content (debug)', |
|
callback: () => { |
|
this.html_widget.value = DEMO_CONTENT |
|
}, |
|
}, |
|
] |
|
: [] |
|
|
|
return [ |
|
...debugItems, |
|
{ |
|
content: `Set to ${newMode}`, |
|
callback: () => { |
|
this.edit_mode_widget.value = newMode |
|
this.updateHTML(this.html_widget.value) |
|
}, |
|
}, |
|
] |
|
} |
|
|
|
_setupEditor(editor) { |
|
this.setTheme(this.theme_widget.value) |
|
|
|
editor.setShowPrintMargin(false) |
|
editor.session.setUseWrapMode(true) |
|
editor.renderer.setShowGutter(false) |
|
editor.session.setTabSize(4) |
|
editor.session.setUseSoftTabs(true) |
|
editor.setFontSize(14) |
|
editor.setReadOnly(false) |
|
editor.setHighlightActiveLine(false) |
|
editor.setShowFoldWidgets(true) |
|
return editor |
|
} |
|
|
|
setTheme(theme) { |
|
this.theme_widget.value = theme |
|
if (this.html_editor) { |
|
this.html_editor.setTheme(`ace/theme/${theme}`) |
|
} |
|
if (this.css_editor) { |
|
this.css_editor.setTheme(`ace/theme/${theme}`) |
|
} |
|
} |
|
|
|
setMode(mode) { |
|
this.edit_mode_widget.value = mode |
|
if (this.html_editor) { |
|
this.html_editor.session.setMode(`ace/mode/${mode}`) |
|
} |
|
|
|
this.updateHTML(this.html_widget.value) |
|
} |
|
setupEditors() { |
|
infoLogger('NotePlus setupEditor') |
|
|
|
this.html_editor = ace.edit('noteplus-html-editor') |
|
|
|
this.css_editor = ace.edit('noteplus-css-editor') |
|
this.css_editor.session.setMode('ace/mode/css') |
|
|
|
this.setMode(DEFAULT_MODE) |
|
|
|
this._setupEditor(this.html_editor) |
|
this._setupEditor(this.css_editor) |
|
|
|
this.css_editor.session.on('change', (_delta) => { |
|
|
|
if (this.live) { |
|
this.updateCSS(this.css_editor.getValue()) |
|
} |
|
}) |
|
|
|
this.html_editor.session.on('change', (_delta) => { |
|
|
|
if (this.live) { |
|
this.updateHTML(this.html_editor.getValue()) |
|
} |
|
}) |
|
|
|
this.html_editor.setValue(this.html_widget.value) |
|
this.css_editor.setValue(this.css_widget.value) |
|
} |
|
|
|
scopeCss(css, scopeId) { |
|
return css |
|
.split('}') |
|
.map((rule) => { |
|
if (rule.trim() === '') { |
|
return '' |
|
} |
|
const scopedRule = rule |
|
.split('{') |
|
.map((segment, index) => { |
|
if (index === 0) { |
|
return `#${scopeId} ${segment.trim()}` |
|
} |
|
return `{${segment.trim()}` |
|
}) |
|
.join(' ') |
|
return `${scopedRule}}` |
|
}) |
|
.join('\n') |
|
} |
|
getCssDom() { |
|
const styleTagId = `note-plus-stylesheet-${this.uuid}` |
|
|
|
let styleTag = document.head.querySelector(`#${styleTagId}`) |
|
|
|
if (!styleTag) { |
|
styleTag = document.createElement('style') |
|
styleTag.type = 'text/css' |
|
styleTag.id = styleTagId |
|
document.head.appendChild(styleTag) |
|
infoLogger(`Creating note-plus-stylesheet-${this.uuid}`, styleTag) |
|
} |
|
|
|
return styleTag |
|
} |
|
calculateHeight() { |
|
this.calculated_height = shared.calculateTotalChildrenHeight( |
|
this.html_widget.element, |
|
) |
|
this.setDirtyCanvas(true, true) |
|
} |
|
updateCSS(css) { |
|
infoLogger('NotePlus updateCSS') |
|
|
|
const scopedCss = this.scopeCss( |
|
`${CSS_RESET}\n${css}`, |
|
`note-plus-${this.uuid}`, |
|
) |
|
|
|
const cssDom = this.getCssDom() |
|
cssDom.innerHTML = scopedCss |
|
|
|
this.css_widget.value = css |
|
this.calculateHeight() |
|
infoLogger('NotePlus updateCSS', this.calculated_height) |
|
|
|
} |
|
|
|
parserInitiated() { |
|
if (window.MTB?.mdParser) return true |
|
return false |
|
} |
|
|
|
|
|
purify(content) { |
|
return DOMPurify.sanitize(content, { |
|
ADD_TAGS: ['iframe', 'detail', 'summary'], |
|
}) |
|
} |
|
|
|
updateHTML(val) { |
|
if (!this.parserInitiated()) { |
|
return |
|
} |
|
val = val || this.html_widget.value |
|
const isHTML = this.edit_mode_widget.value === 'html' |
|
|
|
const cleanHTML = this.purify(val) |
|
|
|
const value = isHTML |
|
? cleanHTML |
|
: cleanHTML.replaceAll('>', '>').replaceAll('<', '<') |
|
|
|
|
|
|
|
|
|
this.html_widget.value = value |
|
|
|
if (isHTML) { |
|
this.inner.innerHTML = value |
|
} else { |
|
MTB.mdParser.parse(value).then((e) => { |
|
this.inner.innerHTML = e |
|
}) |
|
} |
|
|
|
this.calculateHeight() |
|
|
|
} |
|
} |
|
|
|
app.registerExtension({ |
|
name: 'mtb.noteplus', |
|
setup: () => { |
|
app.ui.settings.addSetting({ |
|
id: 'mtb.noteplus.use-shiki', |
|
category: ['mtb', 'Note+', 'use-shiki'], |
|
name: 'Use shiki to highlight code', |
|
tooltip: |
|
'This will load a larger version of @mtb/markdown-parser that bundles shiki, it supports all shiki transformers (supported langs: html,css,python,markdown)', |
|
|
|
type: 'boolean', |
|
defaultValue: false, |
|
attrs: { |
|
style: { |
|
|
|
}, |
|
}, |
|
async onChange(value) { |
|
storage.set('np-use-shiki', value) |
|
useShiki = value |
|
}, |
|
}) |
|
}, |
|
|
|
registerCustomNodes() { |
|
LiteGraph.registerNodeType('Note Plus (mtb)', NotePlus) |
|
|
|
NotePlus.category = 'mtb/utils' |
|
NotePlus.title = 'Note+ (mtb)' |
|
|
|
NotePlus.title_mode = LiteGraph.NO_TITLE |
|
}, |
|
}) |
|
|