// CodeMirror, copyright (c) by Marijn Haverbeke and others // Distributed under an MIT license: https://codemirror.net/LICENSE ;(function (mod) { if (typeof exports == 'object' && typeof module == 'object') // CommonJS mod(require('../../lib/codemirror'), require('./foldcode')) else if (typeof define == 'function' && define.amd) // AMD define(['../../lib/codemirror', './foldcode'], mod) // Plain browser env else mod(CodeMirror) })(function (CodeMirror) { 'use strict' 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) } }) var Pos = CodeMirror.Pos function State(options) { this.options = options this.from = this.to = 0 } function parseOptions(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 } function isFolded(cm, line) { var marks = cm.findMarks(Pos(line, 0), Pos(line + 1, 0)) for (var i = 0; i < marks.length; ++i) { if (marks[i].__isFold) { var fromPos = marks[i].find(-1) if (fromPos && fromPos.line === line) return marks[i] } } } function marker(spec) { if (typeof spec == 'string') { var elt = document.createElement('div') elt.className = spec + ' CodeMirror-guttermarker-subtle' return elt } else { return spec.cloneNode(true) } } function updateFoldInfo(cm, from, to) { var opts = cm.state.foldGutter.options, cur = from - 1 var minSize = cm.foldOption(opts, 'minFoldSize') var func = cm.foldOption(opts, 'rangeFinder') // we can reuse the built-in indicator element if its className matches the new state var clsFolded = typeof opts.indicatorFolded == 'string' && classTest(opts.indicatorFolded) var clsOpen = typeof opts.indicatorOpen == 'string' && classTest(opts.indicatorOpen) cm.eachLine(from, to, function (line) { ++cur var mark = null var 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 { var pos = Pos(cur, 0) var 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 function classTest(cls) { return new RegExp('(^|\\s)' + cls + '(?:$|\\s)\\s*') } function updateInViewport(cm) { var 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 } function onGutterClick(cm, line, gutter) { var state = cm.state.foldGutter if (!state) return var opts = state.options if (gutter != opts.gutter) return var folded = isFolded(cm, line) if (folded) folded.clear() else cm.foldCode(Pos(line, 0), opts) } function onChange(cm) { var state = cm.state.foldGutter if (!state) return var opts = state.options state.from = state.to = 0 clearTimeout(state.changeUpdate) state.changeUpdate = setTimeout(function () { updateInViewport(cm) }, opts.foldOnChangeTimeSpan || 600) } function onViewportChange(cm) { var state = cm.state.foldGutter if (!state) return var opts = state.options clearTimeout(state.changeUpdate) state.changeUpdate = setTimeout(function () { var 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) } function onFold(cm, from) { var state = cm.state.foldGutter if (!state) return var line = from.line if (line >= state.from && line < state.to) updateFoldInfo(cm, line, line + 1) } })