Untitled
unknown
typescript
14 days ago
5.9 kB
6
Indexable
export class PostFormModel { postPartsAtom = reatomArray<AtomMut<PostPart>>([]) .pipe(withReset()) .pipe(withInit(() => [createPartAtom(generateTextPart()) as AtomMut<PostPart>])) .pipe(withSetInterceptor(normalizeParts)) focusedTextPart = atom<FocusedTextPartValue>(null).pipe(withReset()) activeSidebar = atom<ActiveSidebarInfo | null>(null).pipe(withReset()) scheduledDatetime = atom<Date | null>(null).pipe(withReset()) constructor(post?: CommunityPost) { if (post) { const segments = splitKeep(post.content, /(\[image]|\[poll]|\[book]|\[bookmark])/g) const parts: PostPart[] = [] let imageIdx = 0 for (const segment of segments) { if (segment === '[book]') { parts.push(generateBookPart(post.book_meta)) } else if (segment === '[bookmark]') { parts.push(generateBookmarkPart(post.bookmark_meta)) } else if (segment === '[poll]') { parts.push(generatePollPart(new PollFormModel({ title: post.poll_meta.title, multipleChoices: post.poll_meta.multiple, choices: post.poll_meta.options.map(opt => opt.option), }))) } else if (segment === '[image]') { // parts.push(atom(generateImagesPart(post.images[imageIdx]))) imageIdx++ } else { parts.push(generateTextPart(segment.trim().replaceAll('\r\n', '\n'))) } } this.postPartsAtom.change(ctx, parts.map(part => createPartAtom(part))) } } resetAll = action((ctx) => { this.postPartsAtom.reset(ctx) this.focusedTextPart.reset(ctx) this.activeSidebar.reset(ctx) this.scheduledDatetime.reset(ctx) }) setFocusedTextAtom = action((ctx, part: AtomMut<TextPart>, ref: HTMLTextAreaElement | null) => { this.focusedTextPart(ctx, [part, ref]) }) unsetFocusedTextAtom = action((ctx) => { this.focusedTextPart(ctx, null) }) insertMedia = action((ctx, part: PostPart, focusedText: FocusedTextPartValue) => { const newAtoms = [createPartAtom(part)] const parts = ctx.get(this.postPartsAtom) if (focusedText) { const [focusedTextAtom, focusedTextRef] = focusedText const focusedTextAtomIdx = parts.findIndex(item => item === focusedTextAtom) const focusPosition = focusedTextRef?.selectionStart if (focusedTextAtomIdx > -1 && focusPosition !== undefined) { const textValue = ctx.get(focusedTextAtom) const [before, after] = splitInPosition(textValue.content, focusPosition) before.trim().length && newAtoms.unshift(createPartAtom(generateTextPart(before.trim())) as AtomMut<PostPart>) after.trim().length && newAtoms.push(createPartAtom(generateTextPart(after.trim())) as AtomMut<PostPart>) } this.postPartsAtom.change(ctx, [ ...parts.slice(0, focusedTextAtomIdx), ...newAtoms, ...parts.slice(focusedTextAtomIdx + 1), ]) return } this.postPartsAtom.change(ctx, [...parts, ...newAtoms]) }) insertPart = action((ctx, {atom, i}: { atom: AtomMut<PostPart>, i: number }) => { this.postPartsAtom.change(ctx, v => [...v.slice(0, i), atom, ...v.slice(i)]) }) addPart = action((ctx, part: PostPart) => { const newAtoms = [createPartAtom(part)] if (part.type !== 'text') { newAtoms.push(createPartAtom(generateTextPart('')) as AtomMut<PostPart>) } this.postPartsAtom.change(ctx, v => [...v, ...newAtoms]) }) removePart = action((ctx, id: string) => { const partsValue = ctx.get(this.postPartsAtom) const removingI = partsValue.findIndex(atom => ctx.get(atom).id === id) this.postPartsAtom.change(ctx, [...partsValue.slice(0, removingI), ...partsValue.slice(removingI + 1)]) }) rearrangeParts = action(ctx => { this.postPartsAtom.change(ctx, v => v) }) getSerialised() { const totalImages: File[] = [] let totalText = '' let poll: PollForm | undefined let bookId: Book["id"] | undefined let bookmarkId: Bookmark["id"] | undefined const partsValue = ctx.get(this.postPartsAtom) for (const partAtom of partsValue) { const partValue = ctx.get(partAtom) switch (partValue.type) { case 'text': totalText += partValue.content break case 'images': totalText += partValue.images.map(() => '[image]').join('') totalImages.push(...partValue.images.map(item => item.file)) break case 'book': totalText += '[book]' bookId = partValue.book.id break case 'audio_bookmark': totalText += '[bookmark]' bookmarkId = partValue.bookmark.id break case 'poll': poll = partValue.poll.toObject() break } } return { totalText, totalImages, bookId, bookmarkId, poll, publicationDatetime: ctx.get(this.scheduledDatetime), } } symbolsCount = atom(ctx => ctx.spy(this.postPartsAtom) .reduce((count, partAtom) => { const part = ctx.spy(partAtom) return part.type === 'text' ? count + part.content?.length : count }, 0)) books = atom(ctx => ctx.spy(this.postPartsAtom) .map(partAtom => ctx.get(partAtom)) .filter(part => part?.type === 'book')) bookmarks = atom(ctx => ctx.spy(this.postPartsAtom) .map(partAtom => ctx.get(partAtom)) .filter(part => part?.type === 'audio_bookmark')) isEmpty = atom(ctx => ctx.spy(this.postPartsAtom) .map(partAtom => ctx.spy(partAtom)) .find(part => { if (part.type === 'text') return part.content.trim().length if (part.type === 'images') return part.images.length return true }) === undefined) lastPostPart = atom<PostPart | undefined>(ctx => { const lastAtom = ctx.spy(this.postPartsAtom).at(-1) return lastAtom ? ctx.spy(lastAtom) : undefined }) }
Editor is loading...
Leave a Comment