aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/collections/CollectionSubView.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/views/collections/CollectionSubView.tsx')
-rw-r--r--src/client/views/collections/CollectionSubView.tsx375
1 files changed, 212 insertions, 163 deletions
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index 8679c8bd1..70927cf22 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -1,12 +1,11 @@
-import { action, computed, IReactionDisposer, reaction, trace } from "mobx";
-import * as rp from 'request-promise';
+import { action, computed, IReactionDisposer, reaction } from "mobx";
import CursorField from "../../../new_fields/CursorField";
-import { Doc, DocListCast, Opt } from "../../../new_fields/Doc";
+import { Doc, DocListCast, Opt, WidthSym, HeightSym } from "../../../new_fields/Doc";
import { Id } from "../../../new_fields/FieldSymbols";
import { List } from "../../../new_fields/List";
import { listSpec } from "../../../new_fields/Schema";
import { ScriptField } from "../../../new_fields/ScriptField";
-import { Cast } from "../../../new_fields/Types";
+import { Cast, StrCast } from "../../../new_fields/Types";
import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils";
import { Utils } from "../../../Utils";
import { DocServer } from "../../DocServer";
@@ -25,6 +24,7 @@ import { ImageUtils } from "../../util/Import & Export/ImageUtils";
import { Networking } from "../../Network";
import { GestureUtils } from "../../../pen-gestures/GestureUtils";
import { InteractionUtils } from "../../util/InteractionUtils";
+import { Upload } from "../../../server/SharedMediaTypes";
export interface CollectionViewProps extends FieldViewProps {
addDocument: (document: Doc) => boolean;
@@ -33,7 +33,6 @@ export interface CollectionViewProps extends FieldViewProps {
PanelWidth: () => number;
PanelHeight: () => number;
VisibleHeight?: () => number;
- chromeCollapsed: boolean;
setPreviewCursor?: (func: (x: number, y: number, drag: boolean) => void) => void;
fieldKey: string;
}
@@ -41,22 +40,27 @@ export interface CollectionViewProps extends FieldViewProps {
export interface SubCollectionViewProps extends CollectionViewProps {
CollectionView: Opt<CollectionView>;
children?: never | (() => JSX.Element[]) | React.ReactNode;
+ overrideDocuments?: Doc[]; // used to override the documents shown by the sub collection to an explict list (see LinkBox)
+ ignoreFields?: string[]; // used in TreeView to ignore specified fields (see LinkBox)
isAnnotationOverlay?: boolean;
annotationsKey: string;
+ layoutEngine?: () => string;
}
-export function CollectionSubView<T>(schemaCtor: (doc: Doc) => T) {
- class CollectionSubView extends DocComponent<SubCollectionViewProps, T>(schemaCtor) {
+export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?: X) {
+ class CollectionSubView extends DocComponent<X & SubCollectionViewProps, T>(schemaCtor) {
private dropDisposer?: DragManager.DragDropDisposer;
private gestureDisposer?: GestureUtils.GestureEventDisposer;
protected multiTouchDisposer?: InteractionUtils.MultiTouchEventDisposer;
private _childLayoutDisposer?: IReactionDisposer;
+ protected _mainCont?: HTMLDivElement;
protected createDashEventsTarget = (ele: HTMLDivElement) => { //used for stacking and masonry view
this.dropDisposer?.();
this.gestureDisposer?.();
this.multiTouchDisposer?.();
if (ele) {
- this.dropDisposer = DragManager.MakeDropTarget(ele, this.drop.bind(this));
+ this._mainCont = ele;
+ this.dropDisposer = DragManager.MakeDropTarget(ele, this.onInternalDrop.bind(this));
this.gestureDisposer = GestureUtils.MakeGestureTarget(ele, this.onGesture.bind(this));
this.multiTouchDisposer = InteractionUtils.MakeMultiTouchTarget(ele, this.onTouchStart.bind(this));
}
@@ -66,75 +70,98 @@ export function CollectionSubView<T>(schemaCtor: (doc: Doc) => T) {
}
componentDidMount() {
- this._childLayoutDisposer = reaction(() => [this.childDocs, (Cast(this.props.Document.childLayout, Doc) as Doc)?.[Id]],
- (args) => {
- const childLayout = Cast(this.props.Document.childLayout, Doc);
+ this._childLayoutDisposer = reaction(() => ({ childDocs: this.childDocs, childLayout: Cast(this.props.Document.childLayout, Doc) }),
+ ({ childDocs, childLayout }) => {
if (childLayout instanceof Doc) {
- this.childDocs.map(doc => Doc.ApplyTemplateTo(childLayout, doc, "layout_fromParent"));
+ childDocs.map(doc => {
+ doc.layout_fromParent = childLayout;
+ doc.layoutKey = "layout_fromParent";
+ });
}
else if (!(childLayout instanceof Promise)) {
- this.childDocs.filter(d => !d.isTemplateForField).map(doc => doc.layoutKey === "layout_fromParent" && (doc.layoutKey = "layout"));
+ childDocs.filter(d => !d.isTemplateForField).map(doc => doc.layoutKey === "layout_fromParent" && (doc.layoutKey = "layout"));
}
}, { fireImmediately: true });
}
componentWillUnmount() {
- this._childLayoutDisposer && this._childLayoutDisposer();
+ this.gestureDisposer?.();
+ this.multiTouchDisposer?.();
+ this._childLayoutDisposer?.();
}
- @computed get dataDoc() { return this.props.DataDoc && this.props.Document.isTemplateForField ? Doc.GetProto(this.props.DataDoc) : Doc.GetProto(this.props.Document); }
+ @computed get dataDoc() {
+ return (this.props.DataDoc instanceof Doc && this.props.Document.isTemplateForField ? Doc.GetProto(this.props.DataDoc) :
+ this.props.Document.resolvedDataDoc ? this.props.Document : Doc.GetProto(this.props.Document)); // if the layout document has a resolvedDataDoc, then we don't want to get its parent which would be the unexpanded template
+ }
// The data field for rendering this collection will be on the this.props.Document unless we're rendering a template in which case we try to use props.DataDoc.
// When a document has a DataDoc but it's not a template, then it contains its own rendering data, but needs to pass the DataDoc through
// to its children which may be templates.
// If 'annotationField' is specified, then all children exist on that field of the extension document, otherwise, they exist directly on the data document under 'fieldKey'
@computed get dataField() {
- const { annotationsKey, fieldKey } = this.props;
- if (annotationsKey) {
- return this.dataDoc[fieldKey + "-" + annotationsKey];
- }
- return this.dataDoc[fieldKey];
+ return this.dataDoc[this.props.fieldKey + (this.props.annotationsKey ? "-" + this.props.annotationsKey : "")];
}
get childLayoutPairs(): { layout: Doc; data: Doc; }[] {
const { Document, DataDoc } = this.props;
- const validPairs = this.childDocs.map(doc => Doc.GetLayoutDataDocPair(Document, DataDoc, doc)).filter(pair => pair.layout);
- return validPairs.map(({ data, layout }) => ({ data: data!, layout: layout! })); // this mapping is a bit of a hack to coerce types
+ const validPairs = this.childDocs.map(doc => Doc.GetLayoutDataDocPair(Document, !this.props.annotationsKey ? DataDoc : undefined, doc)).filter(pair => pair.layout);
+ return validPairs.map(({ data, layout }) => ({ data: data as Doc, layout: layout! })); // this mapping is a bit of a hack to coerce types
}
get childDocList() {
return Cast(this.dataField, listSpec(Doc));
}
- get childDocs() {
- const docs = DocListCast(this.dataField);
- const viewSpecScript = Cast(this.props.Document.viewSpecScript, ScriptField);
- const viewedDocs = viewSpecScript ? docs.filter(d => viewSpecScript.script.run({ doc: d }, console.log).result) : docs;
- const docFilters = Cast(this.props.Document._docFilter, listSpec("string"), []);
- const clusters: { [key: string]: { [value: string]: string } } = {};
+ @computed get childDocs() {
+ const docFilters = Cast(this.props.Document._docFilters, listSpec("string"), []);
+ const docRangeFilters = Cast(this.props.Document._docRangeFilters, listSpec("string"), []);
+ const filterFacets: { [key: string]: { [value: string]: string } } = {}; // maps each filter key to an object with value=>modifier fields
for (let i = 0; i < docFilters.length; i += 3) {
const [key, value, modifiers] = docFilters.slice(i, i + 3);
- const cluster = clusters[key];
- if (!cluster) {
- const child: { [value: string]: string } = {};
- child[value] = modifiers;
- clusters[key] = child;
- } else {
- cluster[value] = modifiers;
+ if (!filterFacets[key]) {
+ filterFacets[key] = {};
}
+ filterFacets[key][value] = modifiers;
+ }
+
+ let rawdocs: (Doc | Promise<Doc>)[] = [];
+ if (this.dataField instanceof Doc) { // if collection data is just a document, then promote it to a singleton list;
+ rawdocs = [this.dataField];
+ } else if (Cast(this.dataField, listSpec(Doc), null)) { // otherwise, if the collection data is a list, then use it.
+ rawdocs = Cast(this.dataField, listSpec(Doc), null);
+ } else { // Finally, if it's not a doc or a list and the document is a template, we try to render the root doc.
+ // For example, if an image doc is rendered with a slide template, the template will try to render the data field as a collection.
+ // Since the data field is actually an image, we set the list of documents to the singleton of root document's proto which will be an image.
+ const rootDoc = Cast(this.props.Document.rootDocument, Doc, null);
+ rawdocs = rootDoc && !this.props.annotationsKey ? [Doc.GetProto(rootDoc)] : [];
}
- const filteredDocs = docFilters.length ? viewedDocs.filter(d => {
- for (const key of Object.keys(clusters)) {
- const cluster = clusters[key];
- const satisfiesFacet = Object.keys(cluster).some(inner => {
- const modifier = cluster[inner];
- return (modifier === "x") !== Doc.matchFieldValue(d, key, inner);
- });
+ const docs = rawdocs.filter(d => !(d instanceof Promise)).map(d => d as Doc);
+ const viewSpecScript = Cast(this.props.Document.viewSpecScript, ScriptField);
+ const childDocs = viewSpecScript ? docs.filter(d => viewSpecScript.script.run({ doc: d }, console.log).result) : docs;
+
+ const filteredDocs = docFilters.length && !this.props.dontRegisterView ? childDocs.filter(d => {
+ for (const facetKey of Object.keys(filterFacets)) {
+ const facet = filterFacets[facetKey];
+ const satisfiesFacet = Object.keys(facet).some(value =>
+ (facet[value] === "x") !== Doc.matchFieldValue(d, facetKey, value));
if (!satisfiesFacet) {
return false;
}
}
return true;
- }) : viewedDocs;
- return filteredDocs;
+ }) : childDocs;
+ const rangeFilteredDocs = filteredDocs.filter(d => {
+ for (let i = 0; i < docRangeFilters.length; i += 3) {
+ const key = docRangeFilters[i];
+ const min = Number(docRangeFilters[i + 1]);
+ const max = Number(docRangeFilters[i + 2]);
+ const val = Cast(d[key], "number", null);
+ if (val !== undefined && (val < min || val > max)) {
+ return false;
+ }
+ }
+ return true;
+ });
+ return rangeFilteredDocs;
}
@action
@@ -171,23 +198,19 @@ export function CollectionSubView<T>(schemaCtor: (doc: Doc) => T) {
@undoBatch
protected onGesture(e: Event, ge: GestureUtils.GestureEvent) {
-
}
@undoBatch
@action
- protected drop(e: Event, de: DragManager.DropEvent): boolean {
+ protected onInternalDrop(e: Event, de: DragManager.DropEvent): boolean {
const docDragData = de.complete.docDragData;
(this.props.Document.dropConverter instanceof ScriptField) &&
this.props.Document.dropConverter.script.run({ dragData: docDragData }); /// bcz: check this
- if (docDragData && !docDragData.applyAsTemplate) {
- if (de.altKey && docDragData.draggedDocuments.length) {
- this.childDocs.map(doc =>
- Doc.ApplyTemplateTo(docDragData.draggedDocuments[0], doc, "layout_fromParent"));
- e.stopPropagation();
- return true;
- }
+ if (docDragData) {
let added = false;
+ if (this.props.Document._freezeOnDrop) {
+ de.complete.docDragData?.droppedDocuments.forEach(drop => Doc.freezeNativeDimensions(drop, drop[WidthSym](), drop[HeightSym]()));
+ }
if (docDragData.dropAction || docDragData.userDropAction) {
added = docDragData.droppedDocuments.reduce((added: boolean, d) => this.props.addDocument(d) || added, false);
} else if (docDragData.moveDocument) {
@@ -210,150 +233,176 @@ export function CollectionSubView<T>(schemaCtor: (doc: Doc) => T) {
@undoBatch
@action
- protected async onDrop(e: React.DragEvent, options: DocumentOptions, completed?: () => void) {
+ protected async onExternalDrop(e: React.DragEvent, options: DocumentOptions, completed?: () => void) {
if (e.ctrlKey) {
e.stopPropagation(); // bcz: this is a hack to stop propagation when dropping an image on a text document with shift+ctrl
return;
}
- const html = e.dataTransfer.getData("text/html");
- const text = e.dataTransfer.getData("text/plain");
+
+ const { dataTransfer } = e;
+ const html = dataTransfer.getData("text/html");
+ const text = dataTransfer.getData("text/plain");
if (text && text.startsWith("<div")) {
return;
}
+
e.stopPropagation();
e.preventDefault();
+ const { addDocument } = this.props;
+ if (!addDocument) {
+ alert("this.props.addDocument does not exist. Aborting drop operation.");
+ return;
+ }
- if (html && FormattedTextBox.IsFragment(html)) {
- const href = FormattedTextBox.GetHref(html);
- if (href) {
- const docid = FormattedTextBox.GetDocFromUrl(href);
- if (docid) { // prosemirror text containing link to dash document
- DocServer.GetRefField(docid).then(f => {
- if (f instanceof Doc) {
- if (options.x || options.y) { f.x = options.x; f.y = options.y; } // should be in CollectionFreeFormView
- (f instanceof Doc) && this.props.addDocument(f);
- }
- });
+ if (html) {
+ if (FormattedTextBox.IsFragment(html)) {
+ const href = FormattedTextBox.GetHref(html);
+ if (href) {
+ const docid = FormattedTextBox.GetDocFromUrl(href);
+ if (docid) { // prosemirror text containing link to dash document
+ DocServer.GetRefField(docid).then(f => {
+ if (f instanceof Doc) {
+ if (options.x || options.y) { f.x = options.x; f.y = options.y; } // should be in CollectionFreeFormView
+ (f instanceof Doc) && addDocument(f);
+ }
+ });
+ } else {
+ addDocument(Docs.Create.WebDocument(href, { ...options, title: href }));
+ }
+ } else if (text) {
+ addDocument(Docs.Create.TextDocument(text, { ...options, _width: 100, _height: 25 }));
+ }
+ return;
+ }
+ if (!html.startsWith("<a")) {
+ const tags = html.split("<");
+ if (tags[0] === "") tags.splice(0, 1);
+ let img = tags[0].startsWith("img") ? tags[0] : tags.length > 1 && tags[1].startsWith("img") ? tags[1] : "";
+ const cors = img.includes("corsProxy") ? img.match(/http.*corsProxy\//)![0] : "";
+ img = cors ? img.replace(cors, "") : img;
+ if (img) {
+ const split = img.split("src=\"")[1].split("\"")[0];
+ let source = split;
+ if (split.startsWith("data:image") && split.includes("base64")) {
+ const [{ accessPaths }] = await Networking.PostToServer("/uploadRemoteImage", { sources: [split] });
+ source = Utils.prepend(accessPaths.agnostic.client);
+ }
+ if (source.startsWith("http")) {
+ const doc = Docs.Create.ImageDocument(source, { ...options, _width: 300 });
+ ImageUtils.ExtractExif(doc);
+ addDocument(doc);
+ }
+ return;
} else {
- this.props.addDocument && this.props.addDocument(Docs.Create.WebDocument(href, { ...options, title: href }));
+ const path = window.location.origin + "/doc/";
+ if (text.startsWith(path)) {
+ const docid = text.replace(Utils.prepend("/doc/"), "").split("?")[0];
+ DocServer.GetRefField(docid).then(f => {
+ if (f instanceof Doc) {
+ if (options.x || options.y) { f.x = options.x; f.y = options.y; } // should be in CollectionFreeFormView
+ (f instanceof Doc) && this.props.addDocument(f);
+ }
+ });
+ } else {
+ const htmlDoc = Docs.Create.HtmlDocument(html, { ...options, title: "-web page-", _width: 300, _height: 300 });
+ Doc.GetProto(htmlDoc)["data-text"] = text;
+ this.props.addDocument(htmlDoc);
+ }
+ return;
}
- } else if (text) {
- this.props.addDocument && this.props.addDocument(Docs.Create.TextDocument(text, { ...options, _width: 100, _height: 25 }));
}
- return;
}
- if (html && !html.startsWith("<a")) {
- const tags = html.split("<");
- if (tags[0] === "") tags.splice(0, 1);
- const img = tags[0].startsWith("img") ? tags[0] : tags.length > 1 && tags[1].startsWith("img") ? tags[1] : "";
- if (img) {
- const split = img.split("src=\"")[1].split("\"")[0];
- const doc = Docs.Create.ImageDocument(split, { ...options, _width: 300 });
- ImageUtils.ExtractExif(doc);
- this.props.addDocument(doc);
+
+ if (text) {
+ if (text.includes("www.youtube.com/watch")) {
+ const url = text.replace("youtube.com/watch?v=", "youtube.com/embed/");
+ addDocument(Docs.Create.VideoDocument(url, {
+ ...options,
+ title: url,
+ _width: 400,
+ _height: 315,
+ _nativeWidth: 600,
+ _nativeHeight: 472.5
+ }));
return;
- } else {
- const path = window.location.origin + "/doc/";
- if (text.startsWith(path)) {
- const docid = text.replace(Utils.prepend("/doc/"), "").split("?")[0];
- DocServer.GetRefField(docid).then(f => {
- if (f instanceof Doc) {
- if (options.x || options.y) { f.x = options.x; f.y = options.y; } // should be in CollectionFreeFormView
- (f instanceof Doc) && this.props.addDocument(f);
- }
- });
- } else {
- const htmlDoc = Docs.Create.HtmlDocument(html, { ...options, title: "-web page-", _width: 300, _height: 300, documentText: text });
- this.props.addDocument(htmlDoc);
- }
+ }
+ let matches: RegExpExecArray | null;
+ if ((matches = /(https:\/\/)?docs\.google\.com\/document\/d\/([^\\]+)\/edit/g.exec(text)) !== null) {
+ const newBox = Docs.Create.TextDocument("", { ...options, _width: 400, _height: 200, title: "Awaiting title from Google Docs..." });
+ const proto = newBox.proto!;
+ const documentId = matches[2];
+ proto[GoogleRef] = documentId;
+ proto.data = "Please select this document and then click on its pull button to load its contents from from Google Docs...";
+ proto.backgroundColor = "#eeeeff";
+ addDocument(newBox);
+ return;
+ }
+ if ((matches = /(https:\/\/)?photos\.google\.com\/(u\/3\/)?album\/([^\\]+)/g.exec(text)) !== null) {
+ const albumId = matches[3];
+ const mediaItems = await GooglePhotos.Query.AlbumSearch(albumId);
+ console.log(mediaItems);
return;
}
}
- if (text && text.indexOf("www.youtube.com/watch") !== -1) {
- const url = text.replace("youtube.com/watch?v=", "youtube.com/embed/");
- this.props.addDocument(Docs.Create.VideoDocument(url, { ...options, title: url, _width: 400, _height: 315, _nativeWidth: 600, _nativeHeight: 472.5 }));
- return;
- }
- let matches: RegExpExecArray | null;
- if ((matches = /(https:\/\/)?docs\.google\.com\/document\/d\/([^\\]+)\/edit/g.exec(text)) !== null) {
- const newBox = Docs.Create.TextDocument("", { ...options, _width: 400, _height: 200, title: "Awaiting title from Google Docs..." });
- const proto = newBox.proto!;
- const documentId = matches[2];
- proto[GoogleRef] = documentId;
- proto.data = "Please select this document and then click on its pull button to load its contents from from Google Docs...";
- proto.backgroundColor = "#eeeeff";
- this.props.addDocument(newBox);
- // const parent = Docs.Create.StackingDocument([newBox], { title: `Google Doc Import (${documentId})` });
- // CollectionDockingView.Instance.AddRightSplit(parent, undefined);
- // proto.height = parent[HeightSym]();
+
+ const { items } = e.dataTransfer;
+ const { length } = items;
+ const files: File[] = [];
+ const generatedDocuments: Doc[] = [];
+ if (!length) {
+ alert("No uploadable content found.");
return;
}
- if ((matches = /(https:\/\/)?photos\.google\.com\/(u\/3\/)?album\/([^\\]+)/g.exec(text)) !== null) {
- const albums = await GooglePhotos.Transactions.ListAlbums();
- const albumId = matches[3];
- const mediaItems = await GooglePhotos.Query.AlbumSearch(albumId);
- console.log(mediaItems);
- }
+
const batch = UndoManager.StartBatch("collection view drop");
- const promises: Promise<void>[] = [];
- // tslint:disable-next-line:prefer-for-of
- for (let i = 0; i < e.dataTransfer.items.length; i++) {
+ for (let i = 0; i < length; i++) {
const item = e.dataTransfer.items[i];
- if (item.kind === "string" && item.type.indexOf("uri") !== -1) {
- let str: string;
- const prom = new Promise<string>(resolve => e.dataTransfer.items[i].getAsString(resolve))
- .then(action((s: string) => rp.head(Utils.CorsProxy(str = s))))
- .then(result => {
- const type = result["content-type"];
- if (type) {
- Docs.Get.DocumentFromType(type, str, options)
- .then(doc => doc && this.props.addDocument(doc));
- }
- });
- promises.push(prom);
+ if (item.kind === "string" && item.type.includes("uri")) {
+ const stringContents = await new Promise<string>(resolve => item.getAsString(resolve));
+ const type = "html";// (await rp.head(Utils.CorsProxy(stringContents)))["content-type"];
+ if (type) {
+ const doc = await Docs.Get.DocumentFromType(type, stringContents, options);
+ doc && generatedDocuments.push(doc);
+ }
}
- const type = item.type;
if (item.kind === "file") {
const file = item.getAsFile();
- const formData = new FormData();
-
- if (!file || !file.type) {
- continue;
- }
-
- formData.append('file', file);
- const dropFileName = file ? file.name : "-empty-";
- promises.push(Networking.PostFormDataToServer("/uploadFormData", formData).then(results => {
- results.map(action((result: any) => {
- const { clientAccessPath, nativeWidth, nativeHeight, contentSize } = result;
- const full = { ...options, _width: 300, title: dropFileName };
- const pathname = Utils.prepend(clientAccessPath);
- Docs.Get.DocumentFromType(type, pathname, full).then(doc => {
- if (doc) {
- const proto = Doc.GetProto(doc);
- proto.fileUpload = basename(pathname).replace("upload_", "").replace(/\.[a-z0-9]*$/, "");
- nativeWidth && (proto["data-nativeWidth"] = nativeWidth);
- nativeHeight && (proto["data-nativeHeight"] = nativeHeight);
- contentSize && (proto.contentSize = contentSize);
- this.props.addDocument(doc);
- }
- });
- }));
- }));
+ file && file.type && files.push(file);
}
}
-
- if (promises.length) {
- Promise.all(promises).finally(() => { completed && completed(); batch.end(); });
+ for (const { source: { name, type }, result } of await Networking.UploadFilesToServer(files)) {
+ if (result instanceof Error) {
+ alert(`Upload failed: ${result.message}`);
+ return;
+ }
+ const full = { ...options, _width: 300, title: name };
+ const pathname = Utils.prepend(result.accessPaths.agnostic.client);
+ const doc = await Docs.Get.DocumentFromType(type, pathname, full);
+ if (!doc) {
+ continue;
+ }
+ const proto = Doc.GetProto(doc);
+ proto.fileUpload = basename(pathname).replace("upload_", "").replace(/\.[a-z0-9]*$/, "");
+ if (Upload.isImageInformation(result)) {
+ proto["data-nativeWidth"] = (result.nativeWidth > result.nativeHeight) ? 400 * result.nativeWidth / result.nativeHeight : 400;
+ proto["data-nativeHeight"] = (result.nativeWidth > result.nativeHeight) ? 400 : 400 / (result.nativeWidth / result.nativeHeight);
+ proto.contentSize = result.contentSize;
+ }
+ generatedDocuments.push(doc);
+ }
+ if (generatedDocuments.length) {
+ generatedDocuments.forEach(addDocument);
+ completed && completed();
} else {
if (text && !text.includes("https://")) {
- this.props.addDocument(Docs.Create.TextDocument(text, { ...options, _width: 400, _height: 315 }));
+ addDocument(Docs.Create.TextDocument(text, { ...options, _width: 400, _height: 315 }));
}
- batch.end();
}
+ batch.end();
}
}
+
return CollectionSubView;
}