GPQAPP

Форк
0
163 строки · 5.2 Кб
1
// CodeMirror, copyright (c) by Marijn Haverbeke and others
2
// Distributed under an MIT license: https://codemirror.net/LICENSE
3

4
(function(mod) {
5
  if (typeof exports == "object" && typeof module == "object") // CommonJS
6
    mod(require("../../lib/codemirror"), require("./foldcode"));
7
  else if (typeof define == "function" && define.amd) // AMD
8
    define(["../../lib/codemirror", "./foldcode"], mod);
9
  else // Plain browser env
10
    mod(CodeMirror);
11
})(function(CodeMirror) {
12
  "use strict";
13

14
  CodeMirror.defineOption("foldGutter", false, function(cm, val, old) {
15
    if (old && old != CodeMirror.Init) {
16
      cm.clearGutter(cm.state.foldGutter.options.gutter);
17
      cm.state.foldGutter = null;
18
      cm.off("gutterClick", onGutterClick);
19
      cm.off("changes", onChange);
20
      cm.off("viewportChange", onViewportChange);
21
      cm.off("fold", onFold);
22
      cm.off("unfold", onFold);
23
      cm.off("swapDoc", onChange);
24
    }
25
    if (val) {
26
      cm.state.foldGutter = new State(parseOptions(val));
27
      updateInViewport(cm);
28
      cm.on("gutterClick", onGutterClick);
29
      cm.on("changes", onChange);
30
      cm.on("viewportChange", onViewportChange);
31
      cm.on("fold", onFold);
32
      cm.on("unfold", onFold);
33
      cm.on("swapDoc", onChange);
34
    }
35
  });
36

37
  var Pos = CodeMirror.Pos;
38

39
  function State(options) {
40
    this.options = options;
41
    this.from = this.to = 0;
42
  }
43

44
  function parseOptions(opts) {
45
    if (opts === true) opts = {};
46
    if (opts.gutter == null) opts.gutter = "CodeMirror-foldgutter";
47
    if (opts.indicatorOpen == null) opts.indicatorOpen = "CodeMirror-foldgutter-open";
48
    if (opts.indicatorFolded == null) opts.indicatorFolded = "CodeMirror-foldgutter-folded";
49
    return opts;
50
  }
51

52
  function isFolded(cm, line) {
53
    var marks = cm.findMarks(Pos(line, 0), Pos(line + 1, 0));
54
    for (var i = 0; i < marks.length; ++i) {
55
      if (marks[i].__isFold) {
56
        var fromPos = marks[i].find(-1);
57
        if (fromPos && fromPos.line === line)
58
          return marks[i];
59
      }
60
    }
61
  }
62

63
  function marker(spec) {
64
    if (typeof spec == "string") {
65
      var elt = document.createElement("div");
66
      elt.className = spec + " CodeMirror-guttermarker-subtle";
67
      return elt;
68
    } else {
69
      return spec.cloneNode(true);
70
    }
71
  }
72

73
  function updateFoldInfo(cm, from, to) {
74
    var opts = cm.state.foldGutter.options, cur = from - 1;
75
    var minSize = cm.foldOption(opts, "minFoldSize");
76
    var func = cm.foldOption(opts, "rangeFinder");
77
    // we can reuse the built-in indicator element if its className matches the new state
78
    var clsFolded = typeof opts.indicatorFolded == "string" && classTest(opts.indicatorFolded);
79
    var clsOpen = typeof opts.indicatorOpen == "string" && classTest(opts.indicatorOpen);
80
    cm.eachLine(from, to, function(line) {
81
      ++cur;
82
      var mark = null;
83
      var old = line.gutterMarkers;
84
      if (old) old = old[opts.gutter];
85
      if (isFolded(cm, cur)) {
86
        if (clsFolded && old && clsFolded.test(old.className)) return;
87
        mark = marker(opts.indicatorFolded);
88
      } else {
89
        var pos = Pos(cur, 0);
90
        var range = func && func(cm, pos);
91
        if (range && range.to.line - range.from.line >= minSize) {
92
          if (clsOpen && old && clsOpen.test(old.className)) return;
93
          mark = marker(opts.indicatorOpen);
94
        }
95
      }
96
      if (!mark && !old) return;
97
      cm.setGutterMarker(line, opts.gutter, mark);
98
    });
99
  }
100

101
  // copied from CodeMirror/src/util/dom.js
102
  function classTest(cls) { return new RegExp("(^|\\s)" + cls + "(?:$|\\s)\\s*") }
103

104
  function updateInViewport(cm) {
105
    var vp = cm.getViewport(), state = cm.state.foldGutter;
106
    if (!state) return;
107
    cm.operation(function() {
108
      updateFoldInfo(cm, vp.from, vp.to);
109
    });
110
    state.from = vp.from; state.to = vp.to;
111
  }
112

113
  function onGutterClick(cm, line, gutter) {
114
    var state = cm.state.foldGutter;
115
    if (!state) return;
116
    var opts = state.options;
117
    if (gutter != opts.gutter) return;
118
    var folded = isFolded(cm, line);
119
    if (folded) folded.clear();
120
    else cm.foldCode(Pos(line, 0), opts);
121
  }
122

123
  function onChange(cm) {
124
    var state = cm.state.foldGutter;
125
    if (!state) return;
126
    var opts = state.options;
127
    state.from = state.to = 0;
128
    clearTimeout(state.changeUpdate);
129
    state.changeUpdate = setTimeout(function() { updateInViewport(cm); }, opts.foldOnChangeTimeSpan || 600);
130
  }
131

132
  function onViewportChange(cm) {
133
    var state = cm.state.foldGutter;
134
    if (!state) return;
135
    var opts = state.options;
136
    clearTimeout(state.changeUpdate);
137
    state.changeUpdate = setTimeout(function() {
138
      var vp = cm.getViewport();
139
      if (state.from == state.to || vp.from - state.to > 20 || state.from - vp.to > 20) {
140
        updateInViewport(cm);
141
      } else {
142
        cm.operation(function() {
143
          if (vp.from < state.from) {
144
            updateFoldInfo(cm, vp.from, state.from);
145
            state.from = vp.from;
146
          }
147
          if (vp.to > state.to) {
148
            updateFoldInfo(cm, state.to, vp.to);
149
            state.to = vp.to;
150
          }
151
        });
152
      }
153
    }, opts.updateViewportTimeSpan || 400);
154
  }
155

156
  function onFold(cm, from) {
157
    var state = cm.state.foldGutter;
158
    if (!state) return;
159
    var line = from.line;
160
    if (line >= state.from && line < state.to)
161
      updateFoldInfo(cm, line, line + 1);
162
  }
163
});
164

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.