aboutsummaryrefslogtreecommitdiff
path: root/src/new_fields/RichTextUtils.ts
diff options
context:
space:
mode:
Diffstat (limited to 'src/new_fields/RichTextUtils.ts')
-rw-r--r--src/new_fields/RichTextUtils.ts115
1 files changed, 85 insertions, 30 deletions
diff --git a/src/new_fields/RichTextUtils.ts b/src/new_fields/RichTextUtils.ts
index 555c41b67..ab5e677c8 100644
--- a/src/new_fields/RichTextUtils.ts
+++ b/src/new_fields/RichTextUtils.ts
@@ -14,9 +14,10 @@ import { schema } from "../client/util/RichTextSchema";
import { GooglePhotos } from "../client/apis/google_docs/GooglePhotosClientUtils";
import { SchemaHeaderField } from "./SchemaHeaderField";
import { DocServer } from "../client/DocServer";
-import { Cast } from "./Types";
+import { Cast, StrCast } from "./Types";
import { Id } from "./FieldSymbols";
import { DocumentView } from "../client/views/nodes/DocumentView";
+import { AssertionError } from "assert";
export namespace RichTextUtils {
@@ -109,45 +110,78 @@ export namespace RichTextUtils {
return { text, requests };
};
+ interface ImageTemplate {
+ width: number;
+ title: string;
+ url: string;
+ }
+
+ const parseInlineObjects = async (document: docs_v1.Schema$Document): Promise<Map<string, ImageTemplate>> => {
+ const inlineObjectMap = new Map<string, ImageTemplate>();
+ const inlineObjects = document.inlineObjects;
+
+ if (inlineObjects) {
+ const objects = Object.keys(inlineObjects).map(objectId => inlineObjects[objectId]);
+ const mediaItems: MediaItem[] = objects.map(object => {
+ const embeddedObject = object.inlineObjectProperties!.embeddedObject!;
+ const baseUrl = embeddedObject.imageProperties!.contentUri!;
+ const filename = `upload_${Utils.GenerateGuid()}.png`;
+ return { baseUrl, filename };
+ });
+
+ const uploads = await PostToServer(RouteStore.googlePhotosMediaDownload, { mediaItems });
+
+ if (uploads.length !== mediaItems.length) {
+ throw new AssertionError({ expected: mediaItems.length, actual: uploads.length, message: "Error with internally uploading inlineObjects!" });
+ }
+
+ for (let i = 0; i < objects.length; i++) {
+ const object = objects[i];
+ const { fileNames } = uploads[i];
+ const embeddedObject = object.inlineObjectProperties!.embeddedObject!;
+ const size = embeddedObject.size!;
+ const width = size.width!.magnitude!;
+ const url = Utils.fileUrl(fileNames.clean);
+
+ inlineObjectMap.set(object.objectId!, {
+ title: embeddedObject.title || `Imported Image from ${document.title}`,
+ width,
+ url
+ });
+ }
+ }
+ return inlineObjectMap;
+ };
+
type BulletPosition = { value: number, sinks: number };
interface MediaItem {
baseUrl: string;
filename: string;
- width: number;
}
- export const Import = async (documentId: GoogleApiClientUtils.Docs.DocumentId): Promise<Opt<GoogleApiClientUtils.Docs.ImportResult>> => {
+
+ export const Import = async (documentId: GoogleApiClientUtils.Docs.DocumentId, textNote: Doc): Promise<Opt<GoogleApiClientUtils.Docs.ImportResult>> => {
const document = await GoogleApiClientUtils.Docs.retrieve({ documentId });
if (!document) {
return undefined;
}
-
+ const inlineObjectMap = await parseInlineObjects(document);
const title = document.title!;
const { text, paragraphs } = GoogleApiClientUtils.Docs.Utils.extractText(document);
let state = FormattedTextBox.blankState();
let structured = parseLists(paragraphs);
- const inline = document.inlineObjects;
- let inlineUrls: MediaItem[] = [];
- if (inline) {
- inlineUrls = Object.keys(inline).map(key => {
- const embedded = inline[key].inlineObjectProperties!.embeddedObject!;
- const baseUrl = embedded.imageProperties!.contentUri!;
- const filename = `upload_${Utils.GenerateGuid()}.png`;
- const width = embedded.size!.width!.magnitude!;
- return { baseUrl, filename, width };
- });
- }
let position = 3;
let lists: ListGroup[] = [];
const indentMap = new Map<ListGroup, BulletPosition[]>();
let globalOffset = 0;
- const nodes = structured.map(element => {
+ const nodes: Node<any>[] = [];
+ for (let element of structured) {
if (Array.isArray(element)) {
lists.push(element);
let positions: BulletPosition[] = [];
let items = element.map(paragraph => {
- let item = listItem(state.schema, paragraph.runs);
+ let item = listItem(state.schema, paragraph.contents);
let sinks = paragraph.bullet!;
positions.push({
value: position + globalOffset,
@@ -158,13 +192,26 @@ export namespace RichTextUtils {
return item;
});
indentMap.set(element, positions);
- return list(state.schema, items);
+ nodes.push(list(state.schema, items));
} else {
- let paragraph = paragraphNode(state.schema, element.runs);
- position += paragraph.nodeSize;
- return paragraph;
+ if (element.contents.some(child => "inlineObjectId" in child)) {
+ let node: Node<any>;
+ for (const child of element.contents) {
+ if ("inlineObjectId" in child) {
+ node = imageNode(state.schema, inlineObjectMap.get(child.inlineObjectId!)!, textNote);
+ } else {
+ node = paragraphNode(state.schema, [child]);
+ }
+ nodes.push(node);
+ position += node.nodeSize;
+ }
+ } else {
+ let paragraph = paragraphNode(state.schema, element.contents);
+ nodes.push(paragraph);
+ position += paragraph.nodeSize;
+ }
}
- });
+ }
state = state.apply(state.tr.replaceWith(0, 2, nodes));
let sink = sinkListItem(state.schema.nodes.list_item);
@@ -179,14 +226,6 @@ export namespace RichTextUtils {
}
}
- const uploads = await PostToServer(RouteStore.googlePhotosMediaDownload, { mediaItems: inlineUrls });
- for (let i = 0; i < uploads.length; i++) {
- const src = Utils.fileUrl(uploads[i].fileNames.clean);
- const width = inlineUrls[i].width;
- const imageNode = schema.nodes.image.create({ src, width });
- state = state.apply(state.tr.insert(0, imageNode));
- }
-
return { title, text, state };
};
@@ -226,6 +265,22 @@ export namespace RichTextUtils {
return schema.node("paragraph", null, fragment);
};
+ const imageNode = (schema: any, image: ImageTemplate, textNote: Doc) => {
+ const { url: src, width } = image;
+ let docid: string;
+ const guid = Utils.GenerateDeterministicGuid(src);
+ const backingDocId = StrCast(textNote[guid]);
+ if (!backingDocId) {
+ const backingDoc = Docs.Create.ImageDocument(src, { width: 300, height: 300 });
+ DocumentView.makeCustomViewClicked(backingDoc);
+ docid = backingDoc[Id];
+ textNote[guid] = docid;
+ } else {
+ docid = backingDocId;
+ }
+ return schema.node("image", { src, width, docid });
+ };
+
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;