0
0
mirror of https://github.com/naturalcrit/homebrewery.git synced 2026-01-25 09:43:03 +00:00
Files
homebrewery/shared/naturalcrit/codeEditor/helpers/widgets.js

93 lines
2.8 KiB
JavaScript

const React = require('react');
const ReactDOM = require('react-dom');
const { PATTERNS, FIELD_TYPE } = require('./widget-elements/constants');
require('./widget-elements/hints/hints.jsx');
module.exports = function(CodeMirror, widgets, cm, setHints) {
const hintsEl = document.createElement('ul');
hintsEl.id = 'hints';
hintsEl.role = 'listbox';
hintsEl.ariaExpanded = 'true';
hintsEl.className = 'CodeMirror-hints default';
hintsEl.style = 'display: none;';
document.body.append(hintsEl);
const { cClass, field } = require('./widget-elements')(CodeMirror, setHints);
const widgetOptions = widgets.map((widget)=>({
name : widget.name,
pattern : PATTERNS.widget[widget.type](widget.name),
createWidget : (n, node)=>{
const parent = document.createElement('div');
const classes = (widget.classes || []).map((c, i)=>cClass(cm, n, `{{${widget.name}`, c));
const fieldNames = (widget.fields || []).map((f)=>f.name);
const fields = (widget.fields || []).map((f, i)=>field(cm, n, f)).filter((f)=>!!f);
const { text } = cm.lineInfo(n);
const styles = [...text.matchAll(PATTERNS.collectStyles)].map(([_, style])=>{
if(fieldNames.includes(style)) return false;
return field(cm, n, {
name : style,
type : FIELD_TYPE.STYLE,
increment : 5
});
}).filter((s)=>!!s);
ReactDOM.render(<React.Fragment>
{classes}
{fields}
{styles}
</React.Fragment>, node || parent);
return node || parent;
}
}));
const updateLineWidgets = (n, remove)=>{
const { text, widgets } = cm.lineInfo(n);
const widgetOption = widgetOptions.find((option)=>!!text.match(option.pattern));
if(!widgetOption) return;
if(!!widgets) {
for (const widget of widgets) {
widgetOption.createWidget(n, widget.node);
}
} else {
return cm.addLineWidget(n, widgetOption.createWidget(n), {
above : false,
coverGutter : false,
noHScroll : true,
className : `snippet-options-widget ${widgetOption.name}-widget ${widgetOption.name}-widget-${n}`
});
}
};
return {
removeLineWidgets : (widget)=>{
cm.removeLineWidget(widget);
},
updateLineWidgets,
updateAllLineWidgets : ()=>{
for (let i = 0; i < cm.lineCount(); i++) {
const { widgets } = cm.lineInfo(i);
if(!!widgets) {
updateLineWidgets(i);
}
}
},
updateWidgetGutter : ()=>{
cm.operation(()=>{
for (let i = 0; i < cm.lineCount(); i++) {
const line = cm.getLine(i);
if(widgetOptions.some((option)=>line.match(option.pattern))) {
const optionsMarker = document.createElement('div');
optionsMarker.style.color = '#822';
optionsMarker.style.cursor = 'pointer';
optionsMarker.innerHTML = '●';
cm.setGutterMarker(i, 'widget-gutter', optionsMarker);
} else {
cm.setGutterMarker(i, 'widget-gutter', null);
}
}
});
}
};
};