aboutsummaryrefslogtreecommitdiff
path: root/src/client/documents/Documents.ts
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/documents/Documents.ts')
-rw-r--r--src/client/documents/Documents.ts192
1 files changed, 129 insertions, 63 deletions
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 3316e6b48..47fa7067d 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -1,7 +1,8 @@
-import { runInAction, action } from "mobx";
-import { extname, basename } from "path";
+import { runInAction } from "mobx";
+import { basename, extname } from "path";
import { DateField } from "../../fields/DateField";
import { Doc, DocListCast, DocListCastAsync, Field, HeightSym, Opt, WidthSym } from "../../fields/Doc";
+import { Id } from "../../fields/FieldSymbols";
import { HtmlField } from "../../fields/HtmlField";
import { InkField } from "../../fields/InkField";
import { List } from "../../fields/List";
@@ -11,29 +12,31 @@ import { SchemaHeaderField } from "../../fields/SchemaHeaderField";
import { ComputedField, ScriptField } from "../../fields/ScriptField";
import { Cast, NumCast, StrCast } from "../../fields/Types";
import { AudioField, ImageField, PdfField, VideoField, WebField, YoutubeField } from "../../fields/URLField";
+import { SharingPermissions } from "../../fields/util";
import { MessageStore } from "../../server/Message";
+import { Upload } from "../../server/SharedMediaTypes";
import { OmitKeys, Utils } from "../../Utils";
import { YoutubeBox } from "../apis/youtube/YoutubeBox";
import { DocServer } from "../DocServer";
+import { Networking } from "../Network";
import { DocumentManager } from "../util/DocumentManager";
import { dropActionType } from "../util/DragManager";
import { DirectoryImportBox } from "../util/Import & Export/DirectoryImportBox";
import { LinkManager } from "../util/LinkManager";
import { Scripting } from "../util/Scripting";
-import { UndoManager } from "../util/UndoManager";
-import { DocumentType } from "./DocumentTypes";
-import { SearchBox } from "../views/search/SearchBox";
+import { undoBatch, UndoManager } from "../util/UndoManager";
import { CollectionDockingView } from "../views/collections/CollectionDockingView";
import { CollectionView, CollectionViewType } from "../views/collections/CollectionView";
import { ContextMenu } from "../views/ContextMenu";
import { ContextMenuProps } from "../views/ContextMenuItem";
+import { DFLT_IMAGE_NATIVE_DIM } from "../views/globalCssVariables.scss";
import { ActiveArrowEnd, ActiveArrowStart, ActiveDash, ActiveFillColor, ActiveInkBezierApprox, ActiveInkColor, ActiveInkWidth, InkingStroke } from "../views/InkingStroke";
import { AudioBox } from "../views/nodes/AudioBox";
import { ColorBox } from "../views/nodes/ColorBox";
import { ComparisonBox } from "../views/nodes/ComparisonBox";
import { DocHolderBox } from "../views/nodes/DocHolderBox";
+import { FilterBox } from "../views/nodes/FilterBox";
import { FontIconBox } from "../views/nodes/FontIconBox";
-import { MenuIconBox } from "../views/nodes/MenuIconBox";
import { FormattedTextBox } from "../views/nodes/formattedText/FormattedTextBox";
import { ImageBox } from "../views/nodes/ImageBox";
import { KeyValueBox } from "../views/nodes/KeyValueBox";
@@ -47,14 +50,17 @@ import { SliderBox } from "../views/nodes/SliderBox";
import { VideoBox } from "../views/nodes/VideoBox";
import { WebBox } from "../views/nodes/WebBox";
import { PresElementBox } from "../views/presentationview/PresElementBox";
+import { SearchBox } from "../views/search/SearchBox";
import { DashWebRTCVideo } from "../views/webcam/DashWebRTCVideo";
-import { Networking } from "../Network";
-import { Upload } from "../../server/SharedMediaTypes";
+import { DocumentType } from "./DocumentTypes";
const path = require('path');
+const defaultNativeImageDim = Number(DFLT_IMAGE_NATIVE_DIM.replace("px", ""));
export interface DocumentOptions {
system?: boolean;
_autoHeight?: boolean;
+ _headerHeight?: number; // height of header of custom notes
+ _headerFontSize?: number; // font size of header of custom notes
_panX?: number;
_panY?: number;
_width?: number;
@@ -72,6 +78,7 @@ export interface DocumentOptions {
_scrollTop?: number; // scroll location for pdfs
_noAutoscroll?: boolean;// whether collections autoscroll when this item is dragged
_chromeStatus?: string;
+ _searchDoc?: boolean; // is this a search document (used to change UI for search results in schema view)
_viewType?: string; // sub type of a collection
_gridGap?: number; // gap between items in masonry view
_xMargin?: number; // gap between left edge of document and start of masonry/stacking layouts
@@ -87,12 +94,14 @@ export interface DocumentOptions {
y?: number;
z?: number;
author?: string;
+ _hideContextMenu?: boolean; // whether the context menu can be shown
dropAction?: dropActionType;
childDropAction?: dropActionType;
targetDropAction?: dropActionType;
layoutKey?: string;
type?: string;
title?: string;
+ version?: string; // version identifier for a document
label?: string;
hidden?: boolean;
userDoc?: Doc; // the userDocument
@@ -101,12 +110,12 @@ export interface DocumentOptions {
page?: number;
description?: string; // added for links
_viewScale?: number;
- isDisplayPanel?: boolean; // whether the panel functions as GoldenLayout "stack" used to display documents
forceActive?: boolean;
layout?: string | Doc; // default layout string for a document
+ contentPointerEvents?: string; // pointer events allowed for content of a document view. eg. set to "none" sidebar views that are intended to document "menus"
+ childLimitHeight?: number; // whether to limit the height of colleciton children. 0 - means height can be no bigger than width
childLayoutTemplate?: Doc; // template for collection to use to render its children (see PresBox or Buxton layout in tree view)
childLayoutString?: string; // template string for collection to use to render its children
- hideFilterView?: boolean; // whether to hide the filter popout on collections
hideLinkButton?: boolean; // whether the blue link counter button should be hidden
hideAllLinks?: boolean; // whether all individual blue anchor dots should be hidden
_columnsHideIfEmpty?: boolean; // whether stacking view column headings should be hidden
@@ -128,27 +137,27 @@ export interface DocumentOptions {
isAnnotating?: boolean; // whether we web document is annotation mode where links can't be clicked to allow annotations to be created
opacity?: number;
defaultBackgroundColor?: string;
- isBackground?: boolean;
+ _isBackground?: boolean;
+ _raiseWhenDragged?: boolean; // whether a document is brought to front when dragged.
isLinkButton?: boolean;
_columnWidth?: number;
_fontSize?: string;
_fontWeight?: number;
_fontFamily?: string;
- curPage?: number;
- currentTimecode?: number; // the current timecode of a time-based document (e.g., current time of a video) value is in seconds
+ _curPage?: number;
+ _currentTimecode?: number; // the current timecode of a time-based document (e.g., current time of a video) value is in seconds
+ _currentFrame?: number; // the current frame of a frame-based collection (e.g., progressive slide)
displayTimecode?: number; // the time that a document should be displayed (e.g., time an annotation should be displayed on a video)
- currentFrame?: number; // the current frame of a frame-based collection (e.g., progressive slide)
lastFrame?: number; // the last frame of a frame-based collection (e.g., progressive slide)
activeFrame?: number; // the active frame of a document in a frame base collection
appearFrame?: number; // the frame in which the document appears
presTransition?: number; //the time taken for the transition TO a document
presDuration?: number; //the duration of the slide in presentation view
presProgressivize?: boolean;
- // xArray?: number[];
- // yArray?: number[];
borderRounding?: string;
boxShadow?: string;
dontRegisterChildViews?: boolean;
+ dontRegisterView?: boolean;
lookupField?: ScriptField; // script that returns the value of a field. This script is passed the rootDoc, layoutDoc, field, and container of the document. see PresBox.
"onDoubleClick-rawScript"?: string; // onDoubleClick script in raw text form
"onChildDoubleClick-rawScript"?: string; // onChildDoubleClick script in raw text form
@@ -178,7 +187,7 @@ export interface DocumentOptions {
clickFactory?: Doc; // document to create when clicking on a button with a suitable onClick script
onDragStart?: ScriptField; //script to execute at start of drag operation -- e.g., when a "creator" button is dragged this script generates a different document to drop
clipboard?: Doc;
- UseCors?: boolean;
+ useCors?: boolean;
icon?: string;
target?: Doc; // available for use in scripts as the primary target document
sourcePanel?: Doc; // panel to display in 'targetContainer' as the result of a button onClick script
@@ -187,13 +196,20 @@ export interface DocumentOptions {
strokeWidth?: number;
cloneFieldFilter?: List<string>; // fields not to copy when the document is cloned
_stayInCollection?: boolean;// whether the document should remain in its collection when someone tries to drag and drop it elsewhere
+ freezeChildren?: string; // whether children are now allowed to be added and or removed from a collection
treeViewPreventOpen?: boolean; // ignores the treeViewOpen Doc flag which allows a treeViewItem's expand/collapse state to be independent of other views of the same document in the tree view
- treeViewHideTitle?: boolean; // whether to hide the title of a tree view
+ treeViewHideTitle?: boolean; // whether to hide the top document title of a tree view
+ treeViewHideHeader?: boolean; // whether to hide the header for a document in a tree view
treeViewHideHeaderFields?: boolean; // whether to hide the drop down options for tree view items.
treeViewOpen?: boolean; // whether this document is expanded in a tree view
treeViewExpandedView?: string; // which field/thing is displayed when this item is opened in tree view
treeViewChecked?: ScriptField; // script to call when a tree view checkbox is checked
treeViewTruncateTitleWidth?: number;
+ treeViewOutlineMode?: boolean; // whether slide should function as a text outline
+ treeViewLockExpandedView?: boolean; // whether the expanded view can be changed
+ treeViewDefaultExpandedView?: string; // default expanded view
+ sidebarColor?: string; // background color of text sidebar
+ sidebarViewType?: string; // collection type of text sidebar
limitHeight?: number; // maximum height for newly created (eg, from pasting) text documents
// [key: string]: Opt<Field>;
pointerHack?: boolean; // for buttons, allows onClick handler to fire onPointerDown
@@ -243,6 +259,10 @@ export namespace Docs {
layout: { view: SearchBox, dataField: defaultDataKey },
options: { _width: 400 }
}],
+ [DocumentType.FILTER, {
+ layout: { view: FilterBox, dataField: defaultDataKey },
+ options: { _width: 400 }
+ }],
[DocumentType.COLOR, {
layout: { view: ColorBox, dataField: defaultDataKey },
options: { _nativeWidth: 220, _nativeHeight: 300 }
@@ -269,7 +289,7 @@ export namespace Docs {
}],
[DocumentType.VID, {
layout: { view: VideoBox, dataField: defaultDataKey },
- options: { currentTimecode: 0 },
+ options: { _currentTimecode: 0 },
}],
[DocumentType.AUDIO, {
layout: { view: AudioBox, dataField: defaultDataKey },
@@ -277,7 +297,7 @@ export namespace Docs {
}],
[DocumentType.PDF, {
layout: { view: PDFBox, dataField: defaultDataKey },
- options: { curPage: 1 }
+ options: { _curPage: 1 }
}],
[DocumentType.IMPORT, {
layout: { view: DirectoryImportBox, dataField: defaultDataKey },
@@ -332,7 +352,7 @@ export namespace Docs {
}],
[DocumentType.INK, {
layout: { view: InkingStroke, dataField: defaultDataKey },
- options: { backgroundColor: "transparent" }
+ options: { _fontFamily: "cursive", backgroundColor: "transparent" }
}],
[DocumentType.SCREENSHOT, {
layout: { view: ScreenshotBox, dataField: defaultDataKey },
@@ -534,7 +554,7 @@ export namespace Docs {
Scripting.addGlobal(Buxton);
- const delegateKeys = ["x", "y", "system", "layoutKey", "dropAction", "lockedPosiiton", "childDropAction", "isLinkButton", "isBackground", "removeDropProperties", "treeViewOpen"];
+ const delegateKeys = ["x", "y", "system", "layoutKey", "dropAction", "lockedPosiiton", "childDropAction", "isLinkButton", "removeDropProperties", "treeViewOpen"];
/**
* This function receives the relevant document prototype and uses
@@ -584,7 +604,8 @@ export namespace Docs {
viewDoc.author = Doc.CurrentUserEmail;
viewDoc.type !== DocumentType.LINK && DocUtils.MakeLinkToActiveAudio(viewDoc);
- if (Doc.UserDoc()?.defaultAclPrivate) viewDoc["ACL-Public"] = dataDoc["ACL-Public"] = "Not Shared";
+ viewDoc["acl-Public"] = dataDoc["acl-Public"] = Doc.UserDoc()?.defaultAclPrivate ? SharingPermissions.None : SharingPermissions.Add;
+ viewDoc["acl-Override"] = dataDoc["acl-Override"] = "None";
return Doc.assign(viewDoc, delegateProps, true);
}
@@ -661,6 +682,9 @@ export namespace Docs {
return InstanceFromProto(Prototypes.get(DocumentType.COLOR), "", options);
}
+ export function RTFDocument(field: RichTextField, options: DocumentOptions = {}, fieldKey: string = "text") {
+ return InstanceFromProto(Prototypes.get(DocumentType.RTF), field, options, undefined, fieldKey);
+ }
export function TextDocument(text: string, options: DocumentOptions = {}, fieldKey: string = "text") {
const rtf = {
doc: {
@@ -681,24 +705,26 @@ export namespace Docs {
export function LinkDocument(source: { doc: Doc, ctx?: Doc }, target: { doc: Doc, ctx?: Doc }, options: DocumentOptions = {}, id?: string) {
const doc = InstanceFromProto(Prototypes.get(DocumentType.LINK), undefined, {
- isLinkButton: true, treeViewHideTitle: true, treeViewOpen: false, backgroundColor: "lightBlue", // lightBlue is default color for linking dot and link documents text comment area
- removeDropProperties: new List(["isBackground", "isLinkButton"]), ...options
+ dontRegisterChildViews: true,
+ isLinkButton: true, treeViewHideTitle: true, backgroundColor: "lightBlue", // lightBlue is default color for linking dot and link documents text comment area
+ treeViewExpandedView: "fields", removeDropProperties: new List(["_isBackground", "isLinkButton"]), ...options
}, id);
const linkDocProto = Doc.GetProto(doc);
+ linkDocProto.treeViewOpen = true;// setting this in the instance creator would set it on the view document.
linkDocProto.anchor1 = source.doc;
linkDocProto.anchor2 = target.doc;
- linkDocProto.anchor1_timecode = source.doc.currentTimecode || source.doc.displayTimecode;
- linkDocProto.anchor2_timecode = target.doc.currentTimecode || target.doc.displayTimecode;
+ linkDocProto.anchor1_timecode = source.doc._currentTimecode || source.doc.displayTimecode;
+ linkDocProto.anchor2_timecode = target.doc._currentTimecode || target.doc.displayTimecode;
if (linkDocProto.linkBoxExcludedKeys === undefined) {
- Cast(linkDocProto.proto, Doc, null).linkBoxExcludedKeys = new List(["treeViewExpandedView", "treeViewHideTitle", "removeDropProperties", "linkBoxExcludedKeys", "treeViewOpen", "aliasNumber", "isPrototype", "lastOpened", "creationDate", "author"]);
+ Cast(linkDocProto.proto, Doc, null).linkBoxExcludedKeys = new List(["treeViewExpandedView", "aliases", "treeViewHideTitle", "removeDropProperties", "linkBoxExcludedKeys", "treeViewOpen", "aliasNumber", "isPrototype", "creationDate", "author"]);
Cast(linkDocProto.proto, Doc, null).layoutKey = undefined;
}
LinkManager.Instance.addLink(doc);
- Doc.GetProto(source.doc).links = ComputedField.MakeFunction("links(self)");
- Doc.GetProto(target.doc).links = ComputedField.MakeFunction("links(self)");
+ source.doc.links === undefined && (Doc.GetProto(source.doc).links = ComputedField.MakeFunction("links(self)"));
+ target.doc.links === undefined && (Doc.GetProto(target.doc).links = ComputedField.MakeFunction("links(self)"));
return doc;
}
@@ -720,9 +746,12 @@ export namespace Docs {
I._backgroundColor = "transparent";
I._width = options._width;
I._height = options._height;
+ I._fontFamily = "cursive";
I.author = Doc.CurrentUserEmail;
I.rotation = 0;
I.data = new InkField(points);
+ I["acl-Public"] = Doc.UserDoc()?.defaultAclPrivate ? SharingPermissions.None : SharingPermissions.Add;
+ I["acl-Override"] = "None";
return I;
}
@@ -747,11 +776,11 @@ export namespace Docs {
}
export function FreeformDocument(documents: Array<Doc>, options: DocumentOptions, id?: string) {
- return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { _chromeStatus: "collapsed", dontRegisterChildViews: true, ...options, _viewType: CollectionViewType.Freeform }, id);
+ return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { _chromeStatus: "collapsed", ...options, _viewType: CollectionViewType.Freeform }, id);
}
export function PileDocument(documents: Array<Doc>, options: DocumentOptions, id?: string) {
- return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { _chromeStatus: "collapsed", backgroundColor: "black", hideFilterView: true, forceActive: true, ...options, _viewType: CollectionViewType.Pile }, id);
+ return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { _chromeStatus: "collapsed", backgroundColor: "black", _noAutoscroll: true, ...options, _viewType: CollectionViewType.Pile }, id);
}
export function LinearDocument(documents: Array<Doc>, options: DocumentOptions, id?: string) {
@@ -779,7 +808,7 @@ export namespace Docs {
}
export function StackingDocument(documents: Array<Doc>, options: DocumentOptions, id?: string) {
- return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { _chromeStatus: "collapsed", dontRegisterChildViews: true, ...options, _viewType: CollectionViewType.Stacking }, id);
+ return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { _chromeStatus: "collapsed", ...options, _viewType: CollectionViewType.Stacking }, id);
}
export function MulticolumnDocument(documents: Array<Doc>, options: DocumentOptions) {
@@ -791,7 +820,7 @@ export namespace Docs {
export function MasonryDocument(documents: Array<Doc>, options: DocumentOptions) {
- return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { _chromeStatus: "collapsed", dontRegisterChildViews: true, ...options, _viewType: CollectionViewType.Masonry });
+ return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { _chromeStatus: "collapsed", ...options, _viewType: CollectionViewType.Masonry });
}
export function LabelDocument(options?: DocumentOptions) {
@@ -815,14 +844,19 @@ export namespace Docs {
export function FontIconDocument(options?: DocumentOptions) {
return InstanceFromProto(Prototypes.get(DocumentType.FONTICON), undefined, { hideLinkButton: true, ...(options || {}) });
}
+ export function FilterDocument(options?: DocumentOptions) {
+ return InstanceFromProto(Prototypes.get(DocumentType.FILTER), undefined, { ...(options || {}) });
+ }
export function PresElementBoxDocument(options?: DocumentOptions) {
return InstanceFromProto(Prototypes.get(DocumentType.PRESELEMENT), undefined, { ...(options || {}) });
}
export function DockDocument(documents: Array<Doc>, config: string, options: DocumentOptions, id?: string) {
- const inst = InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { ...options, _viewType: CollectionViewType.Docking, dockingConfig: config }, id);
- Doc.GetProto(inst).data = new List<Doc>(documents);
+ const inst = InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { freezeChildren: "remove|add", treeViewDefaultExpandedView: "data", ...options, _viewType: CollectionViewType.Docking, dockingConfig: config }, id);
+ const tabs = TreeDocument(documents, { title: "On-Screen Tabs", freezeChildren: "remove|add", treeViewLockExpandedView: true, treeViewDefaultExpandedView: "data", system: true });
+ const all = TreeDocument([], { title: "Off-Screen Tabs", freezeChildren: "add", treeViewLockExpandedView: true, treeViewDefaultExpandedView: "data", system: true });
+ Doc.GetProto(inst).data = new List<Doc>([tabs, all]);
return inst;
}
@@ -842,7 +876,7 @@ export namespace Docs {
{
type: type,
content: [
- ...configs.map(config => CollectionDockingView.makeDocumentConfig(config.doc, config.initialWidth, config.path))
+ ...configs.map(config => CollectionDockingView.makeDocumentConfig(config.doc, undefined, config.initialWidth))
]
}
]
@@ -857,6 +891,27 @@ export namespace Docs {
}
export namespace DocUtils {
+ export function Excluded(d: Doc, docFilters: 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);
+ if (!filterFacets[key]) {
+ filterFacets[key] = {};
+ }
+ filterFacets[key][value] = modifiers;
+ }
+
+ if (d.z) return false;
+ for (const facetKey of Object.keys(filterFacets)) {
+ const facet = filterFacets[facetKey];
+ const xs = Object.keys(facet).filter(value => facet[value] === "x");
+ const failsNotEqualFacets = xs?.some(value => Doc.matchFieldValue(d, facetKey, value));
+ if (failsNotEqualFacets) {
+ return true;
+ }
+ }
+ return false;
+ }
export function FilterDocs(docs: Doc[], docFilters: string[], docRangeFilters: string[], viewSpecScript?: ScriptField) {
const childDocs = viewSpecScript ? docs.filter(d => viewSpecScript.script.run({ doc: d }, console.log).result) : docs;
@@ -870,21 +925,24 @@ export namespace DocUtils {
}
const filteredDocs = docFilters.length ? childDocs.filter(d => {
+ if (d.z) return true;
for (const facetKey of Object.keys(filterFacets)) {
const facet = filterFacets[facetKey];
- const satisfiesFacet = Object.keys(facet).some(value => {
- if (facet[value] === "match") {
- if (facetKey.startsWith("*")) { // fields starting with a '*' are used to match families of related fields. ie, *lastModified will match text-lastModified, data-lastModified, etc
- const allKeys = Array.from(Object.keys(d));
- allKeys.push(...Object.keys(Doc.GetProto(d)));
- const keys = allKeys.filter(key => key.includes(facetKey.substring(1)));
- return keys.some(key => Field.toString(d[key] as Field).includes(value));
- }
- return d[facetKey] === undefined || Field.toString(d[facetKey] as Field).includes(value);
+ const matches = Object.keys(facet).filter(value => facet[value] === "match");
+ const checks = Object.keys(facet).filter(value => facet[value] === "check");
+ const xs = Object.keys(facet).filter(value => facet[value] === "x");
+ const failsNotEqualFacets = !xs.length ? false : xs.some(value => Doc.matchFieldValue(d, facetKey, value));
+ const satisfiesCheckFacets = !checks.length ? true : checks.some(value => Doc.matchFieldValue(d, facetKey, value));
+ const satisfiesMatchFacets = !matches.length ? true : matches.some(value => {
+ if (facetKey.startsWith("*")) { // fields starting with a '*' are used to match families of related fields. ie, *lastModified will match text-lastModified, data-lastModified, etc
+ const allKeys = Array.from(Object.keys(d));
+ allKeys.push(...Object.keys(Doc.GetProto(d)));
+ const keys = allKeys.filter(key => key.includes(facetKey.substring(1)));
+ return keys.some(key => Field.toString(d[key] as Field).includes(value));
}
- return (facet[value] === "x") !== Doc.matchFieldValue(d, facetKey, value);
+ return Field.toString(d[facetKey] as Field).includes(value);
});
- if (!satisfiesFacet) {
+ if (!satisfiesCheckFacets || !satisfiesMatchFacets || failsNotEqualFacets) {
return false;
}
}
@@ -896,7 +954,7 @@ export namespace DocUtils {
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)) {
+ if (val === undefined || (val < min || val > max)) {
return false;
}
}
@@ -942,9 +1000,9 @@ export namespace DocUtils {
DocUtils.ActiveRecordings.map(d => DocUtils.MakeLink({ doc: doc }, { doc: d }, "audio link", "audio timeline"));
}
- export function MakeLink(source: { doc: Doc }, target: { doc: Doc }, linkRelationship: string = "", description: string = "", id?: string) {
+ export function MakeLink(source: { doc: Doc }, target: { doc: Doc }, linkRelationship: string = "", description: string = "", id?: string, allowParCollectionLink?: boolean) {
const sv = DocumentManager.Instance.getDocumentView(source.doc);
- if (sv && sv.props.ContainingCollectionDoc === target.doc) return;
+ if (!allowParCollectionLink && sv?.props.ContainingCollectionDoc === target.doc) return;
if (target.doc === Doc.UserDoc()) return undefined;
const linkDoc = Docs.Create.LinkDocument(source, target, { linkRelationship, layoutKey: "layout_linkView", description }, id);
@@ -952,6 +1010,7 @@ export namespace DocUtils {
Doc.GetProto(linkDoc)["anchor2-useLinkSmallAnchor"] = target.doc.useLinkSmallAnchor;
linkDoc.linkDisplay = true;
linkDoc.hidden = true;
+ Doc.GetProto(linkDoc)["acl-Public"] = linkDoc["acl-Public"] = SharingPermissions.Add;
linkDoc.layout_linkView = Cast(Cast(Doc.UserDoc()["template-button-link"], Doc, null).dragFactory, Doc, null);
Doc.GetProto(linkDoc).title = ComputedField.MakeFunction('self.anchor1?.title +" (" + (self.linkRelationship||"to") +") " + self.anchor2?.title');
@@ -1032,17 +1091,17 @@ export namespace DocUtils {
});
}
ctor = Docs.Create.WebDocument;
- options = { ...options, _nativeWidth: 850, _nativeHeight: 962, _width: 500, _height: 566, title: path, };
+ options = { ...options, _fitWidth: true, _nativeWidth: 850, _width: 400, _height: 512, title: path, };
}
return ctor ? ctor(path, options) : undefined;
}
- export function addDocumentCreatorMenuItems(docTextAdder: (d: Doc) => void, docAdder: (d: Doc) => void, x: number, y: number): void {
- ContextMenu.Instance.addItem({
+ export function addDocumentCreatorMenuItems(docTextAdder: (d: Doc) => void, docAdder: (d: Doc) => void, x: number, y: number, simpleMenu: boolean = false): void {
+ !simpleMenu && ContextMenu.Instance.addItem({
description: "Add Note ...",
subitems: DocListCast((Doc.UserDoc()["template-notes"] as Doc).data).map((note, i) => ({
description: ":" + StrCast(note.title),
- event: (args: { x: number, y: number }) => {
+ event: undoBatch((args: { x: number, y: number }) => {
const textDoc = Docs.Create.TextDocument("", {
_width: 200, x, y, _autoHeight: note._autoHeight !== false,
title: StrCast(note.title) + "#" + (note.aliasCount = NumCast(note.aliasCount) + 1)
@@ -1050,24 +1109,25 @@ export namespace DocUtils {
textDoc.layoutKey = "layout_" + note.title;
textDoc[textDoc.layoutKey] = note;
docTextAdder(textDoc);
- },
+ }),
icon: "eye"
})) as ContextMenuProps[],
icon: "eye"
});
ContextMenu.Instance.addItem({
description: "Add Template Doc ...",
- subitems: DocListCast(Cast(Doc.UserDoc().myItemCreators, Doc, null)?.data).map(btnDoc => Cast(btnDoc?.dragFactory, Doc, null)).filter(doc => doc).map((dragDoc, i) => ({
+ subitems: DocListCast(Cast(Doc.UserDoc().myItemCreators, Doc, null)?.data).filter(btnDoc => !btnDoc.hidden).map(btnDoc => Cast(btnDoc?.dragFactory, Doc, null)).filter(doc => doc && doc !== Doc.UserDoc().emptyPresentation).map((dragDoc, i) => ({
description: ":" + StrCast(dragDoc.title),
- event: (args: { x: number, y: number }) => {
- const newDoc = Doc.ApplyTemplate(dragDoc);
+ event: undoBatch((args: { x: number, y: number }) => {
+ const newDoc = Doc.copyDragFactory(dragDoc);
if (newDoc) {
newDoc.author = Doc.CurrentUserEmail;
newDoc.x = x;
newDoc.y = y;
+ if (newDoc.type === DocumentType.RTF) FormattedTextBox.SelectOnLoad = newDoc[Id];
docAdder(newDoc);
}
- },
+ }),
icon: "eye"
})) as ContextMenuProps[],
icon: "eye"
@@ -1171,7 +1231,7 @@ export namespace DocUtils {
}
const options = optionsCollection as Doc;
const targetDoc = doc && Doc.GetProto(Cast(doc.rootDocument, Doc, null) || doc);
- const docFind = `options.data.find(doc => doc.title === (this.rootDocument||this)["${enumeratedFieldKey}"])?`;
+ const docFind = `options.data?.find(doc => doc.title === (this.rootDocument||this)["${enumeratedFieldKey}"])?`;
targetDoc && (targetDoc.backgroundColor = ComputedField.MakeFunction(docFind + `._backgroundColor || "white"`, undefined, { options }));
targetDoc && (targetDoc.color = ComputedField.MakeFunction(docFind + `.color || "black"`, undefined, { options }));
targetDoc && (targetDoc.borderRounding = ComputedField.MakeFunction(docFind + `.borderRounding`, undefined, { options }));
@@ -1204,8 +1264,14 @@ export namespace DocUtils {
proto.text = result.rawText;
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);
+ const maxNativeDim = Math.min(Math.max(result.nativeHeight, result.nativeWidth), defaultNativeImageDim);
+ proto["data-nativeOrientation"] = result.exifData?.data?.image?.Orientation;
+ proto["data-nativeWidth"] = (result.nativeWidth < result.nativeHeight) ? maxNativeDim * result.nativeWidth / result.nativeHeight : maxNativeDim;
+ proto["data-nativeHeight"] = (result.nativeWidth < result.nativeHeight) ? maxNativeDim : maxNativeDim / (result.nativeWidth / result.nativeHeight);
+ if (Number(result.exifData?.data?.image?.Orientation) >= 5) {
+ proto["data-nativeHeight"] = (result.nativeWidth < result.nativeHeight) ? maxNativeDim * result.nativeWidth / result.nativeHeight : maxNativeDim;
+ proto["data-nativeWidth"] = (result.nativeWidth < result.nativeHeight) ? maxNativeDim : maxNativeDim / (result.nativeWidth / result.nativeHeight);
+ }
proto.contentSize = result.contentSize;
}
generatedDocuments.push(doc);