@atlaskit/editor-plugin-code-block 3.3.9 → 3.3.11
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 +17 -0
- package/dist/cjs/nodeviews/code-block.js +6 -0
- package/dist/cjs/plugin.js +6 -0
- package/dist/cjs/pm-plugins/codeBlockAutoFullStopTransformPlugin.js +65 -0
- package/dist/cjs/pm-plugins/decorators.js +110 -5
- package/dist/cjs/pm-plugins/main.js +9 -63
- package/dist/cjs/toolbar.js +0 -1
- package/dist/cjs/utils.js +15 -0
- package/dist/es2019/nodeviews/code-block.js +7 -1
- package/dist/es2019/plugin.js +4 -0
- package/dist/es2019/pm-plugins/codeBlockAutoFullStopTransformPlugin.js +65 -0
- package/dist/es2019/pm-plugins/decorators.js +106 -3
- package/dist/es2019/pm-plugins/main.js +9 -60
- package/dist/es2019/toolbar.js +0 -1
- package/dist/es2019/utils.js +14 -0
- package/dist/esm/nodeviews/code-block.js +7 -1
- package/dist/esm/plugin.js +6 -0
- package/dist/esm/pm-plugins/codeBlockAutoFullStopTransformPlugin.js +58 -0
- package/dist/esm/pm-plugins/decorators.js +109 -4
- package/dist/esm/pm-plugins/main.js +9 -63
- package/dist/esm/toolbar.js +0 -1
- package/dist/esm/utils.js +14 -0
- package/dist/types/pm-plugins/codeBlockAutoFullStopTransformPlugin.d.ts +4 -0
- package/dist/types/pm-plugins/decorators.d.ts +32 -4
- package/dist/types/utils.d.ts +3 -1
- package/dist/types-ts4.5/pm-plugins/codeBlockAutoFullStopTransformPlugin.d.ts +4 -0
- package/dist/types-ts4.5/pm-plugins/decorators.d.ts +32 -4
- package/dist/types-ts4.5/utils.d.ts +3 -1
- package/package.json +5 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
# @atlaskit/editor-plugin-code-block
|
|
2
2
|
|
|
3
|
+
## 3.3.11
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#136266](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/pull-requests/136266)
|
|
8
|
+
[`cb41a82ab6813`](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/commits/cb41a82ab6813) -
|
|
9
|
+
ED-24752 Add new plugin to code block that strips auto inserted fullstops from mac on code blocks
|
|
10
|
+
- Updated dependencies
|
|
11
|
+
|
|
12
|
+
## 3.3.10
|
|
13
|
+
|
|
14
|
+
### Patch Changes
|
|
15
|
+
|
|
16
|
+
- [`cbe3b04ebb0b6`](https://stash.atlassian.com/projects/CONFCLOUD/repos/confluence-frontend/commits/cbe3b04ebb0b6) -
|
|
17
|
+
ED-24730 - Address bug where word wrap decorator broke on drag and drop. Required some refactoring
|
|
18
|
+
of decoration functions for code block. Moved all of them to decorators.ts and added unit tests.
|
|
19
|
+
|
|
3
20
|
## 3.3.9
|
|
4
21
|
|
|
5
22
|
### Patch Changes
|
|
@@ -89,6 +89,12 @@ var CodeBlockView = exports.CodeBlockView = /*#__PURE__*/function () {
|
|
|
89
89
|
this.api = api;
|
|
90
90
|
if ((0, _platformFeatureFlags.fg)('editor_support_code_block_wrapping')) {
|
|
91
91
|
this.maintainDynamicGutterSize();
|
|
92
|
+
|
|
93
|
+
// Ensure the code block node has a wrapped state.
|
|
94
|
+
// Wrapped state may already exist from breakout's recreating the node.
|
|
95
|
+
if (!_codeBlock.codeBlockWrappedStates.has(_node)) {
|
|
96
|
+
_codeBlock.codeBlockWrappedStates.set(_node, _codeBlock.defaultWordWrapState);
|
|
97
|
+
}
|
|
92
98
|
} else {
|
|
93
99
|
this.ensureLineNumbers();
|
|
94
100
|
}
|
package/dist/cjs/plugin.js
CHANGED
|
@@ -12,6 +12,7 @@ var _analytics = require("@atlaskit/editor-common/analytics");
|
|
|
12
12
|
var _messages = require("@atlaskit/editor-common/messages");
|
|
13
13
|
var _quickInsert = require("@atlaskit/editor-common/quick-insert");
|
|
14
14
|
var _actions = require("./actions");
|
|
15
|
+
var _codeBlockAutoFullStopTransformPlugin = require("./pm-plugins/codeBlockAutoFullStopTransformPlugin");
|
|
15
16
|
var _codeBlockCopySelectionPlugin = require("./pm-plugins/codeBlockCopySelectionPlugin");
|
|
16
17
|
var _ideUx = _interopRequireDefault(require("./pm-plugins/ide-ux"));
|
|
17
18
|
var _inputRule = require("./pm-plugins/input-rule");
|
|
@@ -65,6 +66,11 @@ var codeBlockPlugin = function codeBlockPlugin(_ref) {
|
|
|
65
66
|
plugin: function plugin() {
|
|
66
67
|
return (0, _codeBlockCopySelectionPlugin.codeBlockCopySelectionPlugin)();
|
|
67
68
|
}
|
|
69
|
+
}, {
|
|
70
|
+
name: 'codeBlockAutoFullStopTransform',
|
|
71
|
+
plugin: function plugin() {
|
|
72
|
+
return (0, _codeBlockAutoFullStopTransformPlugin.codeBlockAutoFullStopTransformPlugin)();
|
|
73
|
+
}
|
|
68
74
|
}];
|
|
69
75
|
},
|
|
70
76
|
// Workaround for a firefox issue where dom selection is off sync
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.codeBlockAutoFullStopTransformPlugin = codeBlockAutoFullStopTransformPlugin;
|
|
7
|
+
exports.codeBlockAutoFullStopTransformPluginKey = void 0;
|
|
8
|
+
var _safePlugin = require("@atlaskit/editor-common/safe-plugin");
|
|
9
|
+
var _utils = require("@atlaskit/editor-common/utils");
|
|
10
|
+
var _state = require("@atlaskit/editor-prosemirror/state");
|
|
11
|
+
var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
|
|
12
|
+
var _utils2 = require("../utils");
|
|
13
|
+
var codeBlockAutoFullStopTransformPluginKey = exports.codeBlockAutoFullStopTransformPluginKey = new _state.PluginKey('codeBlockAutoFullStopTransformPluginKey');
|
|
14
|
+
function codeBlockAutoFullStopTransformPlugin() {
|
|
15
|
+
return new _safePlugin.SafePlugin({
|
|
16
|
+
key: codeBlockAutoFullStopTransformPluginKey,
|
|
17
|
+
appendTransaction: function appendTransaction(_transactions, oldState, newState) {
|
|
18
|
+
if (!(0, _platformFeatureFlags.fg)('editor_support_code_block_wrapping') || !(0, _platformFeatureFlags.fg)('code_block_auto_insertion_bug_fix')) {
|
|
19
|
+
return undefined;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// We need to compare the old and new state to isloate auto insertion of fullstop on mac
|
|
23
|
+
var trNew = newState.tr;
|
|
24
|
+
var trOld = oldState.tr;
|
|
25
|
+
var fromOld = trOld.selection.from;
|
|
26
|
+
var _trNew$selection = trNew.selection,
|
|
27
|
+
fromNew = _trNew$selection.from,
|
|
28
|
+
toNew = _trNew$selection.to;
|
|
29
|
+
var isCodeBlock = !!(0, _utils2.findCodeBlock)(oldState, trOld.selection) && !!(0, _utils2.findCodeBlock)(newState, trNew.selection);
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Mac will auto insert a fullstop when the user double taps the space key after some content.
|
|
33
|
+
* Line number decorators are assumed content so on new lines the fullstop is inserted.
|
|
34
|
+
*
|
|
35
|
+
* - When a fulltop is auto inserted the new states selection is the same, the old state selection is one position less
|
|
36
|
+
* - The text returned for the old state returns as a space with the selection from - 1
|
|
37
|
+
* - The text returned for the new state returns as a fullstop with the selection from - 2 to from -1
|
|
38
|
+
*
|
|
39
|
+
* This is enough conditional logic to isoloate the auto insertion of the fullstop on mac
|
|
40
|
+
*
|
|
41
|
+
* There are some solutions to this problem in codemirror which can be read further here
|
|
42
|
+
* https://discuss.codemirror.net/t/dot-being-added-when-pressing-space-repeatedly/3899
|
|
43
|
+
*/
|
|
44
|
+
|
|
45
|
+
// both selections must be of code block early exit
|
|
46
|
+
if (_utils.browser.mac && fromNew === toNew && fromNew === fromOld + 1 && isCodeBlock) {
|
|
47
|
+
// detect when '.' is inserted when the previous state was a space ' '
|
|
48
|
+
try {
|
|
49
|
+
var textBetweenBefore = trOld.doc.textBetween(fromOld - 1, fromOld); // ' '
|
|
50
|
+
var textBetweenAfter = trNew.doc.textBetween(fromNew - 2, fromNew - 1); // '.'
|
|
51
|
+
if (textBetweenBefore === ' ' && textBetweenAfter === '.') {
|
|
52
|
+
trNew.delete(fromNew - 2, fromNew); // remove the fullstop
|
|
53
|
+
trNew.insertText(' ', fromNew - 2); // insert double space
|
|
54
|
+
|
|
55
|
+
return trNew;
|
|
56
|
+
}
|
|
57
|
+
} catch (error) {
|
|
58
|
+
// if for some reason textBetween fails, just return the new transaction as is by defaut.
|
|
59
|
+
return undefined;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return undefined;
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
}
|
|
@@ -4,14 +4,65 @@ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefau
|
|
|
4
4
|
Object.defineProperty(exports, "__esModule", {
|
|
5
5
|
value: true
|
|
6
6
|
});
|
|
7
|
-
exports.generateLineAttributesFromNode = exports.createLineNumbersDecorations = exports.createDecorationSetFromLineAttributes = exports.DECORATION_WIDGET_TYPE = void 0;
|
|
7
|
+
exports.validateWordWrappedDecorators = exports.updateDecorationSetWithWordWrappedDecorator = exports.updateDecorationSetWithLineNumberDecorators = exports.updateCodeBlockDecorations = exports.getWordWrapDecoratorsFromNodePos = exports.generateLineAttributesFromNode = exports.generateInitialDecorations = exports.createLineNumbersDecorations = exports.createDecorationSetFromLineAttributes = exports.DECORATION_WRAPPED_BLOCK_NODE_TYPE = exports.DECORATION_WIDGET_TYPE = void 0;
|
|
8
8
|
var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
|
|
9
|
+
var _codeBlock = require("@atlaskit/editor-common/code-block");
|
|
9
10
|
var _view = require("@atlaskit/editor-prosemirror/view");
|
|
10
11
|
var _classNames = require("../ui/class-names");
|
|
12
|
+
var _utils = require("../utils");
|
|
11
13
|
var DECORATION_WIDGET_TYPE = exports.DECORATION_WIDGET_TYPE = 'decorationWidgetType';
|
|
12
|
-
var
|
|
14
|
+
var DECORATION_WRAPPED_BLOCK_NODE_TYPE = exports.DECORATION_WRAPPED_BLOCK_NODE_TYPE = 'decorationNodeType';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Generate the initial decorations for the code block.
|
|
18
|
+
*/
|
|
19
|
+
var generateInitialDecorations = exports.generateInitialDecorations = function generateInitialDecorations(state) {
|
|
20
|
+
var codeBlockNodes = (0, _utils.getAllCodeBlockNodesInDoc)(state);
|
|
21
|
+
return codeBlockNodes.flatMap(function (node) {
|
|
22
|
+
return createLineNumbersDecorations(node);
|
|
23
|
+
});
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Update all the decorations used by the code block.
|
|
28
|
+
*/
|
|
29
|
+
var updateCodeBlockDecorations = exports.updateCodeBlockDecorations = function updateCodeBlockDecorations(tr, state, decorationSet) {
|
|
30
|
+
var updatedDecorationSet = decorationSet;
|
|
31
|
+
var codeBlockNodes = (0, _utils.getAllCodeBlockNodesInDoc)(state);
|
|
32
|
+
|
|
33
|
+
// All the line numbers decorators are refreshed on doc change.
|
|
34
|
+
updatedDecorationSet = updateDecorationSetWithLineNumberDecorators(tr, codeBlockNodes, updatedDecorationSet);
|
|
35
|
+
|
|
36
|
+
// Check to make sure the word wrap decorators are still valid.
|
|
37
|
+
updatedDecorationSet = validateWordWrappedDecorators(tr, codeBlockNodes, updatedDecorationSet);
|
|
38
|
+
return updatedDecorationSet;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Update the decorations set with the line number decorators.
|
|
43
|
+
*/
|
|
44
|
+
var updateDecorationSetWithLineNumberDecorators = exports.updateDecorationSetWithLineNumberDecorators = function updateDecorationSetWithLineNumberDecorators(tr, codeBlockNodes, decorationSet) {
|
|
45
|
+
var updatedDecorationSet = decorationSet;
|
|
46
|
+
// remove all the line number children from the decorations set. 'undefined, undefined' is used to find() the whole doc.
|
|
47
|
+
var children = updatedDecorationSet.find(undefined, undefined, function (spec) {
|
|
48
|
+
return spec.type === DECORATION_WIDGET_TYPE;
|
|
49
|
+
});
|
|
50
|
+
updatedDecorationSet = updatedDecorationSet.remove(children);
|
|
51
|
+
|
|
52
|
+
// regenerate all the line number for the documents code blocks
|
|
53
|
+
var lineNumberDecorators = [];
|
|
54
|
+
codeBlockNodes.forEach(function (node) {
|
|
55
|
+
lineNumberDecorators.push.apply(lineNumberDecorators, (0, _toConsumableArray2.default)(createLineNumbersDecorations(node)));
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
// add the newly generated line numbers to the decorations set
|
|
59
|
+
return updatedDecorationSet.add(tr.doc, [].concat(lineNumberDecorators));
|
|
60
|
+
};
|
|
61
|
+
var generateLineAttributesFromNode = exports.generateLineAttributesFromNode = function generateLineAttributesFromNode(node) {
|
|
62
|
+
var innerNode = node.node,
|
|
63
|
+
pos = node.pos;
|
|
13
64
|
// Get content node
|
|
14
|
-
var contentNode =
|
|
65
|
+
var contentNode = innerNode.content;
|
|
15
66
|
|
|
16
67
|
// Get node text content
|
|
17
68
|
var lineAttributes = [];
|
|
@@ -64,6 +115,60 @@ var createDecorationSetFromLineAttributes = exports.createDecorationSetFromLineA
|
|
|
64
115
|
});
|
|
65
116
|
return widgetDecorations;
|
|
66
117
|
};
|
|
67
|
-
var createLineNumbersDecorations = exports.createLineNumbersDecorations = function createLineNumbersDecorations(
|
|
68
|
-
return createDecorationSetFromLineAttributes(generateLineAttributesFromNode(
|
|
118
|
+
var createLineNumbersDecorations = exports.createLineNumbersDecorations = function createLineNumbersDecorations(node) {
|
|
119
|
+
return createDecorationSetFromLineAttributes(generateLineAttributesFromNode(node));
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* There are edge cases like when a user drags and drops a code block node where the decorator breaks and no longer reflects
|
|
124
|
+
* the correct word wrap state. This function validates that the decorator and the state are in line, otherwise it will
|
|
125
|
+
* retrigger the logic to apply the word wrap decorator.
|
|
126
|
+
*/
|
|
127
|
+
var validateWordWrappedDecorators = exports.validateWordWrappedDecorators = function validateWordWrappedDecorators(tr, codeBlockNodes, decorationSet) {
|
|
128
|
+
var updatedDecorationSet = decorationSet;
|
|
129
|
+
codeBlockNodes.forEach(function (node) {
|
|
130
|
+
var isCodeBlockWrappedInState = (0, _codeBlock.isCodeBlockWordWrapEnabled)(node.node);
|
|
131
|
+
var isCodeBlockWrappedByDecorator = getWordWrapDecoratorsFromNodePos(node.pos, decorationSet).length !== 0;
|
|
132
|
+
if (isCodeBlockWrappedInState && !isCodeBlockWrappedByDecorator) {
|
|
133
|
+
updatedDecorationSet = updateDecorationSetWithWordWrappedDecorator(decorationSet, tr, node);
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
return updatedDecorationSet;
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Update the decoration set with the word wrap decorator.
|
|
141
|
+
*/
|
|
142
|
+
var updateDecorationSetWithWordWrappedDecorator = exports.updateDecorationSetWithWordWrappedDecorator = function updateDecorationSetWithWordWrappedDecorator(decorationSet, tr, node) {
|
|
143
|
+
if (!node || node.pos === undefined) {
|
|
144
|
+
return decorationSet;
|
|
145
|
+
}
|
|
146
|
+
var updatedDecorationSet = decorationSet;
|
|
147
|
+
var pos = node.pos,
|
|
148
|
+
innerNode = node.node;
|
|
149
|
+
var isNodeWrapped = (0, _codeBlock.isCodeBlockWordWrapEnabled)(innerNode);
|
|
150
|
+
if (!isNodeWrapped) {
|
|
151
|
+
var currentWrappedBlockDecorationSet = getWordWrapDecoratorsFromNodePos(pos, updatedDecorationSet);
|
|
152
|
+
updatedDecorationSet = updatedDecorationSet.remove(currentWrappedBlockDecorationSet);
|
|
153
|
+
} else {
|
|
154
|
+
var wrappedBlock = _view.Decoration.node(pos, pos + innerNode.nodeSize, {
|
|
155
|
+
class: _classNames.codeBlockClassNames.contentFgWrapped
|
|
156
|
+
}, {
|
|
157
|
+
type: DECORATION_WRAPPED_BLOCK_NODE_TYPE
|
|
158
|
+
} // Allows for quick filtering of decorations while using `find`
|
|
159
|
+
);
|
|
160
|
+
updatedDecorationSet = updatedDecorationSet.add(tr.doc, [wrappedBlock]);
|
|
161
|
+
}
|
|
162
|
+
return updatedDecorationSet;
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Get the word wrap decorators for the given node position.
|
|
167
|
+
*/
|
|
168
|
+
var getWordWrapDecoratorsFromNodePos = exports.getWordWrapDecoratorsFromNodePos = function getWordWrapDecoratorsFromNodePos(pos, decorationSet) {
|
|
169
|
+
var codeBlockNodePosition = pos + 1; // We need to add 1 to the position to get the start of the node.
|
|
170
|
+
var currentWrappedBlockDecorationSet = decorationSet.find(codeBlockNodePosition, codeBlockNodePosition, function (spec) {
|
|
171
|
+
return spec.type === DECORATION_WRAPPED_BLOCK_NODE_TYPE;
|
|
172
|
+
});
|
|
173
|
+
return currentWrappedBlockDecorationSet;
|
|
69
174
|
};
|
|
@@ -6,8 +6,6 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
6
6
|
});
|
|
7
7
|
exports.createPlugin = void 0;
|
|
8
8
|
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
|
|
9
|
-
var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
|
|
10
|
-
var _codeBlock = require("@atlaskit/editor-common/code-block");
|
|
11
9
|
var _messages = require("@atlaskit/editor-common/messages");
|
|
12
10
|
var _safePlugin = require("@atlaskit/editor-common/safe-plugin");
|
|
13
11
|
var _selection = require("@atlaskit/editor-common/selection");
|
|
@@ -16,7 +14,7 @@ var _state = require("@atlaskit/editor-prosemirror/state");
|
|
|
16
14
|
var _view = require("@atlaskit/editor-prosemirror/view");
|
|
17
15
|
var _platformFeatureFlags = require("@atlaskit/platform-feature-flags");
|
|
18
16
|
var _actions = require("../actions");
|
|
19
|
-
var
|
|
17
|
+
var _codeBlock = require("../nodeviews/code-block");
|
|
20
18
|
var _pluginKey = require("../plugin-key");
|
|
21
19
|
var _classNames = require("../ui/class-names");
|
|
22
20
|
var _utils2 = require("../utils");
|
|
@@ -24,7 +22,6 @@ var _actions2 = require("./actions");
|
|
|
24
22
|
var _decorators = require("./decorators");
|
|
25
23
|
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
26
24
|
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
27
|
-
var DECORATION_WRAPPED_BLOCK_NODE_TYPE = 'decorationNodeType';
|
|
28
25
|
var createPlugin = exports.createPlugin = function createPlugin(_ref) {
|
|
29
26
|
var _ref$useLongPressSele = _ref.useLongPressSelection,
|
|
30
27
|
useLongPressSelection = _ref$useLongPressSele === void 0 ? false : _ref$useLongPressSele,
|
|
@@ -33,57 +30,6 @@ var createPlugin = exports.createPlugin = function createPlugin(_ref) {
|
|
|
33
30
|
allowCompositionInputOverride = _ref$allowComposition === void 0 ? false : _ref$allowComposition,
|
|
34
31
|
api = _ref.api;
|
|
35
32
|
var handleDOMEvents = {};
|
|
36
|
-
var createLineNumberDecoratorsFromDecendants = function createLineNumberDecoratorsFromDecendants(editorState) {
|
|
37
|
-
var lineNumberDecorators = [];
|
|
38
|
-
editorState.doc.descendants(function (node, pos) {
|
|
39
|
-
if (node.type === editorState.schema.nodes.codeBlock) {
|
|
40
|
-
lineNumberDecorators.push.apply(lineNumberDecorators, (0, _toConsumableArray2.default)((0, _decorators.createLineNumbersDecorations)(pos, node)));
|
|
41
|
-
return false;
|
|
42
|
-
}
|
|
43
|
-
return true;
|
|
44
|
-
});
|
|
45
|
-
return lineNumberDecorators;
|
|
46
|
-
};
|
|
47
|
-
var createWordWrappedDecoratorPluginState = function createWordWrappedDecoratorPluginState(pluginState, tr, node) {
|
|
48
|
-
var decorationSetFromState = pluginState.decorations;
|
|
49
|
-
if (node) {
|
|
50
|
-
var pos = node.pos,
|
|
51
|
-
innerNode = node.node;
|
|
52
|
-
if (pos !== undefined) {
|
|
53
|
-
var isNodeWrapped = (0, _codeBlock.isCodeBlockWordWrapEnabled)(innerNode);
|
|
54
|
-
if (!isNodeWrapped) {
|
|
55
|
-
// Restricts the range of decorators to the current node while not including the previous nodes position in range
|
|
56
|
-
var codeBlockNodePosition = pos + 1;
|
|
57
|
-
var currentWrappedBlockDecorationSet = decorationSetFromState.find(codeBlockNodePosition, codeBlockNodePosition, function (spec) {
|
|
58
|
-
return spec.type === DECORATION_WRAPPED_BLOCK_NODE_TYPE;
|
|
59
|
-
});
|
|
60
|
-
decorationSetFromState = decorationSetFromState.remove(currentWrappedBlockDecorationSet);
|
|
61
|
-
} else {
|
|
62
|
-
var wrappedBlock = _view.Decoration.node(pos, pos + innerNode.nodeSize, {
|
|
63
|
-
class: _classNames.codeBlockClassNames.contentFgWrapped
|
|
64
|
-
}, {
|
|
65
|
-
type: DECORATION_WRAPPED_BLOCK_NODE_TYPE
|
|
66
|
-
} // Allows for quick filtering of decorations while using `find`
|
|
67
|
-
);
|
|
68
|
-
decorationSetFromState = decorationSetFromState.add(tr.doc, [wrappedBlock]);
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
return decorationSetFromState;
|
|
73
|
-
};
|
|
74
|
-
var updateLineDecorationSet = function updateLineDecorationSet(tr, state, decorationSet) {
|
|
75
|
-
// remove all the line number children from the decorations set. 'undefined, undefined' is used to find() the whole doc.
|
|
76
|
-
var children = decorationSet.find(undefined, undefined, function (spec) {
|
|
77
|
-
return spec.type === _decorators.DECORATION_WIDGET_TYPE;
|
|
78
|
-
});
|
|
79
|
-
decorationSet = decorationSet.remove(children);
|
|
80
|
-
|
|
81
|
-
// regenerate all the line number for the documents code blocks
|
|
82
|
-
var lineDecorators = createLineNumberDecoratorsFromDecendants(state);
|
|
83
|
-
|
|
84
|
-
// add the newly generated line numbers to the decorations set
|
|
85
|
-
return decorationSet.add(tr.doc, (0, _toConsumableArray2.default)(lineDecorators));
|
|
86
|
-
};
|
|
87
33
|
|
|
88
34
|
// ME-1599: Composition on mobile was causing the DOM observer to mutate the code block
|
|
89
35
|
// incorrecly and lose content when pressing enter in the middle of a code block line.
|
|
@@ -127,13 +73,13 @@ var createPlugin = exports.createPlugin = function createPlugin(_ref) {
|
|
|
127
73
|
state: {
|
|
128
74
|
init: function init(_, state) {
|
|
129
75
|
var node = (0, _utils2.findCodeBlock)(state, state.selection);
|
|
130
|
-
var
|
|
76
|
+
var initialDecorations = (0, _platformFeatureFlags.fg)('editor_support_code_block_wrapping') ? (0, _decorators.generateInitialDecorations)(state) : [];
|
|
131
77
|
return {
|
|
132
78
|
pos: node ? node.pos : null,
|
|
133
79
|
contentCopied: false,
|
|
134
80
|
isNodeSelected: false,
|
|
135
81
|
shouldIgnoreFollowingMutations: false,
|
|
136
|
-
decorations: _view.DecorationSet.create(state.doc,
|
|
82
|
+
decorations: _view.DecorationSet.create(state.doc, initialDecorations)
|
|
137
83
|
};
|
|
138
84
|
},
|
|
139
85
|
apply: function apply(tr, pluginState, _oldState, newState) {
|
|
@@ -141,18 +87,18 @@ var createPlugin = exports.createPlugin = function createPlugin(_ref) {
|
|
|
141
87
|
if ((meta === null || meta === void 0 ? void 0 : meta.type) === _actions2.ACTIONS.SET_IS_WRAPPED && (0, _platformFeatureFlags.fg)('editor_support_code_block_wrapping')) {
|
|
142
88
|
var node = (0, _utils2.findCodeBlock)(newState, tr.selection);
|
|
143
89
|
return _objectSpread(_objectSpread({}, pluginState), {}, {
|
|
144
|
-
decorations:
|
|
90
|
+
decorations: (0, _decorators.updateDecorationSetWithWordWrappedDecorator)(pluginState.decorations, tr, node)
|
|
145
91
|
});
|
|
146
92
|
}
|
|
147
93
|
if (tr.docChanged) {
|
|
148
94
|
var _node = (0, _utils2.findCodeBlock)(newState, tr.selection);
|
|
149
95
|
|
|
150
96
|
// Updates mapping position of all existing decorations to new positions
|
|
151
|
-
// specifically used for updating word wrap node decorators
|
|
97
|
+
// specifically used for updating word wrap node decorators (does not cover drag & drop, validateWordWrappedDecorators does).
|
|
152
98
|
var updatedDecorationSet = pluginState.decorations.map(tr.mapping, tr.doc);
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
99
|
+
if ((0, _platformFeatureFlags.fg)('editor_support_code_block_wrapping')) {
|
|
100
|
+
updatedDecorationSet = (0, _decorators.updateCodeBlockDecorations)(tr, newState, updatedDecorationSet);
|
|
101
|
+
}
|
|
156
102
|
var newPluginState = _objectSpread(_objectSpread({}, pluginState), {}, {
|
|
157
103
|
pos: _node ? _node.pos : null,
|
|
158
104
|
isNodeSelected: tr.selection instanceof _state.NodeSelection,
|
|
@@ -193,7 +139,7 @@ var createPlugin = exports.createPlugin = function createPlugin(_ref) {
|
|
|
193
139
|
var _getIntl = getIntl(),
|
|
194
140
|
formatMessage = _getIntl.formatMessage;
|
|
195
141
|
var formattedAriaLabel = formatMessage(_messages.blockTypeMessages.codeblock);
|
|
196
|
-
return (0,
|
|
142
|
+
return (0, _codeBlock.codeBlockNodeView)(node, view, getPos, formattedAriaLabel, api);
|
|
197
143
|
}
|
|
198
144
|
},
|
|
199
145
|
handleClickOn: (0, _selection.createSelectionClickHandler)(['codeBlock'], function (target) {
|
package/dist/cjs/toolbar.js
CHANGED
|
@@ -109,7 +109,6 @@ var getToolbarConfig = exports.getToolbarConfig = function getToolbarConfig() {
|
|
|
109
109
|
supportsViewMode: true,
|
|
110
110
|
icon: _WrapIcon.WrapIcon,
|
|
111
111
|
onClick: (0, _actions.toggleWordWrapStateForCodeBlockNode)(editorAnalyticsAPI),
|
|
112
|
-
// Hooking up here for demo purposes. To be revisited with ED-24222.
|
|
113
112
|
title: isWrapped ? formatMessage(_messages.codeBlockButtonMessages.unwrapCode) : formatMessage(_messages.codeBlockButtonMessages.wrapCode),
|
|
114
113
|
tabIndex: null,
|
|
115
114
|
selected: isWrapped
|
package/dist/cjs/utils.js
CHANGED
|
@@ -9,6 +9,7 @@ Object.defineProperty(exports, "findCodeBlock", {
|
|
|
9
9
|
return _transforms.findCodeBlock;
|
|
10
10
|
}
|
|
11
11
|
});
|
|
12
|
+
exports.getAllCodeBlockNodesInDoc = getAllCodeBlockNodesInDoc;
|
|
12
13
|
exports.getCursor = getCursor;
|
|
13
14
|
Object.defineProperty(exports, "transformSingleLineCodeBlockToCodeMark", {
|
|
14
15
|
enumerable: true,
|
|
@@ -25,4 +26,18 @@ Object.defineProperty(exports, "transformSliceToJoinAdjacentCodeBlocks", {
|
|
|
25
26
|
var _transforms = require("@atlaskit/editor-common/transforms");
|
|
26
27
|
function getCursor(selection) {
|
|
27
28
|
return selection.$cursor || undefined;
|
|
29
|
+
}
|
|
30
|
+
function getAllCodeBlockNodesInDoc(state) {
|
|
31
|
+
var codeBlockNodes = [];
|
|
32
|
+
state.doc.descendants(function (node, pos) {
|
|
33
|
+
if (node.type === state.schema.nodes.codeBlock) {
|
|
34
|
+
codeBlockNodes.push({
|
|
35
|
+
node: node,
|
|
36
|
+
pos: pos
|
|
37
|
+
});
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
return true;
|
|
41
|
+
});
|
|
42
|
+
return codeBlockNodes;
|
|
28
43
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
2
2
|
import rafSchedule from 'raf-schd';
|
|
3
|
-
import { transferCodeBlockWrappedValue } from '@atlaskit/editor-common/code-block';
|
|
3
|
+
import { codeBlockWrappedStates, defaultWordWrapState, transferCodeBlockWrappedValue } from '@atlaskit/editor-common/code-block';
|
|
4
4
|
import { browser } from '@atlaskit/editor-common/utils';
|
|
5
5
|
import { DOMSerializer } from '@atlaskit/editor-prosemirror/model';
|
|
6
6
|
import { fg } from '@atlaskit/platform-feature-flags';
|
|
@@ -77,6 +77,12 @@ export class CodeBlockView {
|
|
|
77
77
|
this.api = api;
|
|
78
78
|
if (fg('editor_support_code_block_wrapping')) {
|
|
79
79
|
this.maintainDynamicGutterSize();
|
|
80
|
+
|
|
81
|
+
// Ensure the code block node has a wrapped state.
|
|
82
|
+
// Wrapped state may already exist from breakout's recreating the node.
|
|
83
|
+
if (!codeBlockWrappedStates.has(_node)) {
|
|
84
|
+
codeBlockWrappedStates.set(_node, defaultWordWrapState);
|
|
85
|
+
}
|
|
80
86
|
} else {
|
|
81
87
|
this.ensureLineNumbers();
|
|
82
88
|
}
|
package/dist/es2019/plugin.js
CHANGED
|
@@ -4,6 +4,7 @@ import { ACTION, ACTION_SUBJECT, ACTION_SUBJECT_ID, EVENT_TYPE, INPUT_METHOD } f
|
|
|
4
4
|
import { blockTypeMessages } from '@atlaskit/editor-common/messages';
|
|
5
5
|
import { IconCode } from '@atlaskit/editor-common/quick-insert';
|
|
6
6
|
import { createInsertCodeBlockTransaction, insertCodeBlockWithAnalytics } from './actions';
|
|
7
|
+
import { codeBlockAutoFullStopTransformPlugin } from './pm-plugins/codeBlockAutoFullStopTransformPlugin';
|
|
7
8
|
import { codeBlockCopySelectionPlugin } from './pm-plugins/codeBlockCopySelectionPlugin';
|
|
8
9
|
import ideUX from './pm-plugins/ide-ux';
|
|
9
10
|
import { createCodeBlockInputRule } from './pm-plugins/input-rule';
|
|
@@ -51,6 +52,9 @@ const codeBlockPlugin = ({
|
|
|
51
52
|
}, {
|
|
52
53
|
name: 'codeBlockCopySelection',
|
|
53
54
|
plugin: () => codeBlockCopySelectionPlugin()
|
|
55
|
+
}, {
|
|
56
|
+
name: 'codeBlockAutoFullStopTransform',
|
|
57
|
+
plugin: () => codeBlockAutoFullStopTransformPlugin()
|
|
54
58
|
}];
|
|
55
59
|
},
|
|
56
60
|
// Workaround for a firefox issue where dom selection is off sync
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { SafePlugin } from '@atlaskit/editor-common/safe-plugin';
|
|
2
|
+
import { browser } from '@atlaskit/editor-common/utils';
|
|
3
|
+
import { PluginKey } from '@atlaskit/editor-prosemirror/state';
|
|
4
|
+
import { fg } from '@atlaskit/platform-feature-flags';
|
|
5
|
+
import { findCodeBlock } from '../utils';
|
|
6
|
+
export const codeBlockAutoFullStopTransformPluginKey = new PluginKey('codeBlockAutoFullStopTransformPluginKey');
|
|
7
|
+
export function codeBlockAutoFullStopTransformPlugin() {
|
|
8
|
+
return new SafePlugin({
|
|
9
|
+
key: codeBlockAutoFullStopTransformPluginKey,
|
|
10
|
+
appendTransaction(_transactions, oldState, newState) {
|
|
11
|
+
if (!fg('editor_support_code_block_wrapping') || !fg('code_block_auto_insertion_bug_fix')) {
|
|
12
|
+
return undefined;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// We need to compare the old and new state to isloate auto insertion of fullstop on mac
|
|
16
|
+
const {
|
|
17
|
+
tr: trNew
|
|
18
|
+
} = newState;
|
|
19
|
+
const {
|
|
20
|
+
tr: trOld
|
|
21
|
+
} = oldState;
|
|
22
|
+
const {
|
|
23
|
+
from: fromOld
|
|
24
|
+
} = trOld.selection;
|
|
25
|
+
const {
|
|
26
|
+
from: fromNew,
|
|
27
|
+
to: toNew
|
|
28
|
+
} = trNew.selection;
|
|
29
|
+
const isCodeBlock = !!findCodeBlock(oldState, trOld.selection) && !!findCodeBlock(newState, trNew.selection);
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Mac will auto insert a fullstop when the user double taps the space key after some content.
|
|
33
|
+
* Line number decorators are assumed content so on new lines the fullstop is inserted.
|
|
34
|
+
*
|
|
35
|
+
* - When a fulltop is auto inserted the new states selection is the same, the old state selection is one position less
|
|
36
|
+
* - The text returned for the old state returns as a space with the selection from - 1
|
|
37
|
+
* - The text returned for the new state returns as a fullstop with the selection from - 2 to from -1
|
|
38
|
+
*
|
|
39
|
+
* This is enough conditional logic to isoloate the auto insertion of the fullstop on mac
|
|
40
|
+
*
|
|
41
|
+
* There are some solutions to this problem in codemirror which can be read further here
|
|
42
|
+
* https://discuss.codemirror.net/t/dot-being-added-when-pressing-space-repeatedly/3899
|
|
43
|
+
*/
|
|
44
|
+
|
|
45
|
+
// both selections must be of code block early exit
|
|
46
|
+
if (browser.mac && fromNew === toNew && fromNew === fromOld + 1 && isCodeBlock) {
|
|
47
|
+
// detect when '.' is inserted when the previous state was a space ' '
|
|
48
|
+
try {
|
|
49
|
+
const textBetweenBefore = trOld.doc.textBetween(fromOld - 1, fromOld); // ' '
|
|
50
|
+
const textBetweenAfter = trNew.doc.textBetween(fromNew - 2, fromNew - 1); // '.'
|
|
51
|
+
if (textBetweenBefore === ' ' && textBetweenAfter === '.') {
|
|
52
|
+
trNew.delete(fromNew - 2, fromNew); // remove the fullstop
|
|
53
|
+
trNew.insertText(' ', fromNew - 2); // insert double space
|
|
54
|
+
|
|
55
|
+
return trNew;
|
|
56
|
+
}
|
|
57
|
+
} catch (error) {
|
|
58
|
+
// if for some reason textBetween fails, just return the new transaction as is by defaut.
|
|
59
|
+
return undefined;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return undefined;
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
}
|
|
@@ -1,9 +1,58 @@
|
|
|
1
|
+
import { isCodeBlockWordWrapEnabled } from '@atlaskit/editor-common/code-block';
|
|
1
2
|
import { Decoration } from '@atlaskit/editor-prosemirror/view';
|
|
2
3
|
import { codeBlockClassNames } from '../ui/class-names';
|
|
4
|
+
import { getAllCodeBlockNodesInDoc } from '../utils';
|
|
3
5
|
export const DECORATION_WIDGET_TYPE = 'decorationWidgetType';
|
|
4
|
-
export const
|
|
6
|
+
export const DECORATION_WRAPPED_BLOCK_NODE_TYPE = 'decorationNodeType';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Generate the initial decorations for the code block.
|
|
10
|
+
*/
|
|
11
|
+
export const generateInitialDecorations = state => {
|
|
12
|
+
const codeBlockNodes = getAllCodeBlockNodesInDoc(state);
|
|
13
|
+
return codeBlockNodes.flatMap(node => createLineNumbersDecorations(node));
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Update all the decorations used by the code block.
|
|
18
|
+
*/
|
|
19
|
+
export const updateCodeBlockDecorations = (tr, state, decorationSet) => {
|
|
20
|
+
let updatedDecorationSet = decorationSet;
|
|
21
|
+
const codeBlockNodes = getAllCodeBlockNodesInDoc(state);
|
|
22
|
+
|
|
23
|
+
// All the line numbers decorators are refreshed on doc change.
|
|
24
|
+
updatedDecorationSet = updateDecorationSetWithLineNumberDecorators(tr, codeBlockNodes, updatedDecorationSet);
|
|
25
|
+
|
|
26
|
+
// Check to make sure the word wrap decorators are still valid.
|
|
27
|
+
updatedDecorationSet = validateWordWrappedDecorators(tr, codeBlockNodes, updatedDecorationSet);
|
|
28
|
+
return updatedDecorationSet;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Update the decorations set with the line number decorators.
|
|
33
|
+
*/
|
|
34
|
+
export const updateDecorationSetWithLineNumberDecorators = (tr, codeBlockNodes, decorationSet) => {
|
|
35
|
+
let updatedDecorationSet = decorationSet;
|
|
36
|
+
// remove all the line number children from the decorations set. 'undefined, undefined' is used to find() the whole doc.
|
|
37
|
+
const children = updatedDecorationSet.find(undefined, undefined, spec => spec.type === DECORATION_WIDGET_TYPE);
|
|
38
|
+
updatedDecorationSet = updatedDecorationSet.remove(children);
|
|
39
|
+
|
|
40
|
+
// regenerate all the line number for the documents code blocks
|
|
41
|
+
const lineNumberDecorators = [];
|
|
42
|
+
codeBlockNodes.forEach(node => {
|
|
43
|
+
lineNumberDecorators.push(...createLineNumbersDecorations(node));
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
// add the newly generated line numbers to the decorations set
|
|
47
|
+
return updatedDecorationSet.add(tr.doc, [...lineNumberDecorators]);
|
|
48
|
+
};
|
|
49
|
+
export const generateLineAttributesFromNode = node => {
|
|
50
|
+
const {
|
|
51
|
+
node: innerNode,
|
|
52
|
+
pos
|
|
53
|
+
} = node;
|
|
5
54
|
// Get content node
|
|
6
|
-
const contentNode =
|
|
55
|
+
const contentNode = innerNode.content;
|
|
7
56
|
|
|
8
57
|
// Get node text content
|
|
9
58
|
let lineAttributes = [];
|
|
@@ -58,4 +107,58 @@ export const createDecorationSetFromLineAttributes = lineAttributes => {
|
|
|
58
107
|
});
|
|
59
108
|
return widgetDecorations;
|
|
60
109
|
};
|
|
61
|
-
export const createLineNumbersDecorations =
|
|
110
|
+
export const createLineNumbersDecorations = node => createDecorationSetFromLineAttributes(generateLineAttributesFromNode(node));
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* There are edge cases like when a user drags and drops a code block node where the decorator breaks and no longer reflects
|
|
114
|
+
* the correct word wrap state. This function validates that the decorator and the state are in line, otherwise it will
|
|
115
|
+
* retrigger the logic to apply the word wrap decorator.
|
|
116
|
+
*/
|
|
117
|
+
export const validateWordWrappedDecorators = (tr, codeBlockNodes, decorationSet) => {
|
|
118
|
+
let updatedDecorationSet = decorationSet;
|
|
119
|
+
codeBlockNodes.forEach(node => {
|
|
120
|
+
const isCodeBlockWrappedInState = isCodeBlockWordWrapEnabled(node.node);
|
|
121
|
+
const isCodeBlockWrappedByDecorator = getWordWrapDecoratorsFromNodePos(node.pos, decorationSet).length !== 0;
|
|
122
|
+
if (isCodeBlockWrappedInState && !isCodeBlockWrappedByDecorator) {
|
|
123
|
+
updatedDecorationSet = updateDecorationSetWithWordWrappedDecorator(decorationSet, tr, node);
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
return updatedDecorationSet;
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Update the decoration set with the word wrap decorator.
|
|
131
|
+
*/
|
|
132
|
+
export const updateDecorationSetWithWordWrappedDecorator = (decorationSet, tr, node) => {
|
|
133
|
+
if (!node || node.pos === undefined) {
|
|
134
|
+
return decorationSet;
|
|
135
|
+
}
|
|
136
|
+
let updatedDecorationSet = decorationSet;
|
|
137
|
+
const {
|
|
138
|
+
pos,
|
|
139
|
+
node: innerNode
|
|
140
|
+
} = node;
|
|
141
|
+
const isNodeWrapped = isCodeBlockWordWrapEnabled(innerNode);
|
|
142
|
+
if (!isNodeWrapped) {
|
|
143
|
+
const currentWrappedBlockDecorationSet = getWordWrapDecoratorsFromNodePos(pos, updatedDecorationSet);
|
|
144
|
+
updatedDecorationSet = updatedDecorationSet.remove(currentWrappedBlockDecorationSet);
|
|
145
|
+
} else {
|
|
146
|
+
const wrappedBlock = Decoration.node(pos, pos + innerNode.nodeSize, {
|
|
147
|
+
class: codeBlockClassNames.contentFgWrapped
|
|
148
|
+
}, {
|
|
149
|
+
type: DECORATION_WRAPPED_BLOCK_NODE_TYPE
|
|
150
|
+
} // Allows for quick filtering of decorations while using `find`
|
|
151
|
+
);
|
|
152
|
+
updatedDecorationSet = updatedDecorationSet.add(tr.doc, [wrappedBlock]);
|
|
153
|
+
}
|
|
154
|
+
return updatedDecorationSet;
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Get the word wrap decorators for the given node position.
|
|
159
|
+
*/
|
|
160
|
+
export const getWordWrapDecoratorsFromNodePos = (pos, decorationSet) => {
|
|
161
|
+
const codeBlockNodePosition = pos + 1; // We need to add 1 to the position to get the start of the node.
|
|
162
|
+
const currentWrappedBlockDecorationSet = decorationSet.find(codeBlockNodePosition, codeBlockNodePosition, spec => spec.type === DECORATION_WRAPPED_BLOCK_NODE_TYPE);
|
|
163
|
+
return currentWrappedBlockDecorationSet;
|
|
164
|
+
};
|