refactor: block storage (#1952)
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import { NoteType } from '@standardnotes/features'
|
||||
import { createNote } from './../../Utilities/Test/SpecUtils'
|
||||
|
||||
describe('SNNote Tests', () => {
|
||||
@@ -34,4 +35,61 @@ describe('SNNote Tests', () => {
|
||||
|
||||
expect(note.noteType).toBe(undefined)
|
||||
})
|
||||
|
||||
it('should getBlock', () => {
|
||||
const note = createNote({
|
||||
text: 'some text',
|
||||
blocksItem: {
|
||||
blocks: [
|
||||
{
|
||||
id: '123',
|
||||
type: NoteType.Authentication,
|
||||
editorIdentifier: '456',
|
||||
content: 'foo',
|
||||
},
|
||||
],
|
||||
},
|
||||
})
|
||||
|
||||
expect(note.getBlock('123')).toStrictEqual({
|
||||
id: '123',
|
||||
type: NoteType.Authentication,
|
||||
editorIdentifier: '456',
|
||||
content: 'foo',
|
||||
})
|
||||
})
|
||||
|
||||
it('should getBlock with no blocks', () => {
|
||||
const note = createNote({
|
||||
text: 'some text',
|
||||
})
|
||||
|
||||
expect(note.getBlock('123')).toBe(undefined)
|
||||
})
|
||||
|
||||
it('should getBlock with no blocksItem', () => {
|
||||
const note = createNote({
|
||||
text: 'some text',
|
||||
})
|
||||
|
||||
expect(note.getBlock('123')).toBe(undefined)
|
||||
})
|
||||
|
||||
it('should get indexOfBlock', () => {
|
||||
const note = createNote({
|
||||
text: 'some text',
|
||||
blocksItem: {
|
||||
blocks: [
|
||||
{
|
||||
id: '123',
|
||||
type: NoteType.Authentication,
|
||||
editorIdentifier: '456',
|
||||
content: 'foo',
|
||||
},
|
||||
],
|
||||
},
|
||||
})
|
||||
|
||||
expect(note.indexOfBlock({ id: '123' })).toBe(0)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -48,4 +48,17 @@ export class SNNote extends DecryptedItem<NoteContent> implements NoteContentSpe
|
||||
getBlock(id: string): NoteBlock | undefined {
|
||||
return this.blocksItem?.blocks.find((block) => block.id === id)
|
||||
}
|
||||
|
||||
indexOfBlock(block: { id: string }): number | undefined {
|
||||
if (!this.blocksItem) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
const index = this.blocksItem.blocks.findIndex((b) => b.id === block.id)
|
||||
if (index === -1) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
return index
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,41 +4,10 @@ export type NoteBlock = {
|
||||
id: string
|
||||
type: NoteType
|
||||
editorIdentifier: string
|
||||
size?: { width: number; height: number }
|
||||
content: string
|
||||
size?: { width: number; height: number }
|
||||
}
|
||||
|
||||
export interface NoteBlocks {
|
||||
blocks: NoteBlock[]
|
||||
}
|
||||
|
||||
export function bracketSyntaxForBlock(block: { id: NoteBlock['id'] }): { open: string; close: string } {
|
||||
return {
|
||||
open: `<Block id=${block.id}>`,
|
||||
close: `</Block id=${block.id}>`,
|
||||
}
|
||||
}
|
||||
|
||||
export function stringIndexOfBlock(
|
||||
text: string,
|
||||
block: { id: NoteBlock['id'] },
|
||||
): { begin: number; end: number } | undefined {
|
||||
const brackets = bracketSyntaxForBlock(block)
|
||||
|
||||
const startIndex = text.indexOf(brackets.open)
|
||||
if (startIndex === -1) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
const endIndex = text.indexOf(brackets.close) + brackets.close.length
|
||||
|
||||
return {
|
||||
begin: startIndex,
|
||||
end: endIndex,
|
||||
}
|
||||
}
|
||||
|
||||
export function blockContentToNoteTextRendition(block: { id: NoteBlock['id'] }, content: string): string {
|
||||
const brackets = bracketSyntaxForBlock(block)
|
||||
return `${brackets.open}${content}${brackets.close}`
|
||||
}
|
||||
|
||||
@@ -21,4 +21,99 @@ describe('note mutator', () => {
|
||||
|
||||
expect(result.content.editorIdentifier).toEqual(FeatureIdentifier.MarkdownProEditor)
|
||||
})
|
||||
|
||||
it('should addBlock to new note', () => {
|
||||
const note = createNote({})
|
||||
const mutator = new NoteMutator(note, MutationType.NoUpdateUserTimestamps)
|
||||
mutator.addBlock({ type: NoteType.Code, id: '123', editorIdentifier: 'markdown', content: 'test' })
|
||||
const result = mutator.getResult()
|
||||
|
||||
expect(result.content.blocksItem).toEqual({
|
||||
blocks: [{ type: NoteType.Code, id: '123', editorIdentifier: 'markdown', content: 'test' }],
|
||||
})
|
||||
})
|
||||
|
||||
it('should addBlock to existing note', () => {
|
||||
const note = createNote({
|
||||
blocksItem: {
|
||||
blocks: [{ type: NoteType.Code, id: '123', editorIdentifier: 'markdown', content: 'test' }],
|
||||
},
|
||||
})
|
||||
const mutator = new NoteMutator(note, MutationType.NoUpdateUserTimestamps)
|
||||
mutator.addBlock({ type: NoteType.RichText, id: '456', editorIdentifier: 'richy', content: 'test' })
|
||||
const result = mutator.getResult()
|
||||
|
||||
expect(result.content.blocksItem).toEqual({
|
||||
blocks: [
|
||||
{ type: NoteType.Code, id: '123', editorIdentifier: 'markdown', content: 'test' },
|
||||
{ type: NoteType.RichText, id: '456', editorIdentifier: 'richy', content: 'test' },
|
||||
],
|
||||
})
|
||||
})
|
||||
|
||||
it('should removeBlock', () => {
|
||||
const note = createNote({
|
||||
blocksItem: {
|
||||
blocks: [
|
||||
{ type: NoteType.Code, id: '123', editorIdentifier: 'markdown', content: 'test' },
|
||||
{ type: NoteType.Code, id: '456', editorIdentifier: 'markdown', content: 'test' },
|
||||
],
|
||||
},
|
||||
})
|
||||
const mutator = new NoteMutator(note, MutationType.NoUpdateUserTimestamps)
|
||||
mutator.removeBlock({ type: NoteType.Code, id: '123', editorIdentifier: 'markdown', content: 'test' })
|
||||
const result = mutator.getResult()
|
||||
|
||||
expect(result.content.blocksItem).toEqual({
|
||||
blocks: [{ type: NoteType.Code, id: '456', editorIdentifier: 'markdown', content: 'test' }],
|
||||
})
|
||||
})
|
||||
|
||||
it('should changeBlockContent', () => {
|
||||
const note = createNote({
|
||||
blocksItem: {
|
||||
blocks: [
|
||||
{ type: NoteType.Code, id: '123', editorIdentifier: 'markdown', content: 'old content 1' },
|
||||
{ type: NoteType.Code, id: '456', editorIdentifier: 'markdown', content: 'old content 2' },
|
||||
],
|
||||
},
|
||||
})
|
||||
const mutator = new NoteMutator(note, MutationType.NoUpdateUserTimestamps)
|
||||
mutator.changeBlockContent('123', 'new content')
|
||||
const result = mutator.getResult()
|
||||
|
||||
expect(result.content.blocksItem).toEqual({
|
||||
blocks: [
|
||||
{ type: NoteType.Code, id: '123', editorIdentifier: 'markdown', content: 'new content' },
|
||||
{ type: NoteType.Code, id: '456', editorIdentifier: 'markdown', content: 'old content 2' },
|
||||
],
|
||||
})
|
||||
})
|
||||
|
||||
it('should changeBlockSize', () => {
|
||||
const note = createNote({
|
||||
blocksItem: {
|
||||
blocks: [
|
||||
{ type: NoteType.Code, id: '123', editorIdentifier: 'markdown', content: 'test' },
|
||||
{ type: NoteType.Code, id: '456', editorIdentifier: 'markdown', content: 'test' },
|
||||
],
|
||||
},
|
||||
})
|
||||
const mutator = new NoteMutator(note, MutationType.NoUpdateUserTimestamps)
|
||||
mutator.changeBlockSize('123', { width: 10, height: 20 })
|
||||
const result = mutator.getResult()
|
||||
|
||||
expect(result.content.blocksItem).toEqual({
|
||||
blocks: [
|
||||
{
|
||||
type: NoteType.Code,
|
||||
id: '123',
|
||||
editorIdentifier: 'markdown',
|
||||
content: 'test',
|
||||
size: { width: 10, height: 20 },
|
||||
},
|
||||
{ type: NoteType.Code, id: '456', editorIdentifier: 'markdown', content: 'test' },
|
||||
],
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -5,8 +5,8 @@ import { NoteToNoteReference } from '../../Abstract/Reference/NoteToNoteReferenc
|
||||
import { ContentType } from '@standardnotes/common'
|
||||
import { ContentReferenceType } from '../../Abstract/Item'
|
||||
import { FeatureIdentifier, NoteType } from '@standardnotes/features'
|
||||
import { blockContentToNoteTextRendition, bracketSyntaxForBlock, NoteBlock, stringIndexOfBlock } from './NoteBlocks'
|
||||
import { removeFromArray } from '@standardnotes/utils'
|
||||
import { NoteBlock } from './NoteBlocks'
|
||||
import { filterFromArray } from '@standardnotes/utils'
|
||||
|
||||
export class NoteMutator extends DecryptedItemMutator<NoteContent> {
|
||||
set title(title: string) {
|
||||
@@ -51,10 +51,6 @@ export class NoteMutator extends DecryptedItemMutator<NoteContent> {
|
||||
}
|
||||
|
||||
this.mutableContent.blocksItem.blocks.push(block)
|
||||
|
||||
const brackets = bracketSyntaxForBlock(block)
|
||||
|
||||
this.text += `${brackets.open}${block.content}${brackets.close}`
|
||||
}
|
||||
|
||||
removeBlock(block: NoteBlock): void {
|
||||
@@ -62,37 +58,24 @@ export class NoteMutator extends DecryptedItemMutator<NoteContent> {
|
||||
return
|
||||
}
|
||||
|
||||
removeFromArray(this.mutableContent.blocksItem.blocks, block)
|
||||
|
||||
const location = stringIndexOfBlock(this.mutableContent.text, block)
|
||||
|
||||
if (location) {
|
||||
this.mutableContent.text = this.mutableContent.text.slice(location.begin, location.end)
|
||||
}
|
||||
filterFromArray(this.mutableContent.blocksItem.blocks, { id: block.id })
|
||||
}
|
||||
|
||||
changeBlockContent(blockId: string, content: string): void {
|
||||
const block = this.mutableContent.blocksItem?.blocks.find((b) => b.id === blockId)
|
||||
const blockIndex = this.mutableContent.blocksItem?.blocks.findIndex((b) => {
|
||||
return b.id === blockId
|
||||
})
|
||||
|
||||
if (blockIndex == null || blockIndex === -1) {
|
||||
return
|
||||
}
|
||||
|
||||
const block = this.mutableContent.blocksItem?.blocks[blockIndex]
|
||||
if (!block) {
|
||||
return
|
||||
}
|
||||
|
||||
block.content = content
|
||||
|
||||
const location = stringIndexOfBlock(this.mutableContent.text, block)
|
||||
|
||||
if (location) {
|
||||
const replaceRange = (s: string, start: number, end: number, substitute: string) => {
|
||||
return s.substring(0, start) + substitute + s.substring(end)
|
||||
}
|
||||
|
||||
this.mutableContent.text = replaceRange(
|
||||
this.mutableContent.text,
|
||||
location.begin,
|
||||
location.end,
|
||||
blockContentToNoteTextRendition({ id: blockId }, content),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
changeBlockSize(blockId: string, size: { width: number; height: number }): void {
|
||||
|
||||
Reference in New Issue
Block a user