foldcode.js 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. // CodeMirror, copyright (c) by Marijn Haverbeke and others
  2. // Distributed under an MIT license: https://codemirror.net/LICENSE
  3. ;(function (mod) {
  4. if (typeof exports == 'object' && typeof module == 'object')
  5. // CommonJS
  6. mod(require('../../lib/codemirror'))
  7. else if (typeof define == 'function' && define.amd)
  8. // AMD
  9. define(['../../lib/codemirror'], mod)
  10. // Plain browser env
  11. else mod(CodeMirror)
  12. })(function (CodeMirror) {
  13. 'use strict'
  14. function doFold(cm, pos, options, force) {
  15. if (options && options.call) {
  16. var finder = options
  17. options = null
  18. } else {
  19. var finder = getOption(cm, options, 'rangeFinder')
  20. }
  21. if (typeof pos == 'number') pos = CodeMirror.Pos(pos, 0)
  22. var minSize = getOption(cm, options, 'minFoldSize')
  23. function getRange(allowFolded) {
  24. var range = finder(cm, pos)
  25. if (!range || range.to.line - range.from.line < minSize) return null
  26. if (force === 'fold') return range
  27. var marks = cm.findMarksAt(range.from)
  28. for (var i = 0; i < marks.length; ++i) {
  29. if (marks[i].__isFold) {
  30. if (!allowFolded) return null
  31. range.cleared = true
  32. marks[i].clear()
  33. }
  34. }
  35. return range
  36. }
  37. var range = getRange(true)
  38. if (getOption(cm, options, 'scanUp'))
  39. while (!range && pos.line > cm.firstLine()) {
  40. pos = CodeMirror.Pos(pos.line - 1, 0)
  41. range = getRange(false)
  42. }
  43. if (!range || range.cleared || force === 'unfold') return
  44. var myWidget = makeWidget(cm, options, range)
  45. CodeMirror.on(myWidget, 'mousedown', function (e) {
  46. myRange.clear()
  47. CodeMirror.e_preventDefault(e)
  48. })
  49. var myRange = cm.markText(range.from, range.to, {
  50. replacedWith: myWidget,
  51. clearOnEnter: getOption(cm, options, 'clearOnEnter'),
  52. __isFold: true,
  53. })
  54. myRange.on('clear', function (from, to) {
  55. CodeMirror.signal(cm, 'unfold', cm, from, to)
  56. })
  57. CodeMirror.signal(cm, 'fold', cm, range.from, range.to)
  58. }
  59. function makeWidget(cm, options, range) {
  60. var widget = getOption(cm, options, 'widget')
  61. if (typeof widget == 'function') {
  62. widget = widget(range.from, range.to)
  63. }
  64. if (typeof widget == 'string') {
  65. var text = document.createTextNode(widget)
  66. widget = document.createElement('span')
  67. widget.appendChild(text)
  68. widget.className = 'CodeMirror-foldmarker'
  69. } else if (widget) {
  70. widget = widget.cloneNode(true)
  71. }
  72. return widget
  73. }
  74. // Clumsy backwards-compatible interface
  75. CodeMirror.newFoldFunction = function (rangeFinder, widget) {
  76. return function (cm, pos) {
  77. doFold(cm, pos, { rangeFinder: rangeFinder, widget: widget })
  78. }
  79. }
  80. // New-style interface
  81. CodeMirror.defineExtension('foldCode', function (pos, options, force) {
  82. doFold(this, pos, options, force)
  83. })
  84. CodeMirror.defineExtension('isFolded', function (pos) {
  85. var marks = this.findMarksAt(pos)
  86. for (var i = 0; i < marks.length; ++i) if (marks[i].__isFold) return true
  87. })
  88. CodeMirror.commands.toggleFold = function (cm) {
  89. cm.foldCode(cm.getCursor())
  90. }
  91. CodeMirror.commands.fold = function (cm) {
  92. cm.foldCode(cm.getCursor(), null, 'fold')
  93. }
  94. CodeMirror.commands.unfold = function (cm) {
  95. cm.foldCode(cm.getCursor(), { scanUp: false }, 'unfold')
  96. }
  97. CodeMirror.commands.foldAll = function (cm) {
  98. cm.operation(function () {
  99. for (var i = cm.firstLine(), e = cm.lastLine(); i <= e; i++) cm.foldCode(CodeMirror.Pos(i, 0), { scanUp: false }, 'fold')
  100. })
  101. }
  102. CodeMirror.commands.unfoldAll = function (cm) {
  103. cm.operation(function () {
  104. for (var i = cm.firstLine(), e = cm.lastLine(); i <= e; i++) cm.foldCode(CodeMirror.Pos(i, 0), { scanUp: false }, 'unfold')
  105. })
  106. }
  107. CodeMirror.registerHelper('fold', 'combine', function () {
  108. var funcs = Array.prototype.slice.call(arguments, 0)
  109. return function (cm, start) {
  110. for (var i = 0; i < funcs.length; ++i) {
  111. var found = funcs[i](cm, start)
  112. if (found) return found
  113. }
  114. }
  115. })
  116. CodeMirror.registerHelper('fold', 'auto', function (cm, start) {
  117. var helpers = cm.getHelpers(start, 'fold')
  118. for (var i = 0; i < helpers.length; i++) {
  119. var cur = helpers[i](cm, start)
  120. if (cur) return cur
  121. }
  122. })
  123. var defaultOptions = {
  124. rangeFinder: CodeMirror.fold.auto,
  125. widget: '\u2194',
  126. minFoldSize: 0,
  127. scanUp: false,
  128. clearOnEnter: true,
  129. }
  130. CodeMirror.defineOption('foldOptions', null)
  131. function getOption(cm, options, name) {
  132. if (options && options[name] !== undefined) return options[name]
  133. var editorOptions = cm.options.foldOptions
  134. if (editorOptions && editorOptions[name] !== undefined) return editorOptions[name]
  135. return defaultOptions[name]
  136. }
  137. CodeMirror.defineExtension('foldOption', function (options, name) {
  138. return getOption(this, options, name)
  139. })
  140. })