Skip to content

Commit

Permalink
feat: extension-code-block check for multi block changes
Browse files Browse the repository at this point in the history
  • Loading branch information
ifiokjr committed Jul 12, 2019
1 parent 5f4b2cc commit 908c823
Show file tree
Hide file tree
Showing 7 changed files with 58 additions and 12 deletions.
2 changes: 2 additions & 0 deletions @remirror/extension-code-block/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,14 @@
"@remirror/core": "0.3.0",
"@types/prismjs": "^1.16.0",
"@types/prosemirror-state": "^1.2.3",
"@types/prosemirror-transform": "^1.1.0",
"@types/prosemirror-view": "^1.3.2",
"@types/react-syntax-highlighter": "^10.2.1",
"@types/refractor": "^2.8.0",
"emotion": "^10.0.14",
"prettier": "^1.18.2",
"prosemirror-state": "^1.2.3",
"prosemirror-transform": "^1.1.3",
"prosemirror-view": "^1.9.11",
"react-syntax-highlighter": "^11.0.1",
"refractor": "^2.9.0"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ describe('plugin', () => {
});

// TODO implement the functionality to update multiple codeBlocks at once.
it.only('updates when multiple changes occur', () => {
it('updates when multiple changes occur', () => {
const tsBlock = codeBlock({ language: 'typescript' });
const { overwrite } = add(doc(tsBlock(`const a = 'test';`), tsBlock(`let b;`)));
expect(dom.innerHTML).toMatchSnapshot();
Expand Down
51 changes: 44 additions & 7 deletions @remirror/extension-code-block/src/code-block-state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@ import {
PosParams,
TransactionParams,
} from '@remirror/core';
import { Step } from 'prosemirror-transform';
import { DecorationSet } from 'prosemirror-view';
import { createDecorations } from './code-block-utils';
import { createDecorations, posWithinRange } from './code-block-utils';

export class CodeBlockState {
/**
Expand All @@ -37,19 +38,57 @@ export class CodeBlockState {
return this;
}

/**
* Recreate all the decorations again
*/
private refreshDecorationSet({ blocks, node }: RefreshDecorationSetParams) {
const decorations = createDecorations(blocks);
this.decorationSet = DecorationSet.create(node, decorations);
this.blocks = blocks;
}

/**
* Currently this is very primitive and simply re-renders all the blocks if more than one block has changed.
* Or if the length of the blocks has changed.
* Run through each step in the transaction and check whether the change
* occurred within one of the active code blocks.
*/
private hasChangedBlocks(steps: Step[], threshold = 2) {
let changes = 0;

// Urm yeah this is a loop within a loop within a loop and it makes me head hurt.
for (const { node, pos: from } of this.blocks) {
let hasChanged = false;
for (const step of steps) {
step.getMap().forEach((oldStart, oldEnd) => {
const to = from + node.nodeSize;
if (posWithinRange({ from, to, pos: oldStart }) || posWithinRange({ from, to, pos: oldEnd })) {
hasChanged = true;
}
});

if (hasChanged) {
break;
}
}

if (hasChanged) {
changes++;
}

if (changes >= threshold) {
return true;
}
}

return false;
}

/**
* Check that either a new block has been added or more than one block has changed.
* This is very simplistic and in the future should only update the changed blocks.
*/
private updateBlocks({ tr }: EditorStateParams & TransactionParams) {
const blocks = findChildrenByNode({ node: tr.doc, type: this.type });
if (blocks.length !== this.blocks.length) {
if (blocks.length !== this.blocks.length || (blocks.length > 1 && this.hasChangedBlocks(tr.steps))) {
this.refreshDecorationSet({ blocks, node: tr.doc });
return false;
}
Expand All @@ -62,20 +101,18 @@ export class CodeBlockState {
*/
public apply({ tr, prevState, newState }: ApplyParams) {
if (!tr.docChanged) {
console.log('nothing changed');
return this;
}

// Check for multi block changes, if so refresh every codeBlock
if (!this.updateBlocks({ state: newState, tr })) {
console.log('nothing to change');
return this;
}

this.decorationSet = this.decorationSet.map(tr.mapping, tr.doc);

const current = getNodeInformationFromState(newState);
const previous = getNodeInformationFromState(prevState);

this.manageDecorationSet({ current, previous, tr });

return this;
Expand Down
9 changes: 8 additions & 1 deletion @remirror/extension-code-block/src/code-block-utils.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { flattenArray, FromToParams, NodeWithPosition, TextParams } from '@remirror/core';
import { flattenArray, FromToParams, NodeWithPosition, PosParams, TextParams } from '@remirror/core';
import { Decoration } from 'prosemirror-view';
import refractor, { RefractorNode } from 'refractor/core';

Expand Down Expand Up @@ -78,3 +78,10 @@ const getPositionedRefractorNodes = ({ node, pos }: NodeWithPosition) => {

return flattenArray<ParsedRefractorNode>(parsedRefractorNodes).map(mapper);
};

interface PosWithinRangeParams extends PosParams, FromToParams {}

/**
* Check if the position is within the range.
*/
export const posWithinRange = ({ from, to, pos }: PosWithinRangeParams) => from <= pos && to >= pos;
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
import debounce from 'debounce';
import { collab, getVersion, receiveTransaction, sendableSteps } from 'prosemirror-collab';
import { Step } from 'prosemirror-transform';
import { CollaborationAttrs, CollaborationExtensionOptions } from './types';
import { CollaborationAttrs, CollaborationExtensionOptions } from './collaboration-types';

/**
* The collaboration extension adds collaborative functionality to your editor.
Expand Down
4 changes: 2 additions & 2 deletions @remirror/extension-collaboration/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
export * from './collaboration.extension';
export * from './types';
export * from './collaboration-extension';
export * from './collaboration-types';

0 comments on commit 908c823

Please sign in to comment.