@atlaskit/editor-plugin-code-block-advanced 2.1.3 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +25 -0
- package/dist/cjs/nodeviews/codeBlockAdvanced.js +22 -3
- package/dist/cjs/nodeviews/languages/languageMap.js +12 -0
- package/dist/cjs/nodeviews/lazyCodeBlockAdvanced.js +32 -14
- package/dist/cjs/pm-plugins/main.js +14 -0
- package/dist/cjs/pm-plugins/shiftArrowKeyWorkaround.js +55 -0
- package/dist/es2019/nodeviews/codeBlockAdvanced.js +18 -3
- package/dist/es2019/nodeviews/languages/languageMap.js +9 -1
- package/dist/es2019/nodeviews/lazyCodeBlockAdvanced.js +5 -9
- package/dist/es2019/pm-plugins/main.js +14 -0
- package/dist/es2019/pm-plugins/shiftArrowKeyWorkaround.js +61 -0
- package/dist/esm/nodeviews/codeBlockAdvanced.js +22 -3
- package/dist/esm/nodeviews/languages/languageMap.js +11 -1
- package/dist/esm/nodeviews/lazyCodeBlockAdvanced.js +28 -10
- package/dist/esm/pm-plugins/main.js +14 -0
- package/dist/esm/pm-plugins/shiftArrowKeyWorkaround.js +49 -0
- package/dist/types/nodeviews/codeBlockAdvanced.d.ts +3 -2
- package/dist/types/pm-plugins/shiftArrowKeyWorkaround.d.ts +3 -0
- package/dist/types-ts4.5/nodeviews/codeBlockAdvanced.d.ts +3 -2
- package/dist/types-ts4.5/pm-plugins/shiftArrowKeyWorkaround.d.ts +3 -0
- package/package.json +8 -7
- package/src/nodeviews/codeBlockAdvanced.ts +36 -3
- package/src/nodeviews/languages/languageMap.ts +11 -1
- package/src/nodeviews/lazyCodeBlockAdvanced.ts +12 -9
- package/src/pm-plugins/main.ts +17 -0
- package/src/pm-plugins/shiftArrowKeyWorkaround.ts +58 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,30 @@
|
|
|
1
1
|
# @atlaskit/editor-plugin-code-block-advanced
|
|
2
2
|
|
|
3
|
+
## 2.2.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#137683](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/pull-requests/137683)
|
|
8
|
+
[`c1020ef8cdf87`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/c1020ef8cdf87) -
|
|
9
|
+
Adds support for Handlebars syntax highlighting.
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- [#137043](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/pull-requests/137043)
|
|
14
|
+
[`616c9cd4a2c60`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/616c9cd4a2c60) -
|
|
15
|
+
Fix line wrapping and decorations being lost on breakout in advanced codeblocks
|
|
16
|
+
- Updated dependencies
|
|
17
|
+
|
|
18
|
+
## 2.1.4
|
|
19
|
+
|
|
20
|
+
### Patch Changes
|
|
21
|
+
|
|
22
|
+
- [#136263](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/pull-requests/136263)
|
|
23
|
+
[`602e9a7824b0c`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/602e9a7824b0c) -
|
|
24
|
+
Fix editor crashing with advanced code blocks due to infinite codemirror loop with decorations
|
|
25
|
+
when changing breakout.
|
|
26
|
+
- Updated dependencies
|
|
27
|
+
|
|
3
28
|
## 2.1.3
|
|
4
29
|
|
|
5
30
|
### Patch Changes
|
|
@@ -15,6 +15,7 @@ var _state = require("@codemirror/state");
|
|
|
15
15
|
var _view = require("@codemirror/view");
|
|
16
16
|
var _codeBlock = require("@atlaskit/editor-common/code-block");
|
|
17
17
|
var _state2 = require("@atlaskit/editor-prosemirror/state");
|
|
18
|
+
var _view2 = require("@atlaskit/editor-prosemirror/view");
|
|
18
19
|
var _syntaxHighlightingTheme = require("../ui/syntaxHighlightingTheme");
|
|
19
20
|
var _theme = require("../ui/theme");
|
|
20
21
|
var _syncCMWithPM = require("./codemirrorSync/syncCMWithPM");
|
|
@@ -25,7 +26,7 @@ var _prosemirrorDecorations = require("./extensions/prosemirrorDecorations");
|
|
|
25
26
|
var _loader = require("./languages/loader");
|
|
26
27
|
// Based on: https://prosemirror.net/examples/codemirror/
|
|
27
28
|
var CodeBlockAdvancedNodeView = /*#__PURE__*/function () {
|
|
28
|
-
function CodeBlockAdvancedNodeView(node, view, getPos, config) {
|
|
29
|
+
function CodeBlockAdvancedNodeView(node, view, getPos, innerDecorations, config) {
|
|
29
30
|
var _config$api,
|
|
30
31
|
_this = this,
|
|
31
32
|
_config$api2,
|
|
@@ -86,11 +87,17 @@ var CodeBlockAdvancedNodeView = /*#__PURE__*/function () {
|
|
|
86
87
|
// inner editor
|
|
87
88
|
this.updating = false;
|
|
88
89
|
this.updateLanguage();
|
|
90
|
+
this.updateWordWrap(node);
|
|
91
|
+
this.updateProseMirrorDecorations(innerDecorations);
|
|
89
92
|
}
|
|
90
93
|
return (0, _createClass2.default)(CodeBlockAdvancedNodeView, [{
|
|
91
94
|
key: "destroy",
|
|
92
95
|
value: function destroy() {
|
|
93
96
|
var _this$cleanupDisabled;
|
|
97
|
+
// ED-27428: CodeMirror gets into an infinite loop as it detects mutations on removed
|
|
98
|
+
// decorations. When we change the breakout we destroy the node and cleanup these decorations from
|
|
99
|
+
// codemirror
|
|
100
|
+
this.clearProseMirrorDecorations();
|
|
94
101
|
(_this$cleanupDisabled = this.cleanupDisabledState) === null || _this$cleanupDisabled === void 0 || _this$cleanupDisabled.call(this);
|
|
95
102
|
}
|
|
96
103
|
}, {
|
|
@@ -202,6 +209,18 @@ var CodeBlockAdvancedNodeView = /*#__PURE__*/function () {
|
|
|
202
209
|
});
|
|
203
210
|
this.updating = false;
|
|
204
211
|
}
|
|
212
|
+
}, {
|
|
213
|
+
key: "clearProseMirrorDecorations",
|
|
214
|
+
value: function clearProseMirrorDecorations() {
|
|
215
|
+
this.updating = true;
|
|
216
|
+
var computedFacet = this.pmFacet.compute([], function () {
|
|
217
|
+
return _view2.DecorationSet.empty;
|
|
218
|
+
});
|
|
219
|
+
this.cm.dispatch({
|
|
220
|
+
effects: this.pmDecorationsCompartment.reconfigure(computedFacet)
|
|
221
|
+
});
|
|
222
|
+
this.updating = false;
|
|
223
|
+
}
|
|
205
224
|
}, {
|
|
206
225
|
key: "stopEvent",
|
|
207
226
|
value: function stopEvent(e) {
|
|
@@ -234,7 +253,7 @@ var CodeBlockAdvancedNodeView = /*#__PURE__*/function () {
|
|
|
234
253
|
}]);
|
|
235
254
|
}();
|
|
236
255
|
var getCodeBlockAdvancedNodeView = exports.getCodeBlockAdvancedNodeView = function getCodeBlockAdvancedNodeView(props) {
|
|
237
|
-
return function (node, view, getPos) {
|
|
238
|
-
return new CodeBlockAdvancedNodeView(node, view, getPos, props);
|
|
256
|
+
return function (node, view, getPos, innerDecorations) {
|
|
257
|
+
return new CodeBlockAdvancedNodeView(node, view, getPos, innerDecorations, props);
|
|
239
258
|
};
|
|
240
259
|
};
|
|
@@ -68,6 +68,18 @@ var mapLanguageToCodeMirror = exports.mapLanguageToCodeMirror = function mapLang
|
|
|
68
68
|
return _languageData.languages.find(function (l) {
|
|
69
69
|
return l.name === 'VB.NET';
|
|
70
70
|
});
|
|
71
|
+
case 'handlebars':
|
|
72
|
+
return _language.LanguageDescription.of({
|
|
73
|
+
name: 'Handlebars',
|
|
74
|
+
load: function load() {
|
|
75
|
+
return Promise.resolve().then(function () {
|
|
76
|
+
return _interopRequireWildcard(require( /* webpackChunkName: "@atlaskit-internal_@atlaskit/editor-plugin-code-block-advanced-lang-handlebars" */
|
|
77
|
+
'@xiechao/codemirror-lang-handlebars'));
|
|
78
|
+
}).then(function (m) {
|
|
79
|
+
return new _language.LanguageSupport(m.handlebarsLanguage);
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
});
|
|
71
83
|
case 'elixir':
|
|
72
84
|
return _language.LanguageDescription.of({
|
|
73
85
|
name: 'Elixir',
|
|
@@ -1,29 +1,47 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
3
|
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
+
var _typeof = require("@babel/runtime/helpers/typeof");
|
|
4
5
|
Object.defineProperty(exports, "__esModule", {
|
|
5
6
|
value: true
|
|
6
7
|
});
|
|
7
8
|
exports.lazyCodeBlockView = void 0;
|
|
8
|
-
var
|
|
9
|
+
var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
|
|
10
|
+
var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
|
|
9
11
|
var _lazyNodeView = require("@atlaskit/editor-common/lazy-node-view");
|
|
10
12
|
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(e) { return e ? t : r; })(e); }
|
|
11
|
-
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != (
|
|
13
|
+
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != _typeof(e) && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
|
12
14
|
var lazyCodeBlockView = exports.lazyCodeBlockView = function lazyCodeBlockView(props) {
|
|
13
15
|
return (0, _lazyNodeView.withLazyLoading)({
|
|
14
16
|
nodeName: 'codeBlock',
|
|
15
17
|
getNodeViewOptions: function getNodeViewOptions() {},
|
|
16
|
-
loader: function
|
|
17
|
-
var
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
18
|
+
loader: function () {
|
|
19
|
+
var _loader = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee() {
|
|
20
|
+
var _yield$import, getCodeBlockAdvancedNodeView;
|
|
21
|
+
return _regenerator.default.wrap(function _callee$(_context) {
|
|
22
|
+
while (1) switch (_context.prev = _context.next) {
|
|
23
|
+
case 0:
|
|
24
|
+
_context.next = 2;
|
|
25
|
+
return Promise.resolve().then(function () {
|
|
26
|
+
return _interopRequireWildcard(require( /* webpackChunkName: "@atlaskit-internal_editor-plugin-code-block-advanced-nodeview" */
|
|
27
|
+
'./codeBlockAdvanced'));
|
|
28
|
+
});
|
|
29
|
+
case 2:
|
|
30
|
+
_yield$import = _context.sent;
|
|
31
|
+
getCodeBlockAdvancedNodeView = _yield$import.getCodeBlockAdvancedNodeView;
|
|
32
|
+
return _context.abrupt("return", function (node, view, getPos, _decs, _nodeViewOptions, innerDecorations) {
|
|
33
|
+
return getCodeBlockAdvancedNodeView(props)(node, view, getPos, innerDecorations);
|
|
34
|
+
});
|
|
35
|
+
case 5:
|
|
36
|
+
case "end":
|
|
37
|
+
return _context.stop();
|
|
38
|
+
}
|
|
39
|
+
}, _callee);
|
|
40
|
+
}));
|
|
41
|
+
function loader() {
|
|
42
|
+
return _loader.apply(this, arguments);
|
|
43
|
+
}
|
|
44
|
+
return loader;
|
|
45
|
+
}()
|
|
28
46
|
});
|
|
29
47
|
};
|
|
@@ -6,11 +6,25 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
6
6
|
exports.createPlugin = void 0;
|
|
7
7
|
var _safePlugin = require("@atlaskit/editor-common/safe-plugin");
|
|
8
8
|
var _lazyCodeBlockAdvanced = require("../nodeviews/lazyCodeBlockAdvanced");
|
|
9
|
+
var _shiftArrowKeyWorkaround = require("./shiftArrowKeyWorkaround");
|
|
9
10
|
var createPlugin = exports.createPlugin = function createPlugin(props) {
|
|
10
11
|
return new _safePlugin.SafePlugin({
|
|
11
12
|
props: {
|
|
12
13
|
nodeViews: {
|
|
13
14
|
codeBlock: (0, _lazyCodeBlockAdvanced.lazyCodeBlockView)(props)
|
|
15
|
+
},
|
|
16
|
+
// Custom selection behaviour to fix issues with codeblocks with Shift + Arrow{Up || Down}
|
|
17
|
+
// These issues are also present in the prosemirror codemirror example and @marijnh suggests to
|
|
18
|
+
// use custom event handlers: https://github.com/ProseMirror/website/issues/83
|
|
19
|
+
handleKeyDown: function handleKeyDown(view, event) {
|
|
20
|
+
if (!(event instanceof KeyboardEvent)) {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
if (event.key === 'ArrowUp' && event.shiftKey) {
|
|
24
|
+
return (0, _shiftArrowKeyWorkaround.shiftArrowUpWorkaround)(view, event);
|
|
25
|
+
} else if (event.key === 'ArrowDown' && event.shiftKey) {
|
|
26
|
+
return (0, _shiftArrowKeyWorkaround.shiftArrowDownWorkaround)(view, event);
|
|
27
|
+
}
|
|
14
28
|
}
|
|
15
29
|
}
|
|
16
30
|
});
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.shiftArrowUpWorkaround = exports.shiftArrowDownWorkaround = void 0;
|
|
7
|
+
var _state = require("@atlaskit/editor-prosemirror/state");
|
|
8
|
+
var shiftArrowUpWorkaround = exports.shiftArrowUpWorkaround = function shiftArrowUpWorkaround(view, event) {
|
|
9
|
+
var _doc$resolve$nodeBefo;
|
|
10
|
+
var _view$state = view.state,
|
|
11
|
+
doc = _view$state.doc,
|
|
12
|
+
_view$state$selection = _view$state.selection,
|
|
13
|
+
$head = _view$state$selection.$head,
|
|
14
|
+
$anchor = _view$state$selection.$anchor,
|
|
15
|
+
tr = _view$state.tr,
|
|
16
|
+
codeBlock = _view$state.schema.nodes.codeBlock;
|
|
17
|
+
|
|
18
|
+
// Position we want to check (directly after our current position)
|
|
19
|
+
var pos = Math.max($head.pos - 1, 1);
|
|
20
|
+
var isNodeBefore = ((_doc$resolve$nodeBefo = doc.resolve(pos).nodeBefore) === null || _doc$resolve$nodeBefo === void 0 ? void 0 : _doc$resolve$nodeBefo.type) === codeBlock;
|
|
21
|
+
var maybeProblematicNode = isNodeBefore ? doc.resolve(pos).nodeBefore : doc.resolve(pos).node();
|
|
22
|
+
if ((maybeProblematicNode === null || maybeProblematicNode === void 0 ? void 0 : maybeProblematicNode.type) === codeBlock) {
|
|
23
|
+
var nodeSize = maybeProblematicNode.nodeSize;
|
|
24
|
+
var startPos = isNodeBefore ? pos : $head.pos;
|
|
25
|
+
tr.setSelection(_state.TextSelection.create(doc, $anchor.pos, Math.max(startPos - nodeSize, 0)));
|
|
26
|
+
view.dispatch(tr);
|
|
27
|
+
event.preventDefault();
|
|
28
|
+
return true;
|
|
29
|
+
}
|
|
30
|
+
return false;
|
|
31
|
+
};
|
|
32
|
+
var shiftArrowDownWorkaround = exports.shiftArrowDownWorkaround = function shiftArrowDownWorkaround(view, event) {
|
|
33
|
+
var _doc$resolve$nodeAfte;
|
|
34
|
+
var _view$state2 = view.state,
|
|
35
|
+
doc = _view$state2.doc,
|
|
36
|
+
_view$state2$selectio = _view$state2.selection,
|
|
37
|
+
$head = _view$state2$selectio.$head,
|
|
38
|
+
$anchor = _view$state2$selectio.$anchor,
|
|
39
|
+
tr = _view$state2.tr,
|
|
40
|
+
codeBlock = _view$state2.schema.nodes.codeBlock;
|
|
41
|
+
|
|
42
|
+
// Position we want to check (directly after our current position)
|
|
43
|
+
var pos = $head.pos + 1;
|
|
44
|
+
var isNodeAfter = ((_doc$resolve$nodeAfte = doc.resolve(pos).nodeAfter) === null || _doc$resolve$nodeAfte === void 0 ? void 0 : _doc$resolve$nodeAfte.type) === codeBlock;
|
|
45
|
+
var maybeProblematicNode = isNodeAfter ? doc.resolve(pos).nodeAfter : doc.resolve(pos).node();
|
|
46
|
+
if ((maybeProblematicNode === null || maybeProblematicNode === void 0 ? void 0 : maybeProblematicNode.type) === codeBlock) {
|
|
47
|
+
var nodeSize = maybeProblematicNode.nodeSize;
|
|
48
|
+
var startPos = isNodeAfter ? pos : $head.pos;
|
|
49
|
+
tr.setSelection(_state.TextSelection.create(doc, $anchor.pos, Math.min(startPos + nodeSize, doc.content.size)));
|
|
50
|
+
view.dispatch(tr);
|
|
51
|
+
event.preventDefault();
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
return false;
|
|
55
|
+
};
|
|
@@ -5,6 +5,7 @@ import { Compartment, EditorSelection, Facet } from '@codemirror/state';
|
|
|
5
5
|
import { EditorView as CodeMirror, lineNumbers, gutters } from '@codemirror/view';
|
|
6
6
|
import { isCodeBlockWordWrapEnabled } from '@atlaskit/editor-common/code-block';
|
|
7
7
|
import { NodeSelection } from '@atlaskit/editor-prosemirror/state';
|
|
8
|
+
import { DecorationSet } from '@atlaskit/editor-prosemirror/view';
|
|
8
9
|
import { highlightStyle } from '../ui/syntaxHighlightingTheme';
|
|
9
10
|
import { cmTheme } from '../ui/theme';
|
|
10
11
|
import { syncCMWithPM } from './codemirrorSync/syncCMWithPM';
|
|
@@ -15,7 +16,7 @@ import { prosemirrorDecorationPlugin } from './extensions/prosemirrorDecorations
|
|
|
15
16
|
import { LanguageLoader } from './languages/loader';
|
|
16
17
|
// Based on: https://prosemirror.net/examples/codemirror/
|
|
17
18
|
class CodeBlockAdvancedNodeView {
|
|
18
|
-
constructor(node, view, getPos, config) {
|
|
19
|
+
constructor(node, view, getPos, innerDecorations, config) {
|
|
19
20
|
var _config$api, _config$api$selection, _config$api2, _config$api2$editorDi, _config$api3;
|
|
20
21
|
_defineProperty(this, "lineWrappingCompartment", new Compartment());
|
|
21
22
|
_defineProperty(this, "languageCompartment", new Compartment());
|
|
@@ -66,9 +67,15 @@ class CodeBlockAdvancedNodeView {
|
|
|
66
67
|
// inner editor
|
|
67
68
|
this.updating = false;
|
|
68
69
|
this.updateLanguage();
|
|
70
|
+
this.updateWordWrap(node);
|
|
71
|
+
this.updateProseMirrorDecorations(innerDecorations);
|
|
69
72
|
}
|
|
70
73
|
destroy() {
|
|
71
74
|
var _this$cleanupDisabled;
|
|
75
|
+
// ED-27428: CodeMirror gets into an infinite loop as it detects mutations on removed
|
|
76
|
+
// decorations. When we change the breakout we destroy the node and cleanup these decorations from
|
|
77
|
+
// codemirror
|
|
78
|
+
this.clearProseMirrorDecorations();
|
|
72
79
|
(_this$cleanupDisabled = this.cleanupDisabledState) === null || _this$cleanupDisabled === void 0 ? void 0 : _this$cleanupDisabled.call(this);
|
|
73
80
|
}
|
|
74
81
|
forwardUpdate(update) {
|
|
@@ -161,6 +168,14 @@ class CodeBlockAdvancedNodeView {
|
|
|
161
168
|
});
|
|
162
169
|
this.updating = false;
|
|
163
170
|
}
|
|
171
|
+
clearProseMirrorDecorations() {
|
|
172
|
+
this.updating = true;
|
|
173
|
+
const computedFacet = this.pmFacet.compute([], () => DecorationSet.empty);
|
|
174
|
+
this.cm.dispatch({
|
|
175
|
+
effects: this.pmDecorationsCompartment.reconfigure(computedFacet)
|
|
176
|
+
});
|
|
177
|
+
this.updating = false;
|
|
178
|
+
}
|
|
164
179
|
stopEvent(e) {
|
|
165
180
|
var _this$getPos5;
|
|
166
181
|
if (e instanceof MouseEvent && e.type === 'mousedown') {
|
|
@@ -188,6 +203,6 @@ class CodeBlockAdvancedNodeView {
|
|
|
188
203
|
return true;
|
|
189
204
|
}
|
|
190
205
|
}
|
|
191
|
-
export const getCodeBlockAdvancedNodeView = props => (node, view, getPos) => {
|
|
192
|
-
return new CodeBlockAdvancedNodeView(node, view, getPos, props);
|
|
206
|
+
export const getCodeBlockAdvancedNodeView = props => (node, view, getPos, innerDecorations) => {
|
|
207
|
+
return new CodeBlockAdvancedNodeView(node, view, getPos, innerDecorations, props);
|
|
193
208
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { LanguageDescription } from '@codemirror/language';
|
|
1
|
+
import { LanguageDescription, LanguageSupport } from '@codemirror/language';
|
|
2
2
|
import { languages } from '@codemirror/language-data';
|
|
3
3
|
// getLanguageIdentifier defines `language.alias[0]`
|
|
4
4
|
export const mapLanguageToCodeMirror = language => {
|
|
@@ -58,6 +58,14 @@ export const mapLanguageToCodeMirror = language => {
|
|
|
58
58
|
return languages.find(l => {
|
|
59
59
|
return l.name === 'VB.NET';
|
|
60
60
|
});
|
|
61
|
+
case 'handlebars':
|
|
62
|
+
return LanguageDescription.of({
|
|
63
|
+
name: 'Handlebars',
|
|
64
|
+
load() {
|
|
65
|
+
return import( /* webpackChunkName: "@atlaskit-internal_@atlaskit/editor-plugin-code-block-advanced-lang-handlebars" */
|
|
66
|
+
'@xiechao/codemirror-lang-handlebars').then(m => new LanguageSupport(m.handlebarsLanguage));
|
|
67
|
+
}
|
|
68
|
+
});
|
|
61
69
|
case 'elixir':
|
|
62
70
|
return LanguageDescription.of({
|
|
63
71
|
name: 'Elixir',
|
|
@@ -3,16 +3,12 @@ export const lazyCodeBlockView = props => {
|
|
|
3
3
|
return withLazyLoading({
|
|
4
4
|
nodeName: 'codeBlock',
|
|
5
5
|
getNodeViewOptions: () => {},
|
|
6
|
-
loader: () => {
|
|
7
|
-
const
|
|
8
|
-
'./codeBlockAdvanced').then(({
|
|
6
|
+
loader: async () => {
|
|
7
|
+
const {
|
|
9
8
|
getCodeBlockAdvancedNodeView
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
};
|
|
14
|
-
});
|
|
15
|
-
return result;
|
|
9
|
+
} = await import( /* webpackChunkName: "@atlaskit-internal_editor-plugin-code-block-advanced-nodeview" */
|
|
10
|
+
'./codeBlockAdvanced');
|
|
11
|
+
return (node, view, getPos, _decs, _nodeViewOptions, innerDecorations) => getCodeBlockAdvancedNodeView(props)(node, view, getPos, innerDecorations);
|
|
16
12
|
}
|
|
17
13
|
});
|
|
18
14
|
};
|
|
@@ -1,10 +1,24 @@
|
|
|
1
1
|
import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
|
|
2
2
|
import { lazyCodeBlockView } from '../nodeviews/lazyCodeBlockAdvanced';
|
|
3
|
+
import { shiftArrowDownWorkaround, shiftArrowUpWorkaround } from './shiftArrowKeyWorkaround';
|
|
3
4
|
export const createPlugin = props => {
|
|
4
5
|
return new SafePlugin({
|
|
5
6
|
props: {
|
|
6
7
|
nodeViews: {
|
|
7
8
|
codeBlock: lazyCodeBlockView(props)
|
|
9
|
+
},
|
|
10
|
+
// Custom selection behaviour to fix issues with codeblocks with Shift + Arrow{Up || Down}
|
|
11
|
+
// These issues are also present in the prosemirror codemirror example and @marijnh suggests to
|
|
12
|
+
// use custom event handlers: https://github.com/ProseMirror/website/issues/83
|
|
13
|
+
handleKeyDown(view, event) {
|
|
14
|
+
if (!(event instanceof KeyboardEvent)) {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
if (event.key === 'ArrowUp' && event.shiftKey) {
|
|
18
|
+
return shiftArrowUpWorkaround(view, event);
|
|
19
|
+
} else if (event.key === 'ArrowDown' && event.shiftKey) {
|
|
20
|
+
return shiftArrowDownWorkaround(view, event);
|
|
21
|
+
}
|
|
8
22
|
}
|
|
9
23
|
}
|
|
10
24
|
});
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { TextSelection } from '@atlaskit/editor-prosemirror/state';
|
|
2
|
+
export const shiftArrowUpWorkaround = (view, event) => {
|
|
3
|
+
var _doc$resolve$nodeBefo;
|
|
4
|
+
const {
|
|
5
|
+
doc,
|
|
6
|
+
selection: {
|
|
7
|
+
$head,
|
|
8
|
+
$anchor
|
|
9
|
+
},
|
|
10
|
+
tr,
|
|
11
|
+
schema: {
|
|
12
|
+
nodes: {
|
|
13
|
+
codeBlock
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
} = view.state;
|
|
17
|
+
|
|
18
|
+
// Position we want to check (directly after our current position)
|
|
19
|
+
const pos = Math.max($head.pos - 1, 1);
|
|
20
|
+
const isNodeBefore = ((_doc$resolve$nodeBefo = doc.resolve(pos).nodeBefore) === null || _doc$resolve$nodeBefo === void 0 ? void 0 : _doc$resolve$nodeBefo.type) === codeBlock;
|
|
21
|
+
const maybeProblematicNode = isNodeBefore ? doc.resolve(pos).nodeBefore : doc.resolve(pos).node();
|
|
22
|
+
if ((maybeProblematicNode === null || maybeProblematicNode === void 0 ? void 0 : maybeProblematicNode.type) === codeBlock) {
|
|
23
|
+
const nodeSize = maybeProblematicNode.nodeSize;
|
|
24
|
+
const startPos = isNodeBefore ? pos : $head.pos;
|
|
25
|
+
tr.setSelection(TextSelection.create(doc, $anchor.pos, Math.max(startPos - nodeSize, 0)));
|
|
26
|
+
view.dispatch(tr);
|
|
27
|
+
event.preventDefault();
|
|
28
|
+
return true;
|
|
29
|
+
}
|
|
30
|
+
return false;
|
|
31
|
+
};
|
|
32
|
+
export const shiftArrowDownWorkaround = (view, event) => {
|
|
33
|
+
var _doc$resolve$nodeAfte;
|
|
34
|
+
const {
|
|
35
|
+
doc,
|
|
36
|
+
selection: {
|
|
37
|
+
$head,
|
|
38
|
+
$anchor
|
|
39
|
+
},
|
|
40
|
+
tr,
|
|
41
|
+
schema: {
|
|
42
|
+
nodes: {
|
|
43
|
+
codeBlock
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
} = view.state;
|
|
47
|
+
|
|
48
|
+
// Position we want to check (directly after our current position)
|
|
49
|
+
const pos = $head.pos + 1;
|
|
50
|
+
const isNodeAfter = ((_doc$resolve$nodeAfte = doc.resolve(pos).nodeAfter) === null || _doc$resolve$nodeAfte === void 0 ? void 0 : _doc$resolve$nodeAfte.type) === codeBlock;
|
|
51
|
+
const maybeProblematicNode = isNodeAfter ? doc.resolve(pos).nodeAfter : doc.resolve(pos).node();
|
|
52
|
+
if ((maybeProblematicNode === null || maybeProblematicNode === void 0 ? void 0 : maybeProblematicNode.type) === codeBlock) {
|
|
53
|
+
const nodeSize = maybeProblematicNode.nodeSize;
|
|
54
|
+
const startPos = isNodeAfter ? pos : $head.pos;
|
|
55
|
+
tr.setSelection(TextSelection.create(doc, $anchor.pos, Math.min(startPos + nodeSize, doc.content.size)));
|
|
56
|
+
view.dispatch(tr);
|
|
57
|
+
event.preventDefault();
|
|
58
|
+
return true;
|
|
59
|
+
}
|
|
60
|
+
return false;
|
|
61
|
+
};
|
|
@@ -8,6 +8,7 @@ import { Compartment, EditorSelection, Facet } from '@codemirror/state';
|
|
|
8
8
|
import { EditorView as CodeMirror, lineNumbers, gutters } from '@codemirror/view';
|
|
9
9
|
import { isCodeBlockWordWrapEnabled } from '@atlaskit/editor-common/code-block';
|
|
10
10
|
import { NodeSelection } from '@atlaskit/editor-prosemirror/state';
|
|
11
|
+
import { DecorationSet } from '@atlaskit/editor-prosemirror/view';
|
|
11
12
|
import { highlightStyle } from '../ui/syntaxHighlightingTheme';
|
|
12
13
|
import { cmTheme } from '../ui/theme';
|
|
13
14
|
import { syncCMWithPM } from './codemirrorSync/syncCMWithPM';
|
|
@@ -18,7 +19,7 @@ import { prosemirrorDecorationPlugin } from './extensions/prosemirrorDecorations
|
|
|
18
19
|
import { LanguageLoader } from './languages/loader';
|
|
19
20
|
// Based on: https://prosemirror.net/examples/codemirror/
|
|
20
21
|
var CodeBlockAdvancedNodeView = /*#__PURE__*/function () {
|
|
21
|
-
function CodeBlockAdvancedNodeView(node, view, getPos, config) {
|
|
22
|
+
function CodeBlockAdvancedNodeView(node, view, getPos, innerDecorations, config) {
|
|
22
23
|
var _config$api,
|
|
23
24
|
_this = this,
|
|
24
25
|
_config$api2,
|
|
@@ -79,11 +80,17 @@ var CodeBlockAdvancedNodeView = /*#__PURE__*/function () {
|
|
|
79
80
|
// inner editor
|
|
80
81
|
this.updating = false;
|
|
81
82
|
this.updateLanguage();
|
|
83
|
+
this.updateWordWrap(node);
|
|
84
|
+
this.updateProseMirrorDecorations(innerDecorations);
|
|
82
85
|
}
|
|
83
86
|
return _createClass(CodeBlockAdvancedNodeView, [{
|
|
84
87
|
key: "destroy",
|
|
85
88
|
value: function destroy() {
|
|
86
89
|
var _this$cleanupDisabled;
|
|
90
|
+
// ED-27428: CodeMirror gets into an infinite loop as it detects mutations on removed
|
|
91
|
+
// decorations. When we change the breakout we destroy the node and cleanup these decorations from
|
|
92
|
+
// codemirror
|
|
93
|
+
this.clearProseMirrorDecorations();
|
|
87
94
|
(_this$cleanupDisabled = this.cleanupDisabledState) === null || _this$cleanupDisabled === void 0 || _this$cleanupDisabled.call(this);
|
|
88
95
|
}
|
|
89
96
|
}, {
|
|
@@ -195,6 +202,18 @@ var CodeBlockAdvancedNodeView = /*#__PURE__*/function () {
|
|
|
195
202
|
});
|
|
196
203
|
this.updating = false;
|
|
197
204
|
}
|
|
205
|
+
}, {
|
|
206
|
+
key: "clearProseMirrorDecorations",
|
|
207
|
+
value: function clearProseMirrorDecorations() {
|
|
208
|
+
this.updating = true;
|
|
209
|
+
var computedFacet = this.pmFacet.compute([], function () {
|
|
210
|
+
return DecorationSet.empty;
|
|
211
|
+
});
|
|
212
|
+
this.cm.dispatch({
|
|
213
|
+
effects: this.pmDecorationsCompartment.reconfigure(computedFacet)
|
|
214
|
+
});
|
|
215
|
+
this.updating = false;
|
|
216
|
+
}
|
|
198
217
|
}, {
|
|
199
218
|
key: "stopEvent",
|
|
200
219
|
value: function stopEvent(e) {
|
|
@@ -227,7 +246,7 @@ var CodeBlockAdvancedNodeView = /*#__PURE__*/function () {
|
|
|
227
246
|
}]);
|
|
228
247
|
}();
|
|
229
248
|
export var getCodeBlockAdvancedNodeView = function getCodeBlockAdvancedNodeView(props) {
|
|
230
|
-
return function (node, view, getPos) {
|
|
231
|
-
return new CodeBlockAdvancedNodeView(node, view, getPos, props);
|
|
249
|
+
return function (node, view, getPos, innerDecorations) {
|
|
250
|
+
return new CodeBlockAdvancedNodeView(node, view, getPos, innerDecorations, props);
|
|
232
251
|
};
|
|
233
252
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { LanguageDescription } from '@codemirror/language';
|
|
1
|
+
import { LanguageDescription, LanguageSupport } from '@codemirror/language';
|
|
2
2
|
import { languages } from '@codemirror/language-data';
|
|
3
3
|
// getLanguageIdentifier defines `language.alias[0]`
|
|
4
4
|
export var mapLanguageToCodeMirror = function mapLanguageToCodeMirror(language) {
|
|
@@ -58,6 +58,16 @@ export var mapLanguageToCodeMirror = function mapLanguageToCodeMirror(language)
|
|
|
58
58
|
return languages.find(function (l) {
|
|
59
59
|
return l.name === 'VB.NET';
|
|
60
60
|
});
|
|
61
|
+
case 'handlebars':
|
|
62
|
+
return LanguageDescription.of({
|
|
63
|
+
name: 'Handlebars',
|
|
64
|
+
load: function load() {
|
|
65
|
+
return import( /* webpackChunkName: "@atlaskit-internal_@atlaskit/editor-plugin-code-block-advanced-lang-handlebars" */
|
|
66
|
+
'@xiechao/codemirror-lang-handlebars').then(function (m) {
|
|
67
|
+
return new LanguageSupport(m.handlebarsLanguage);
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
});
|
|
61
71
|
case 'elixir':
|
|
62
72
|
return LanguageDescription.of({
|
|
63
73
|
name: 'Elixir',
|
|
@@ -1,17 +1,35 @@
|
|
|
1
|
+
import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
|
|
2
|
+
import _regeneratorRuntime from "@babel/runtime/regenerator";
|
|
1
3
|
import { withLazyLoading } from '@atlaskit/editor-common/lazy-node-view';
|
|
2
4
|
export var lazyCodeBlockView = function lazyCodeBlockView(props) {
|
|
3
5
|
return withLazyLoading({
|
|
4
6
|
nodeName: 'codeBlock',
|
|
5
7
|
getNodeViewOptions: function getNodeViewOptions() {},
|
|
6
|
-
loader: function
|
|
7
|
-
var
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
8
|
+
loader: function () {
|
|
9
|
+
var _loader = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
|
|
10
|
+
var _yield$import, getCodeBlockAdvancedNodeView;
|
|
11
|
+
return _regeneratorRuntime.wrap(function _callee$(_context) {
|
|
12
|
+
while (1) switch (_context.prev = _context.next) {
|
|
13
|
+
case 0:
|
|
14
|
+
_context.next = 2;
|
|
15
|
+
return import( /* webpackChunkName: "@atlaskit-internal_editor-plugin-code-block-advanced-nodeview" */
|
|
16
|
+
'./codeBlockAdvanced');
|
|
17
|
+
case 2:
|
|
18
|
+
_yield$import = _context.sent;
|
|
19
|
+
getCodeBlockAdvancedNodeView = _yield$import.getCodeBlockAdvancedNodeView;
|
|
20
|
+
return _context.abrupt("return", function (node, view, getPos, _decs, _nodeViewOptions, innerDecorations) {
|
|
21
|
+
return getCodeBlockAdvancedNodeView(props)(node, view, getPos, innerDecorations);
|
|
22
|
+
});
|
|
23
|
+
case 5:
|
|
24
|
+
case "end":
|
|
25
|
+
return _context.stop();
|
|
26
|
+
}
|
|
27
|
+
}, _callee);
|
|
28
|
+
}));
|
|
29
|
+
function loader() {
|
|
30
|
+
return _loader.apply(this, arguments);
|
|
31
|
+
}
|
|
32
|
+
return loader;
|
|
33
|
+
}()
|
|
16
34
|
});
|
|
17
35
|
};
|
|
@@ -1,10 +1,24 @@
|
|
|
1
1
|
import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
|
|
2
2
|
import { lazyCodeBlockView } from '../nodeviews/lazyCodeBlockAdvanced';
|
|
3
|
+
import { shiftArrowDownWorkaround, shiftArrowUpWorkaround } from './shiftArrowKeyWorkaround';
|
|
3
4
|
export var createPlugin = function createPlugin(props) {
|
|
4
5
|
return new SafePlugin({
|
|
5
6
|
props: {
|
|
6
7
|
nodeViews: {
|
|
7
8
|
codeBlock: lazyCodeBlockView(props)
|
|
9
|
+
},
|
|
10
|
+
// Custom selection behaviour to fix issues with codeblocks with Shift + Arrow{Up || Down}
|
|
11
|
+
// These issues are also present in the prosemirror codemirror example and @marijnh suggests to
|
|
12
|
+
// use custom event handlers: https://github.com/ProseMirror/website/issues/83
|
|
13
|
+
handleKeyDown: function handleKeyDown(view, event) {
|
|
14
|
+
if (!(event instanceof KeyboardEvent)) {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
if (event.key === 'ArrowUp' && event.shiftKey) {
|
|
18
|
+
return shiftArrowUpWorkaround(view, event);
|
|
19
|
+
} else if (event.key === 'ArrowDown' && event.shiftKey) {
|
|
20
|
+
return shiftArrowDownWorkaround(view, event);
|
|
21
|
+
}
|
|
8
22
|
}
|
|
9
23
|
}
|
|
10
24
|
});
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { TextSelection } from '@atlaskit/editor-prosemirror/state';
|
|
2
|
+
export var shiftArrowUpWorkaround = function shiftArrowUpWorkaround(view, event) {
|
|
3
|
+
var _doc$resolve$nodeBefo;
|
|
4
|
+
var _view$state = view.state,
|
|
5
|
+
doc = _view$state.doc,
|
|
6
|
+
_view$state$selection = _view$state.selection,
|
|
7
|
+
$head = _view$state$selection.$head,
|
|
8
|
+
$anchor = _view$state$selection.$anchor,
|
|
9
|
+
tr = _view$state.tr,
|
|
10
|
+
codeBlock = _view$state.schema.nodes.codeBlock;
|
|
11
|
+
|
|
12
|
+
// Position we want to check (directly after our current position)
|
|
13
|
+
var pos = Math.max($head.pos - 1, 1);
|
|
14
|
+
var isNodeBefore = ((_doc$resolve$nodeBefo = doc.resolve(pos).nodeBefore) === null || _doc$resolve$nodeBefo === void 0 ? void 0 : _doc$resolve$nodeBefo.type) === codeBlock;
|
|
15
|
+
var maybeProblematicNode = isNodeBefore ? doc.resolve(pos).nodeBefore : doc.resolve(pos).node();
|
|
16
|
+
if ((maybeProblematicNode === null || maybeProblematicNode === void 0 ? void 0 : maybeProblematicNode.type) === codeBlock) {
|
|
17
|
+
var nodeSize = maybeProblematicNode.nodeSize;
|
|
18
|
+
var startPos = isNodeBefore ? pos : $head.pos;
|
|
19
|
+
tr.setSelection(TextSelection.create(doc, $anchor.pos, Math.max(startPos - nodeSize, 0)));
|
|
20
|
+
view.dispatch(tr);
|
|
21
|
+
event.preventDefault();
|
|
22
|
+
return true;
|
|
23
|
+
}
|
|
24
|
+
return false;
|
|
25
|
+
};
|
|
26
|
+
export var shiftArrowDownWorkaround = function shiftArrowDownWorkaround(view, event) {
|
|
27
|
+
var _doc$resolve$nodeAfte;
|
|
28
|
+
var _view$state2 = view.state,
|
|
29
|
+
doc = _view$state2.doc,
|
|
30
|
+
_view$state2$selectio = _view$state2.selection,
|
|
31
|
+
$head = _view$state2$selectio.$head,
|
|
32
|
+
$anchor = _view$state2$selectio.$anchor,
|
|
33
|
+
tr = _view$state2.tr,
|
|
34
|
+
codeBlock = _view$state2.schema.nodes.codeBlock;
|
|
35
|
+
|
|
36
|
+
// Position we want to check (directly after our current position)
|
|
37
|
+
var pos = $head.pos + 1;
|
|
38
|
+
var isNodeAfter = ((_doc$resolve$nodeAfte = doc.resolve(pos).nodeAfter) === null || _doc$resolve$nodeAfte === void 0 ? void 0 : _doc$resolve$nodeAfte.type) === codeBlock;
|
|
39
|
+
var maybeProblematicNode = isNodeAfter ? doc.resolve(pos).nodeAfter : doc.resolve(pos).node();
|
|
40
|
+
if ((maybeProblematicNode === null || maybeProblematicNode === void 0 ? void 0 : maybeProblematicNode.type) === codeBlock) {
|
|
41
|
+
var nodeSize = maybeProblematicNode.nodeSize;
|
|
42
|
+
var startPos = isNodeAfter ? pos : $head.pos;
|
|
43
|
+
tr.setSelection(TextSelection.create(doc, $anchor.pos, Math.min(startPos + nodeSize, doc.content.size)));
|
|
44
|
+
view.dispatch(tr);
|
|
45
|
+
event.preventDefault();
|
|
46
|
+
return true;
|
|
47
|
+
}
|
|
48
|
+
return false;
|
|
49
|
+
};
|
|
@@ -24,7 +24,7 @@ declare class CodeBlockAdvancedNodeView implements NodeView {
|
|
|
24
24
|
private cleanupDisabledState;
|
|
25
25
|
private languageLoader;
|
|
26
26
|
private pmFacet;
|
|
27
|
-
constructor(node: PMNode, view: EditorView, getPos: getPosHandlerNode, config: ConfigProps);
|
|
27
|
+
constructor(node: PMNode, view: EditorView, getPos: getPosHandlerNode, innerDecorations: DecorationSource, config: ConfigProps);
|
|
28
28
|
destroy(): void;
|
|
29
29
|
forwardUpdate(update: ViewUpdate): void;
|
|
30
30
|
setSelection(anchor: number, head: number): void;
|
|
@@ -40,7 +40,8 @@ declare class CodeBlockAdvancedNodeView implements NodeView {
|
|
|
40
40
|
* This then gets translated to codemirror decorations in `prosemirrorDecorationPlugin`
|
|
41
41
|
*/
|
|
42
42
|
private updateProseMirrorDecorations;
|
|
43
|
+
private clearProseMirrorDecorations;
|
|
43
44
|
stopEvent(e: Event): boolean;
|
|
44
45
|
}
|
|
45
|
-
export declare const getCodeBlockAdvancedNodeView: (props: ConfigProps) => (node: PMNode, view: EditorView, getPos: getPosHandler) => CodeBlockAdvancedNodeView;
|
|
46
|
+
export declare const getCodeBlockAdvancedNodeView: (props: ConfigProps) => (node: PMNode, view: EditorView, getPos: getPosHandler, innerDecorations: DecorationSource) => CodeBlockAdvancedNodeView;
|
|
46
47
|
export {};
|
|
@@ -24,7 +24,7 @@ declare class CodeBlockAdvancedNodeView implements NodeView {
|
|
|
24
24
|
private cleanupDisabledState;
|
|
25
25
|
private languageLoader;
|
|
26
26
|
private pmFacet;
|
|
27
|
-
constructor(node: PMNode, view: EditorView, getPos: getPosHandlerNode, config: ConfigProps);
|
|
27
|
+
constructor(node: PMNode, view: EditorView, getPos: getPosHandlerNode, innerDecorations: DecorationSource, config: ConfigProps);
|
|
28
28
|
destroy(): void;
|
|
29
29
|
forwardUpdate(update: ViewUpdate): void;
|
|
30
30
|
setSelection(anchor: number, head: number): void;
|
|
@@ -40,7 +40,8 @@ declare class CodeBlockAdvancedNodeView implements NodeView {
|
|
|
40
40
|
* This then gets translated to codemirror decorations in `prosemirrorDecorationPlugin`
|
|
41
41
|
*/
|
|
42
42
|
private updateProseMirrorDecorations;
|
|
43
|
+
private clearProseMirrorDecorations;
|
|
43
44
|
stopEvent(e: Event): boolean;
|
|
44
45
|
}
|
|
45
|
-
export declare const getCodeBlockAdvancedNodeView: (props: ConfigProps) => (node: PMNode, view: EditorView, getPos: getPosHandler) => CodeBlockAdvancedNodeView;
|
|
46
|
+
export declare const getCodeBlockAdvancedNodeView: (props: ConfigProps) => (node: PMNode, view: EditorView, getPos: getPosHandler, innerDecorations: DecorationSource) => CodeBlockAdvancedNodeView;
|
|
46
47
|
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atlaskit/editor-plugin-code-block-advanced",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.2.0",
|
|
4
4
|
"description": "CodeBlockAdvanced plugin for @atlaskit/editor-core",
|
|
5
5
|
"author": "Atlassian Pty Ltd",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -33,14 +33,14 @@
|
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
35
|
"@atlaskit/adf-schema": "^47.6.0",
|
|
36
|
-
"@atlaskit/editor-common": "^102.
|
|
37
|
-
"@atlaskit/editor-plugin-code-block": "^4.
|
|
36
|
+
"@atlaskit/editor-common": "^102.19.0",
|
|
37
|
+
"@atlaskit/editor-plugin-code-block": "^4.2.0",
|
|
38
38
|
"@atlaskit/editor-plugin-editor-disabled": "^2.0.0",
|
|
39
39
|
"@atlaskit/editor-plugin-find-replace": "^2.0.0",
|
|
40
|
-
"@atlaskit/editor-plugin-selection": "^2.
|
|
41
|
-
"@atlaskit/editor-plugin-selection-marker": "^2.
|
|
40
|
+
"@atlaskit/editor-plugin-selection": "^2.1.0",
|
|
41
|
+
"@atlaskit/editor-plugin-selection-marker": "^2.1.0",
|
|
42
42
|
"@atlaskit/editor-prosemirror": "7.0.0",
|
|
43
|
-
"@atlaskit/tokens": "^4.
|
|
43
|
+
"@atlaskit/tokens": "^4.6.0",
|
|
44
44
|
"@babel/runtime": "^7.0.0",
|
|
45
45
|
"@codemirror/autocomplete": "6.18.4",
|
|
46
46
|
"@codemirror/commands": "6.7.1",
|
|
@@ -49,6 +49,7 @@
|
|
|
49
49
|
"@codemirror/state": "6.5.1",
|
|
50
50
|
"@codemirror/view": "6.36.2",
|
|
51
51
|
"@lezer/highlight": "1.2.1",
|
|
52
|
+
"@xiechao/codemirror-lang-handlebars": "^1.0.4",
|
|
52
53
|
"cm6-graphql": "0.2.0",
|
|
53
54
|
"codemirror-lang-elixir": "4.0.0"
|
|
54
55
|
},
|
|
@@ -56,7 +57,7 @@
|
|
|
56
57
|
"react": "^18.2.0"
|
|
57
58
|
},
|
|
58
59
|
"devDependencies": {
|
|
59
|
-
"@atlaskit/code": "^
|
|
60
|
+
"@atlaskit/code": "^17.0.0",
|
|
60
61
|
"typescript": "~5.4.2"
|
|
61
62
|
},
|
|
62
63
|
"techstack": {
|
|
@@ -19,6 +19,7 @@ import type {
|
|
|
19
19
|
EditorView,
|
|
20
20
|
NodeView,
|
|
21
21
|
} from '@atlaskit/editor-prosemirror/view';
|
|
22
|
+
import { DecorationSet } from '@atlaskit/editor-prosemirror/view';
|
|
22
23
|
|
|
23
24
|
import type { CodeBlockAdvancedPlugin } from '../codeBlockAdvancedPluginType';
|
|
24
25
|
import { highlightStyle } from '../ui/syntaxHighlightingTheme';
|
|
@@ -54,7 +55,13 @@ class CodeBlockAdvancedNodeView implements NodeView {
|
|
|
54
55
|
private languageLoader: LanguageLoader;
|
|
55
56
|
private pmFacet = Facet.define<DecorationSource>();
|
|
56
57
|
|
|
57
|
-
constructor(
|
|
58
|
+
constructor(
|
|
59
|
+
node: PMNode,
|
|
60
|
+
view: EditorView,
|
|
61
|
+
getPos: getPosHandlerNode,
|
|
62
|
+
innerDecorations: DecorationSource,
|
|
63
|
+
config: ConfigProps,
|
|
64
|
+
) {
|
|
58
65
|
this.node = node;
|
|
59
66
|
this.view = view;
|
|
60
67
|
this.getPos = getPos;
|
|
@@ -110,9 +117,15 @@ class CodeBlockAdvancedNodeView implements NodeView {
|
|
|
110
117
|
// inner editor
|
|
111
118
|
this.updating = false;
|
|
112
119
|
this.updateLanguage();
|
|
120
|
+
this.updateWordWrap(node);
|
|
121
|
+
this.updateProseMirrorDecorations(innerDecorations);
|
|
113
122
|
}
|
|
114
123
|
|
|
115
124
|
destroy() {
|
|
125
|
+
// ED-27428: CodeMirror gets into an infinite loop as it detects mutations on removed
|
|
126
|
+
// decorations. When we change the breakout we destroy the node and cleanup these decorations from
|
|
127
|
+
// codemirror
|
|
128
|
+
this.clearProseMirrorDecorations();
|
|
116
129
|
this.cleanupDisabledState?.();
|
|
117
130
|
}
|
|
118
131
|
|
|
@@ -214,6 +227,15 @@ class CodeBlockAdvancedNodeView implements NodeView {
|
|
|
214
227
|
this.updating = false;
|
|
215
228
|
}
|
|
216
229
|
|
|
230
|
+
private clearProseMirrorDecorations() {
|
|
231
|
+
this.updating = true;
|
|
232
|
+
const computedFacet = this.pmFacet.compute([], () => DecorationSet.empty);
|
|
233
|
+
this.cm.dispatch({
|
|
234
|
+
effects: this.pmDecorationsCompartment.reconfigure(computedFacet),
|
|
235
|
+
});
|
|
236
|
+
this.updating = false;
|
|
237
|
+
}
|
|
238
|
+
|
|
217
239
|
stopEvent(e: Event) {
|
|
218
240
|
if (e instanceof MouseEvent && e.type === 'mousedown') {
|
|
219
241
|
// !Warning: Side effect!
|
|
@@ -247,6 +269,17 @@ class CodeBlockAdvancedNodeView implements NodeView {
|
|
|
247
269
|
|
|
248
270
|
export const getCodeBlockAdvancedNodeView =
|
|
249
271
|
(props: ConfigProps) =>
|
|
250
|
-
(
|
|
251
|
-
|
|
272
|
+
(
|
|
273
|
+
node: PMNode,
|
|
274
|
+
view: EditorView,
|
|
275
|
+
getPos: getPosHandler,
|
|
276
|
+
innerDecorations: DecorationSource,
|
|
277
|
+
): CodeBlockAdvancedNodeView => {
|
|
278
|
+
return new CodeBlockAdvancedNodeView(
|
|
279
|
+
node,
|
|
280
|
+
view,
|
|
281
|
+
getPos as getPosHandlerNode,
|
|
282
|
+
innerDecorations,
|
|
283
|
+
props,
|
|
284
|
+
);
|
|
252
285
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { LanguageDescription } from '@codemirror/language';
|
|
1
|
+
import { LanguageDescription, LanguageSupport } from '@codemirror/language';
|
|
2
2
|
import { languages } from '@codemirror/language-data';
|
|
3
3
|
|
|
4
4
|
import type { LanguageAlias } from '@atlaskit/code';
|
|
@@ -63,6 +63,16 @@ export const mapLanguageToCodeMirror = (language: LanguageAliasValue) => {
|
|
|
63
63
|
return languages.find((l) => {
|
|
64
64
|
return l.name === 'VB.NET';
|
|
65
65
|
});
|
|
66
|
+
case 'handlebars':
|
|
67
|
+
return LanguageDescription.of({
|
|
68
|
+
name: 'Handlebars',
|
|
69
|
+
load() {
|
|
70
|
+
return import(
|
|
71
|
+
/* webpackChunkName: "@atlaskit-internal_@atlaskit/editor-plugin-code-block-advanced-lang-handlebars" */
|
|
72
|
+
'@xiechao/codemirror-lang-handlebars'
|
|
73
|
+
).then((m) => new LanguageSupport(m.handlebarsLanguage));
|
|
74
|
+
},
|
|
75
|
+
});
|
|
66
76
|
case 'elixir':
|
|
67
77
|
return LanguageDescription.of({
|
|
68
78
|
name: 'Elixir',
|
|
@@ -3,7 +3,7 @@ import { Extension } from '@codemirror/state';
|
|
|
3
3
|
import { withLazyLoading } from '@atlaskit/editor-common/lazy-node-view';
|
|
4
4
|
import type { ExtractInjectionAPI } from '@atlaskit/editor-common/types';
|
|
5
5
|
import type { Node as PMNode } from '@atlaskit/editor-prosemirror/model';
|
|
6
|
-
import type { EditorView } from '@atlaskit/editor-prosemirror/view';
|
|
6
|
+
import type { EditorView, DecorationSource, Decoration } from '@atlaskit/editor-prosemirror/view';
|
|
7
7
|
|
|
8
8
|
import type { CodeBlockAdvancedPlugin } from '../codeBlockAdvancedPluginType';
|
|
9
9
|
|
|
@@ -16,16 +16,19 @@ export const lazyCodeBlockView = (props: Props) => {
|
|
|
16
16
|
return withLazyLoading({
|
|
17
17
|
nodeName: 'codeBlock',
|
|
18
18
|
getNodeViewOptions: () => {},
|
|
19
|
-
loader: () => {
|
|
20
|
-
const
|
|
19
|
+
loader: async () => {
|
|
20
|
+
const { getCodeBlockAdvancedNodeView } = await import(
|
|
21
21
|
/* webpackChunkName: "@atlaskit-internal_editor-plugin-code-block-advanced-nodeview" */
|
|
22
22
|
'./codeBlockAdvanced'
|
|
23
|
-
)
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
23
|
+
);
|
|
24
|
+
return (
|
|
25
|
+
node: PMNode,
|
|
26
|
+
view: EditorView,
|
|
27
|
+
getPos: () => number | undefined,
|
|
28
|
+
_decs: readonly Decoration[],
|
|
29
|
+
_nodeViewOptions: () => void,
|
|
30
|
+
innerDecorations: DecorationSource,
|
|
31
|
+
) => getCodeBlockAdvancedNodeView(props)(node, view, getPos, innerDecorations);
|
|
29
32
|
},
|
|
30
33
|
});
|
|
31
34
|
};
|
package/src/pm-plugins/main.ts
CHANGED
|
@@ -2,10 +2,13 @@ import type { Extension } from '@codemirror/state';
|
|
|
2
2
|
|
|
3
3
|
import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
|
|
4
4
|
import type { ExtractInjectionAPI } from '@atlaskit/editor-common/types';
|
|
5
|
+
import type { EditorView } from '@atlaskit/editor-prosemirror/view';
|
|
5
6
|
|
|
6
7
|
import type { CodeBlockAdvancedPlugin } from '../codeBlockAdvancedPluginType';
|
|
7
8
|
import { lazyCodeBlockView } from '../nodeviews/lazyCodeBlockAdvanced';
|
|
8
9
|
|
|
10
|
+
import { shiftArrowDownWorkaround, shiftArrowUpWorkaround } from './shiftArrowKeyWorkaround';
|
|
11
|
+
|
|
9
12
|
interface Props {
|
|
10
13
|
api: ExtractInjectionAPI<CodeBlockAdvancedPlugin> | undefined;
|
|
11
14
|
extensions: Extension[];
|
|
@@ -17,6 +20,20 @@ export const createPlugin = (props: Props) => {
|
|
|
17
20
|
nodeViews: {
|
|
18
21
|
codeBlock: lazyCodeBlockView(props),
|
|
19
22
|
},
|
|
23
|
+
// Custom selection behaviour to fix issues with codeblocks with Shift + Arrow{Up || Down}
|
|
24
|
+
// These issues are also present in the prosemirror codemirror example and @marijnh suggests to
|
|
25
|
+
// use custom event handlers: https://github.com/ProseMirror/website/issues/83
|
|
26
|
+
handleKeyDown(view: EditorView, event: KeyboardEvent) {
|
|
27
|
+
if (!(event instanceof KeyboardEvent)) {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (event.key === 'ArrowUp' && event.shiftKey) {
|
|
32
|
+
return shiftArrowUpWorkaround(view, event);
|
|
33
|
+
} else if (event.key === 'ArrowDown' && event.shiftKey) {
|
|
34
|
+
return shiftArrowDownWorkaround(view, event);
|
|
35
|
+
}
|
|
36
|
+
},
|
|
20
37
|
},
|
|
21
38
|
});
|
|
22
39
|
};
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { TextSelection } from '@atlaskit/editor-prosemirror/state';
|
|
2
|
+
import type { EditorView } from '@atlaskit/editor-prosemirror/view';
|
|
3
|
+
|
|
4
|
+
export const shiftArrowUpWorkaround = (view: EditorView, event: KeyboardEvent) => {
|
|
5
|
+
const {
|
|
6
|
+
doc,
|
|
7
|
+
selection: { $head, $anchor },
|
|
8
|
+
tr,
|
|
9
|
+
schema: {
|
|
10
|
+
nodes: { codeBlock },
|
|
11
|
+
},
|
|
12
|
+
} = view.state;
|
|
13
|
+
|
|
14
|
+
// Position we want to check (directly after our current position)
|
|
15
|
+
const pos = Math.max($head.pos - 1, 1);
|
|
16
|
+
const isNodeBefore = doc.resolve(pos).nodeBefore?.type === codeBlock;
|
|
17
|
+
const maybeProblematicNode = isNodeBefore ? doc.resolve(pos).nodeBefore : doc.resolve(pos).node();
|
|
18
|
+
|
|
19
|
+
if (maybeProblematicNode?.type === codeBlock) {
|
|
20
|
+
const nodeSize = maybeProblematicNode.nodeSize;
|
|
21
|
+
const startPos = isNodeBefore ? pos : $head.pos;
|
|
22
|
+
|
|
23
|
+
tr.setSelection(TextSelection.create(doc, $anchor.pos, Math.max(startPos - nodeSize, 0)));
|
|
24
|
+
view.dispatch(tr);
|
|
25
|
+
event.preventDefault();
|
|
26
|
+
return true;
|
|
27
|
+
}
|
|
28
|
+
return false;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export const shiftArrowDownWorkaround = (view: EditorView, event: KeyboardEvent) => {
|
|
32
|
+
const {
|
|
33
|
+
doc,
|
|
34
|
+
selection: { $head, $anchor },
|
|
35
|
+
tr,
|
|
36
|
+
schema: {
|
|
37
|
+
nodes: { codeBlock },
|
|
38
|
+
},
|
|
39
|
+
} = view.state;
|
|
40
|
+
|
|
41
|
+
// Position we want to check (directly after our current position)
|
|
42
|
+
const pos = $head.pos + 1;
|
|
43
|
+
const isNodeAfter = doc.resolve(pos).nodeAfter?.type === codeBlock;
|
|
44
|
+
const maybeProblematicNode = isNodeAfter ? doc.resolve(pos).nodeAfter : doc.resolve(pos).node();
|
|
45
|
+
|
|
46
|
+
if (maybeProblematicNode?.type === codeBlock) {
|
|
47
|
+
const nodeSize = maybeProblematicNode.nodeSize;
|
|
48
|
+
const startPos = isNodeAfter ? pos : $head.pos;
|
|
49
|
+
|
|
50
|
+
tr.setSelection(
|
|
51
|
+
TextSelection.create(doc, $anchor.pos, Math.min(startPos + nodeSize, doc.content.size)),
|
|
52
|
+
);
|
|
53
|
+
view.dispatch(tr);
|
|
54
|
+
event.preventDefault();
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
return false;
|
|
58
|
+
};
|