mirror of
https://github.com/naturalcrit/homebrewery.git
synced 2025-12-24 18:32:41 +00:00
Replace copied code with require methods to import the CodeMirror helpers
Put back the correct require notation for importing the foldcode and foldgutter helpers #629
This commit is contained in:
@@ -14,8 +14,11 @@ if(typeof navigator !== 'undefined'){
|
||||
require('codemirror/mode/css/css.js');
|
||||
require('codemirror/mode/javascript/javascript.js');
|
||||
|
||||
// this should add the foldcode helpers and such to the CodeMirror object, but seemingly is adding them to a new instance of CodeMirror
|
||||
require('codemirror/addon/fold/foldcode.js');
|
||||
require('codemirror/addon/fold/foldgutter.js');
|
||||
|
||||
const foldCode = require('./fold-code');
|
||||
foldCode.enableCodeFolding(CodeMirror);
|
||||
foldCode.registerHomebreweryHelper(CodeMirror);
|
||||
}
|
||||
|
||||
@@ -40,8 +43,10 @@ const CodeEditor = createClass({
|
||||
const newDoc = CodeMirror.Doc(this.props.value, this.props.language);
|
||||
this.codeMirror.swapDoc(newDoc);
|
||||
},
|
||||
|
||||
componentDidUpdate : function(prevProps) {
|
||||
getSnapshotBeforeUpdate : function() {
|
||||
return _.uniq(this.codeMirror.getAllMarks().filter((mark)=>mark.__isFold).map((mark)=>mark.find().from));
|
||||
},
|
||||
componentDidUpdate : function(prevProps, prevState, snapshot) {
|
||||
if(prevProps.view !== this.props.view){ //view changed; swap documents
|
||||
let newDoc;
|
||||
|
||||
@@ -61,6 +66,12 @@ const CodeEditor = createClass({
|
||||
} else if(this.codeMirror?.getValue() != this.props.value) { //update editor contents if brew.text is changed from outside
|
||||
this.codeMirror.setValue(this.props.value);
|
||||
}
|
||||
|
||||
setTimeout(()=>{
|
||||
snapshot.forEach((fold)=>{
|
||||
this.codeMirror.foldCode(fold, { scanUp: false }, 'fold');
|
||||
});
|
||||
}, 0);
|
||||
},
|
||||
|
||||
buildEditor : function() {
|
||||
@@ -79,12 +90,30 @@ const CodeEditor = createClass({
|
||||
'Cmd-M' : this.makeSpan,
|
||||
'Ctrl-/' : this.makeComment,
|
||||
'Cmd-/' : this.makeComment,
|
||||
'Ctrl-,' : this.toggleCodeFolded,
|
||||
'Cmd-,' : this.toggleCodeFolded
|
||||
'Ctrl-\\' : this.toggleCodeFolded,
|
||||
'Cmd-\\' : this.toggleCodeFolded,
|
||||
'Ctrl-[' : this.foldAllCode,
|
||||
'Cmd-[' : this.foldAllCode,
|
||||
'Ctrl-]' : this.unfoldAllCode,
|
||||
'Cmd-]' : this.unfoldAllCode
|
||||
},
|
||||
foldGutter : true,
|
||||
foldOptions : {
|
||||
rangeFinder : CodeMirror.fold.homebrewery,
|
||||
widget : (from, to)=>{
|
||||
let text = '';
|
||||
let currentLine = from.line;
|
||||
const maxLength = 50;
|
||||
while (currentLine <= to.line && text.length <= maxLength) {
|
||||
text += this.codeMirror.getLine(currentLine);
|
||||
if(currentLine < to.line) {
|
||||
text += ' ';
|
||||
}
|
||||
currentLine += 1;
|
||||
}
|
||||
|
||||
return `\u21A4${text.substr(0, maxLength)}\u21A6`;
|
||||
}
|
||||
},
|
||||
gutters : ['CodeMirror-linenumbers', 'CodeMirror-foldgutter']
|
||||
});
|
||||
@@ -134,6 +163,14 @@ const CodeEditor = createClass({
|
||||
this.codeMirror.foldCode(this.codeMirror.getCursor());
|
||||
},
|
||||
|
||||
foldAllCode : function() {
|
||||
this.codeMirror.execCommand('foldAll');
|
||||
},
|
||||
|
||||
unfoldAllCode : function() {
|
||||
this.codeMirror.execCommand('unfoldAll');
|
||||
},
|
||||
|
||||
//=-- Externally used -==//
|
||||
setCursorPosition : function(line, char){
|
||||
setTimeout(()=>{
|
||||
|
||||
@@ -2,5 +2,7 @@
|
||||
@import (less) 'codemirror/addon/fold/foldgutter.css';
|
||||
|
||||
.codeEditor{
|
||||
|
||||
.CodeMirror-foldmarker {
|
||||
font-family: inherit;
|
||||
}
|
||||
}
|
||||
@@ -1,313 +1,4 @@
|
||||
/* eslint-disable max-lines */
|
||||
module.exports = {
|
||||
enableCodeFolding : function (CodeMirror) {
|
||||
// foldcode.js
|
||||
const makeWidget = function(cm, options, range) {
|
||||
let widget = getOption(cm, options, 'widget');
|
||||
|
||||
if(typeof widget == 'function') {
|
||||
widget = widget(range.from, range.to);
|
||||
}
|
||||
|
||||
if(typeof widget == 'string') {
|
||||
const text = document.createTextNode(widget);
|
||||
widget = document.createElement('span');
|
||||
widget.appendChild(text);
|
||||
widget.className = 'CodeMirror-foldmarker';
|
||||
} else if(widget) {
|
||||
widget = widget.cloneNode(true);
|
||||
}
|
||||
return widget;
|
||||
};
|
||||
|
||||
const doFold = function(cm, pos, options, force) {
|
||||
let finder;
|
||||
if(options && options.call) {
|
||||
finder = options;
|
||||
options = null;
|
||||
} else {
|
||||
finder = getOption(cm, options, 'rangeFinder');
|
||||
}
|
||||
if(typeof pos == 'number') pos = CodeMirror.Pos(pos, 0);
|
||||
const minSize = getOption(cm, options, 'minFoldSize');
|
||||
|
||||
const getRange = function(allowFolded) {
|
||||
const range = finder(cm, pos);
|
||||
if(!range || range.to.line - range.from.line < minSize) return null;
|
||||
if(force === 'fold') return range;
|
||||
|
||||
const marks = cm.findMarksAt(range.from);
|
||||
for (let i = 0; i < marks.length; ++i) {
|
||||
if(marks[i].__isFold) {
|
||||
if(!allowFolded) return null;
|
||||
range.cleared = true;
|
||||
marks[i].clear();
|
||||
}
|
||||
}
|
||||
return range;
|
||||
};
|
||||
|
||||
let range = getRange(true);
|
||||
if(getOption(cm, options, 'scanUp')) while (!range && pos.line > cm.firstLine()) {
|
||||
pos = CodeMirror.Pos(pos.line - 1, 0);
|
||||
range = getRange(false);
|
||||
}
|
||||
if(!range || range.cleared || force === 'unfold') return;
|
||||
|
||||
const myWidget = makeWidget(cm, options, range);
|
||||
CodeMirror.on(myWidget, 'mousedown', function (e) {
|
||||
myRange.clear();
|
||||
CodeMirror.e_preventDefault(e);
|
||||
});
|
||||
const myRange = cm.markText(range.from, range.to, {
|
||||
replacedWith : myWidget,
|
||||
clearOnEnter : getOption(cm, options, 'clearOnEnter'),
|
||||
__isFold : true
|
||||
});
|
||||
myRange.on('clear', function (from, to) {
|
||||
CodeMirror.signal(cm, 'unfold', cm, from, to);
|
||||
});
|
||||
CodeMirror.signal(cm, 'fold', cm, range.from, range.to);
|
||||
};
|
||||
|
||||
// Clumsy backwards-compatible interface
|
||||
CodeMirror.newFoldFunction = function (rangeFinder, widget) {
|
||||
return function (cm, pos) {
|
||||
doFold(cm, pos, { rangeFinder: rangeFinder, widget: widget });
|
||||
};
|
||||
};
|
||||
|
||||
// New-style interface
|
||||
CodeMirror.defineExtension('foldCode', function (pos, options, force) {
|
||||
doFold(this, pos, options, force);
|
||||
});
|
||||
|
||||
CodeMirror.defineExtension('isFolded', function (pos) {
|
||||
const marks = this.findMarksAt(pos);
|
||||
for (let i = 0; i < marks.length; ++i)
|
||||
if(marks[i].__isFold) return true;
|
||||
});
|
||||
|
||||
CodeMirror.commands.toggleFold = function (cm) {
|
||||
cm.foldCode(cm.getCursor());
|
||||
};
|
||||
CodeMirror.commands.fold = function (cm) {
|
||||
cm.foldCode(cm.getCursor(), null, 'fold');
|
||||
};
|
||||
CodeMirror.commands.unfold = function (cm) {
|
||||
cm.foldCode(cm.getCursor(), { scanUp: false }, 'unfold');
|
||||
};
|
||||
CodeMirror.commands.foldAll = function (cm) {
|
||||
cm.operation(function () {
|
||||
for (let i = cm.firstLine(), e = cm.lastLine(); i <= e; i++)
|
||||
cm.foldCode(CodeMirror.Pos(i, 0), { scanUp: false }, 'fold');
|
||||
});
|
||||
};
|
||||
CodeMirror.commands.unfoldAll = function (cm) {
|
||||
cm.operation(function () {
|
||||
for (let i = cm.firstLine(), e = cm.lastLine(); i <= e; i++)
|
||||
cm.foldCode(CodeMirror.Pos(i, 0), { scanUp: false }, 'unfold');
|
||||
});
|
||||
};
|
||||
|
||||
CodeMirror.registerHelper('fold', 'combine', function () {
|
||||
const funcs = Array.prototype.slice.call(arguments, 0);
|
||||
return function (cm, start) {
|
||||
for (let i = 0; i < funcs.length; ++i) {
|
||||
const found = funcs[i](cm, start);
|
||||
if(found) return found;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
CodeMirror.registerHelper('fold', 'auto', function (cm, start) {
|
||||
const helpers = cm.getHelpers(start, 'fold');
|
||||
for (let i = 0; i < helpers.length; i++) {
|
||||
const cur = helpers[i](cm, start);
|
||||
if(cur) return cur;
|
||||
}
|
||||
});
|
||||
|
||||
const defaultOptions = {
|
||||
rangeFinder : CodeMirror.fold.auto,
|
||||
widget : '\u2194',
|
||||
minFoldSize : 0,
|
||||
scanUp : false,
|
||||
clearOnEnter : true
|
||||
};
|
||||
|
||||
CodeMirror.defineOption('foldOptions', null);
|
||||
|
||||
const getOption = function(cm, options, name) {
|
||||
if(options && options[name] !== undefined)
|
||||
return options[name];
|
||||
const editorOptions = cm.options.foldOptions;
|
||||
if(editorOptions && editorOptions[name] !== undefined)
|
||||
return editorOptions[name];
|
||||
return defaultOptions[name];
|
||||
};
|
||||
|
||||
CodeMirror.defineExtension('foldOption', function (options, name) {
|
||||
return getOption(this, options, name);
|
||||
});
|
||||
|
||||
// foldgutter.js
|
||||
const State = function(options) {
|
||||
this.options = options;
|
||||
this.from = this.to = 0;
|
||||
};
|
||||
|
||||
const parseOptions = function(opts) {
|
||||
if(opts === true) opts = {};
|
||||
if(opts.gutter == null) opts.gutter = 'CodeMirror-foldgutter';
|
||||
if(opts.indicatorOpen == null) opts.indicatorOpen = 'CodeMirror-foldgutter-open';
|
||||
if(opts.indicatorFolded == null) opts.indicatorFolded = 'CodeMirror-foldgutter-folded';
|
||||
return opts;
|
||||
};
|
||||
|
||||
CodeMirror.defineOption('foldGutter', false, function (cm, val, old) {
|
||||
if(old && old != CodeMirror.Init) {
|
||||
cm.clearGutter(cm.state.foldGutter.options.gutter);
|
||||
cm.state.foldGutter = null;
|
||||
cm.off('gutterClick', onGutterClick);
|
||||
cm.off('changes', onChange);
|
||||
cm.off('viewportChange', onViewportChange);
|
||||
cm.off('fold', onFold);
|
||||
cm.off('unfold', onFold);
|
||||
cm.off('swapDoc', onChange);
|
||||
}
|
||||
if(val) {
|
||||
cm.state.foldGutter = new State(parseOptions(val));
|
||||
updateInViewport(cm);
|
||||
cm.on('gutterClick', onGutterClick);
|
||||
cm.on('changes', onChange);
|
||||
cm.on('viewportChange', onViewportChange);
|
||||
cm.on('fold', onFold);
|
||||
cm.on('unfold', onFold);
|
||||
cm.on('swapDoc', onChange);
|
||||
}
|
||||
});
|
||||
|
||||
const Pos = CodeMirror.Pos;
|
||||
|
||||
const isFolded = function(cm, line) {
|
||||
const marks = cm.findMarks(Pos(line, 0), Pos(line + 1, 0));
|
||||
for (let i = 0; i < marks.length; ++i) {
|
||||
if(marks[i].__isFold) {
|
||||
const fromPos = marks[i].find(-1);
|
||||
if(fromPos && fromPos.line === line)
|
||||
return marks[i];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const marker = function(spec) {
|
||||
if(typeof spec == 'string') {
|
||||
const elt = document.createElement('div');
|
||||
elt.className = `${spec} CodeMirror-guttermarker-subtle`;
|
||||
return elt;
|
||||
} else {
|
||||
return spec.cloneNode(true);
|
||||
}
|
||||
};
|
||||
|
||||
const updateFoldInfo = function(cm, from, to) {
|
||||
const opts = cm.state.foldGutter.options;
|
||||
let cur = from - 1;
|
||||
const minSize = cm.foldOption(opts, 'minFoldSize');
|
||||
const func = cm.foldOption(opts, 'rangeFinder');
|
||||
// we can reuse the built-in indicator element if its className matches the new state
|
||||
const clsFolded = typeof opts.indicatorFolded == 'string' && classTest(opts.indicatorFolded);
|
||||
const clsOpen = typeof opts.indicatorOpen == 'string' && classTest(opts.indicatorOpen);
|
||||
cm.eachLine(from, to, function (line) {
|
||||
++cur;
|
||||
let mark = null;
|
||||
let old = line.gutterMarkers;
|
||||
if(old) old = old[opts.gutter];
|
||||
if(isFolded(cm, cur)) {
|
||||
if(clsFolded && old && clsFolded.test(old.className)) return;
|
||||
mark = marker(opts.indicatorFolded);
|
||||
} else {
|
||||
const pos = Pos(cur, 0);
|
||||
const range = func && func(cm, pos);
|
||||
if(range && range.to.line - range.from.line >= minSize) {
|
||||
if(clsOpen && old && clsOpen.test(old.className)) return;
|
||||
mark = marker(opts.indicatorOpen);
|
||||
}
|
||||
}
|
||||
if(!mark && !old) return;
|
||||
cm.setGutterMarker(line, opts.gutter, mark);
|
||||
});
|
||||
};
|
||||
|
||||
// copied from CodeMirror/src/util/dom.js
|
||||
const classTest = function(cls) {
|
||||
return new RegExp(`(^|\\s)${cls}(?:$|\\s)\\s*`);
|
||||
};
|
||||
|
||||
const updateInViewport = function(cm) {
|
||||
const vp = cm.getViewport(), state = cm.state.foldGutter;
|
||||
if(!state) return;
|
||||
cm.operation(function () {
|
||||
updateFoldInfo(cm, vp.from, vp.to);
|
||||
});
|
||||
state.from = vp.from;
|
||||
state.to = vp.to;
|
||||
};
|
||||
|
||||
const onGutterClick = function(cm, line, gutter) {
|
||||
const state = cm.state.foldGutter;
|
||||
if(!state) return;
|
||||
const opts = state.options;
|
||||
if(gutter != opts.gutter) return;
|
||||
const folded = isFolded(cm, line);
|
||||
if(folded) folded.clear();
|
||||
else cm.foldCode(Pos(line, 0), opts);
|
||||
};
|
||||
|
||||
const onChange = function(cm) {
|
||||
const state = cm.state.foldGutter;
|
||||
if(!state) return;
|
||||
const opts = state.options;
|
||||
state.from = state.to = 0;
|
||||
clearTimeout(state.changeUpdate);
|
||||
state.changeUpdate = setTimeout(function () {
|
||||
updateInViewport(cm);
|
||||
}, opts.foldOnChangeTimeSpan || 600);
|
||||
};
|
||||
|
||||
const onViewportChange = function(cm) {
|
||||
const state = cm.state.foldGutter;
|
||||
if(!state) return;
|
||||
const opts = state.options;
|
||||
clearTimeout(state.changeUpdate);
|
||||
state.changeUpdate = setTimeout(function () {
|
||||
const vp = cm.getViewport();
|
||||
if(state.from == state.to || vp.from - state.to > 20 || state.from - vp.to > 20) {
|
||||
updateInViewport(cm);
|
||||
} else {
|
||||
cm.operation(function () {
|
||||
if(vp.from < state.from) {
|
||||
updateFoldInfo(cm, vp.from, state.from);
|
||||
state.from = vp.from;
|
||||
}
|
||||
if(vp.to > state.to) {
|
||||
updateFoldInfo(cm, state.to, vp.to);
|
||||
state.to = vp.to;
|
||||
}
|
||||
});
|
||||
}
|
||||
}, opts.updateViewportTimeSpan || 400);
|
||||
};
|
||||
|
||||
const onFold = function(cm, from) {
|
||||
const state = cm.state.foldGutter;
|
||||
if(!state) return;
|
||||
const line = from.line;
|
||||
if(line >= state.from && line < state.to)
|
||||
updateFoldInfo(cm, line, line + 1);
|
||||
};
|
||||
},
|
||||
registerHomebreweryHelper : function(CodeMirror) {
|
||||
CodeMirror.registerHelper('fold', 'homebrewery', function(cm, start) {
|
||||
const matcher = /^\\page.*/;
|
||||
@@ -321,7 +12,7 @@ module.exports = {
|
||||
while (end < lastLineNo) {
|
||||
if(nextLine.match(matcher)) {
|
||||
return {
|
||||
from : CodeMirror.Pos(start.line, firstLine.length),
|
||||
from : CodeMirror.Pos(start.line, 0),
|
||||
to : CodeMirror.Pos(end, cm.getLine(end).length)
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user