diff options
author | Sam Wilkins <samwilkins333@gmail.com> | 2019-08-30 15:51:13 -0400 |
---|---|---|
committer | Sam Wilkins <samwilkins333@gmail.com> | 2019-08-30 15:51:13 -0400 |
commit | c9a7d747916c31730f71479d8e516ba0ed2c658f (patch) | |
tree | 2cd03764a446c81de91638fefac3812fcc2a67f5 /src | |
parent | c53d721dd95bdb4ccddc7a89dbdda72a88d29058 (diff) |
complete transfer except for list items
Diffstat (limited to 'src')
-rw-r--r-- | src/client/apis/google_docs/GoogleApiClientUtils.ts | 2 | ||||
-rw-r--r-- | src/client/views/nodes/FormattedTextBox.tsx | 11 | ||||
-rw-r--r-- | src/new_fields/RichTextUtils.ts | 89 |
3 files changed, 57 insertions, 45 deletions
diff --git a/src/client/apis/google_docs/GoogleApiClientUtils.ts b/src/client/apis/google_docs/GoogleApiClientUtils.ts index 9bf3cae38..fdd708e31 100644 --- a/src/client/apis/google_docs/GoogleApiClientUtils.ts +++ b/src/client/apis/google_docs/GoogleApiClientUtils.ts @@ -45,7 +45,7 @@ export namespace GoogleApiClientUtils { export interface ImportResult { title: string; text: string; - data: RichTextField; + state: EditorState; } export interface CreateOptions { diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 83011e590..6af5c8f0b 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -38,6 +38,7 @@ import { DictationManager } from '../../util/DictationManager'; import { ReplaceStep } from 'prosemirror-transform'; import { DocumentType } from '../../documents/DocumentTypes'; import { RichTextUtils } from '../../../new_fields/RichTextUtils'; +import * as _ from "lodash"; library.add(faEdit); library.add(faSmile, faTextHeight, faUpload); @@ -481,7 +482,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe let pullSuccess = false; if (exportState !== undefined) { pullSuccess = true; - dataDoc.data = exportState.data; + dataDoc.data = new RichTextField(JSON.stringify(exportState.state.toJSON())); setTimeout(() => { if (this._editorView) { let state = this._editorView.state; @@ -500,11 +501,9 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe checkState = (exportState: Opt<GoogleApiClientUtils.Docs.ImportResult>, dataDoc: Doc) => { if (exportState && this._editorView) { - let storedPlainText = RichTextUtils.ToPlainText(this._editorView.state) + "\n"; - let receivedPlainText = exportState.text; - let storedTitle = dataDoc.title; - let receivedTitle = exportState.title; - let unchanged = storedPlainText === receivedPlainText && storedTitle === receivedTitle; + let equalContent = _.isEqual(this._editorView.state.doc, exportState.state.doc); + let equalTitles = dataDoc.title === exportState.title; + let unchanged = equalContent && equalTitles; dataDoc.unchanged = unchanged; DocumentDecorations.Instance.setPullState(unchanged); } diff --git a/src/new_fields/RichTextUtils.ts b/src/new_fields/RichTextUtils.ts index 4ca51d311..bc338e45b 100644 --- a/src/new_fields/RichTextUtils.ts +++ b/src/new_fields/RichTextUtils.ts @@ -5,6 +5,7 @@ import { docs_v1 } from "googleapis"; import { GoogleApiClientUtils } from "../client/apis/google_docs/GoogleApiClientUtils"; import { FormattedTextBox } from "../client/views/nodes/FormattedTextBox"; import { Opt } from "./Doc"; +import * as Color from "color"; export namespace RichTextUtils { @@ -96,73 +97,85 @@ export namespace RichTextUtils { }; export const Import = async (documentId: GoogleApiClientUtils.Docs.DocumentId): Promise<Opt<GoogleApiClientUtils.Docs.ImportResult>> => { - let Docs = GoogleApiClientUtils.Docs; - let document = await Docs.retrieve({ documentId }); - + const Docs = GoogleApiClientUtils.Docs; + const document = await Docs.retrieve({ documentId }); if (!document) { return undefined; } - let title = document.title!; - - let { text, runs } = Docs.Utils.extractText(document); - let segments = runs[Symbol.iterator](); + const title = document.title!; + const { text, runs } = Docs.Utils.extractText(document); + const segments = runs[Symbol.iterator](); let state = FormattedTextBox.blankState(); - let breaks: number[] = []; - let from = 0; + const schema = state.schema; + const nodes: Node[] = []; + let result = segments.next(); while (!result.done) { let run = result.value; - let fragment = run.content!; - if (fragment.hasNewline()) { - let trimmed = fragment.removeTrailingNewlines(); - if (fragment.length === 1) { - breaks.push(from); - } else { - let content = Fragment.from(state.schema.text(trimmed, styleToMarks(state.schema, run.textStyle))); - let node = state.schema.node("paragraph", null, content); - state = state.apply(state.tr.insert(from, node)); - from += node.nodeSize; - } + if (run.content!.hasNewline()) { + addParagraph(nodes, schema, textNode(schema, run)); result = segments.next(); } else { - let nodes: Node[] = []; - nodes.push(state.schema.text(fragment, styleToMarks(state.schema, run.textStyle))); + const inner: Node[] = []; + inner.push(textNode(schema, run)); result = segments.next(); while (!result.done) { run = result.value; - fragment = run.content!; - let trimmed = fragment.removeTrailingNewlines(); - nodes.push(state.schema.text(trimmed, styleToMarks(state.schema, run.textStyle))); - if (fragment.hasNewline()) { - let node = state.schema.node("paragraph", null, Fragment.fromArray(nodes)); - state = state.apply(state.tr.insert(from, node)); - from += node.nodeSize; - result = segments.next(); + inner.push(textNode(schema, run)); + result = segments.next(); + if (run.content!.hasNewline()) { + addParagraph(nodes, schema, inner); break; } - result = segments.next(); } if (result.done) { break; } } } - breaks.forEach(position => state = state.apply(state.tr.insert(position, state.schema.node("paragraph")))); - let data = new RichTextField(JSON.stringify(state.toJSON())); - return { title, text, data }; + state = state.apply(state.tr.replaceWith(0, 2, nodes)); + return { title, text, state }; + }; + + const addParagraph = (list: Node[], schema: any, content?: Node[] | Node) => { + list.push(schema.node("paragraph", null, content ? Fragment.from(content) : null)); }; + const textNode = (schema: any, run: docs_v1.Schema$TextRun) => { + let text = run.content!.removeTrailingNewlines(); + return text.length ? schema.text(text, styleToMarks(schema, run.textStyle)) : undefined; + }; + + const MarkMapping = new Map<keyof docs_v1.Schema$TextStyle, string>([ + ["bold", "strong"], + ["italic", "em"], + ["foregroundColor", "pFontColor"] + ]); + const styleToMarks = (schema: any, textStyle?: docs_v1.Schema$TextStyle) => { if (!textStyle) { return undefined; } let marks: Mark[] = []; - if (textStyle.link) { - let href = textStyle.link.url; - marks.push(schema.mark(schema.marks.link, { href })); - } + Object.keys(textStyle).forEach(key => { + let value: any; + let targeted = key as keyof docs_v1.Schema$TextStyle; + if (value = textStyle[targeted]) { + let attributes: any = {}; + let converted = MarkMapping.get(targeted) || targeted; + + value.url && (attributes.href = value.url); + if (value.color) { + let object: { [key: string]: number } = value.color.rgbColor; + attributes.color = Color.rgb(Object.values(object).map(value => value * 255)).hex(); + } + + let mark = schema.mark(schema.marks[converted], attributes); + mark && marks.push(mark); + } + }); return marks; }; |