aboutsummaryrefslogtreecommitdiff
path: root/src/client/documents/Documents.ts
diff options
context:
space:
mode:
authorMichael Foiani <sotech117@michaels-mbp-3.devices.brown.edu>2022-04-28 17:31:27 -0400
committerMichael Foiani <sotech117@michaels-mbp-3.devices.brown.edu>2022-04-28 17:31:27 -0400
commit813ac366831c95f3fa11e01b9588cf18cbe466bc (patch)
tree24a98e427543ff57c9396918ff12ae1cf81a5a92 /src/client/documents/Documents.ts
parentf8503355ff82930e640369637c33d989fd7eaff3 (diff)
parent22fe2791b6a6e92cc4d0ad953363120b51bd6e2c (diff)
Handle merge conflicts with jenny work
Diffstat (limited to 'src/client/documents/Documents.ts')
-rw-r--r--src/client/documents/Documents.ts109
1 files changed, 69 insertions, 40 deletions
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 9bcd23aa0..8f92e9313 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -11,10 +11,10 @@ import { RichTextField } from "../../fields/RichTextField";
import { SchemaHeaderField } from "../../fields/SchemaHeaderField";
import { ComputedField, ScriptField } from "../../fields/ScriptField";
import { Cast, NumCast, StrCast } from "../../fields/Types";
-import { AudioField, ImageField, MapField, PdfField, VideoField, WebField, YoutubeField } from "../../fields/URLField";
+import { AudioField, ImageField, MapField, PdfField, RecordingField, VideoField, WebField, YoutubeField } from "../../fields/URLField";
import { SharingPermissions } from "../../fields/util";
import { Upload } from "../../server/SharedMediaTypes";
-import { OmitKeys, Utils } from "../../Utils";
+import { OmitKeys, Utils, aggregateBounds } from "../../Utils";
import { YoutubeBox } from "../apis/youtube/YoutubeBox";
import { DocServer } from "../DocServer";
import { Networking } from "../Network";
@@ -61,6 +61,7 @@ import { DashWebRTCVideo } from "../views/webcam/DashWebRTCVideo";
import { DocumentType } from "./DocumentTypes";
import { IconProp } from "@fortawesome/fontawesome-svg-core";
import { MapBox } from "../views/nodes/MapBox/MapBox";
+import { RecordingBox } from "../views/nodes/RecordingBox/RecordingBox";
const defaultNativeImageDim = Number(DFLT_IMAGE_NATIVE_DIM.replace("px", ""));
class EmptyBox {
@@ -117,6 +118,7 @@ export class DocumentOptions {
_lockedPosition?: boolean; // lock the x,y coordinates of the document so that it can't be dragged
_lockedTransform?: boolean; // lock the panx,pany and scale parameters of the document so that it be panned/zoomed
_freeformLOD?: boolean; // whether to use LOD to render a freeform document
+ _isPushpin?: boolean; // whether document, when clicked, toggles display of its link target
_showTitle?: string; // field name to display in header (:hover is an optional suffix)
_showCaption?: string; // which field to display in the caption area. leave empty to have no caption
_scrollTop?: number; // scroll location for pdfs
@@ -139,6 +141,8 @@ export class DocumentOptions {
_itemIndex?: number; // which item index the carousel viewer is showing
_showSidebar?: boolean; //whether an annotationsidebar should be displayed for text docuemnts
_singleLine?: boolean; // whether text document is restricted to a single line (carriage returns make new document)
+ _minFontSize?: number; // minimum font size for labelBoxes
+ _maxFontSize?: number; // maximum font size for labelBoxes
_columnWidth?: number;
_columnsHideIfEmpty?: boolean; // whether stacking view column headings should be hidden
_fontSize?: string;
@@ -221,6 +225,7 @@ export class DocumentOptions {
dockingConfig?: string;
annotationOn?: Doc;
isPushpin?: boolean;
+ isGroup?: boolean; // whether a collection should use a grouping UI behavior
_removeDropProperties?: List<string>; // list of properties that should be removed from a document when it is dropped. e.g., a creator button may be forceActive to allow it be dragged, but the forceActive property can be removed from the dropped document
// BACKGROUND GRID
@@ -278,8 +283,10 @@ export class DocumentOptions {
strokeWidth?: number;
freezeChildren?: string; // whether children are now allowed to be added and or removed from a collection
treeViewHideTitle?: boolean; // whether to hide the top document title of a tree view
+ treeViewHideHeaderIfTemplate?: boolean; // whether to hide the header for a document in a tree view only if a childLayoutTemplate is provided (presBox)
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.
+ treeViewGrowsHorizontally?: boolean; // whether an embedded tree view of the document can grow horizontally without growing vertically
// Action Button
buttonMenu?: boolean; // whether a action button should be displayed
@@ -361,7 +368,7 @@ export namespace Docs {
[DocumentType.RTF, {
layout: { view: FormattedTextBox, dataField: "text" },
options: {
- _height: 150, _xMargin: 10, _yMargin: 10, nativeDimModifiable: true, nativeHeightUnfrozen: true,
+ _height: 150, _xMargin: 10, _yMargin: 10, nativeDimModifiable: true, nativeHeightUnfrozen: true, treeViewGrowsHorizontally: true,
links: "@links(self)"
}
}],
@@ -401,6 +408,10 @@ export namespace Docs {
layout: { view: AudioBox, dataField: defaultDataKey },
options: { _height: 100, backgroundColor: "lightGray", links: "@links(self)" }
}],
+ [DocumentType.REC, {
+ layout: { view: VideoBox, dataField: defaultDataKey },
+ options: { _height: 100, backgroundColor: "pink", links: "@links(self)" }
+ }],
[DocumentType.PDF, {
layout: { view: PDFBox, dataField: defaultDataKey },
options: { _curPage: 1, _fitWidth: true, nativeDimModifiable: true, nativeHeightUnfrozen: true, links: "@links(self)" }
@@ -441,7 +452,7 @@ export namespace Docs {
}],
[DocumentType.LABEL, {
layout: { view: LabelBox, dataField: defaultDataKey },
- options: { links: "@links(self)" }
+ options: { links: "@links(self)", _singleLine: true }
}],
[DocumentType.EQUATION, {
layout: { view: EquationBox, dataField: defaultDataKey },
@@ -456,8 +467,8 @@ export namespace Docs {
options: { links: "@links(self)" }
}],
[DocumentType.SLIDER, {
- layout: { view: SliderBox, dataField: defaultDataKey },
- options: { links: "@links(self)" }
+ layout: { view: SliderBox, dataField: defaultDataKey, },
+ options: { links: "@links(self)", treeViewGrowsHorizontally: true }
}],
[DocumentType.PRES, {
layout: { view: PresBox, dataField: defaultDataKey },
@@ -468,7 +479,7 @@ export namespace Docs {
options: { hideLinkButton: true, _width: 40, _height: 40, borderRounding: "100%", links: "@links(self)" },
}],
[DocumentType.WEBCAM, {
- layout: { view: DashWebRTCVideo, dataField: defaultDataKey },
+ layout: { view: RecordingBox, dataField: defaultDataKey },
options: { links: "@links(self)" }
}],
[DocumentType.PRESELEMENT, {
@@ -699,6 +710,10 @@ export namespace Docs {
{ ...options, backgroundColor: ComputedField.MakeFunction("this._mediaState === 'playing' ? 'green':'gray'") as any });
}
+ export function RecordingDocument(url: string, options: DocumentOptions = {}) {
+ return InstanceFromProto(Prototypes.get(DocumentType.REC), "", options);
+ }
+
export function SearchDocument(options: DocumentOptions = {}) {
return InstanceFromProto(Prototypes.get(DocumentType.SEARCH), new List<Doc>([]), options);
}
@@ -745,7 +760,7 @@ export namespace Docs {
I.layout = InkingStroke.LayoutString("data");
I.color = color;
I.hideDecorationTitle = true; // don't show title when selected
- I.hideOpenButton = true; // don't show open full screen button when selected
+ // I.hideOpenButton = true; // don't show open full screen button when selected
I.fillColor = fillColor;
I.strokeWidth = strokeWidth;
I.strokeBezier = strokeBezier;
@@ -765,7 +780,7 @@ export namespace Docs {
I.data = new InkField(points);
I["acl-Public"] = Doc.UserDoc()?.defaultAclPrivate ? SharingPermissions.None : SharingPermissions.Augment;
I["acl-Override"] = "None";
- I.links = "@links(self)";
+ I.links = ComputedField.MakeFunction("links(self)");
I[Initializing] = false;
return I;
}
@@ -805,7 +820,7 @@ export namespace Docs {
}
export function FreeformDocument(documents: Array<Doc>, options: DocumentOptions, id?: string) {
- const inst = InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { ...options, _viewType: CollectionViewType.Freeform }, id);
+ const inst = InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { _xPadding: 20, _yPadding: 20, ...options, _viewType: CollectionViewType.Freeform }, id);
documents.map(d => d.context = inst);
return inst;
}
@@ -823,7 +838,7 @@ export namespace Docs {
}
export function PileDocument(documents: Array<Doc>, options: DocumentOptions, id?: string) {
- return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { _noAutoscroll: true, ...options, _viewType: CollectionViewType.Pile }, id);
+ return InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { _overflow: "visible", _forceActive: true, _noAutoscroll: true, ...options, _viewType: CollectionViewType.Pile }, id);
}
export function LinearDocument(documents: Array<Doc>, options: DocumentOptions, id?: string) {
@@ -1089,10 +1104,11 @@ export namespace DocUtils {
export function MakeLinkToActiveAudio(getSourceDoc: () => Doc, broadcastEvent = true) {
broadcastEvent && runInAction(() => DocumentManager.Instance.RecordingEvent = DocumentManager.Instance.RecordingEvent + 1);
return DocUtils.ActiveRecordings.map(audio =>
- DocUtils.MakeLink({ doc: getSourceDoc() }, { doc: audio.getAnchor() || audio.props.Document }, "recording link", "recording timeline"));
+ DocUtils.MakeLink({ doc: getSourceDoc() }, { doc: audio.getAnchor() || audio.props.Document }, "recording annotation:linked recording", "recording timeline"));
}
export function MakeLink(source: { doc: Doc }, target: { doc: Doc }, linkRelationship: string = "", description: string = "", id?: string, allowParCollectionLink?: boolean, showPopup?: number[]) {
+ if (!linkRelationship) linkRelationship = target.doc.type === DocumentType.RTF ? "Commentary:Comments On" : "link";
const sv = DocumentManager.Instance.getDocumentView(source.doc);
if (!allowParCollectionLink && sv?.props.ContainingCollectionDoc === target.doc) return;
if (target.doc === Doc.UserDoc()) return undefined;
@@ -1160,6 +1176,9 @@ export namespace DocUtils {
} else if (field instanceof AudioField) {
created = Docs.Create.AudioDocument((field).url.href, resolved);
layout = AudioBox.LayoutString;
+ } else if (field instanceof RecordingField) {
+ created = Docs.Create.RecordingDocument((field).url.href, resolved);
+ layout = RecordingBox.LayoutString;
} else if (field instanceof InkField) {
created = Docs.Create.InkDocument(ActiveInkColor(), CurrentUserUtils.SelectedTool, ActiveInkWidth(), ActiveInkBezierApprox(), ActiveFillColor(), ActiveArrowStart(), ActiveArrowEnd(), ActiveDash(), (field).inkData, resolved);
layout = InkingStroke.LayoutString;
@@ -1315,22 +1334,25 @@ export namespace DocUtils {
const _height = NumCast(doc._height);
const options = { title: "data", backgroundColor: StrCast(doc.backgroundColor), _autoHeight: true, _width, x: -_width / 2, y: - _height / 2, _showSidebar: false };
- let fieldTemplate: Opt<Doc>;
- if (doc.data instanceof RichTextField || typeof (doc.data) === "string") {
- fieldTemplate = Docs.Create.TextDocument("", options);
- } else if (doc.data instanceof PdfField) {
- fieldTemplate = Docs.Create.PdfDocument("http://www.msn.com", options);
- } else if (doc.data instanceof VideoField) {
- fieldTemplate = Docs.Create.VideoDocument("http://www.cs.brown.edu", options);
- } else if (doc.data instanceof AudioField) {
- fieldTemplate = Docs.Create.AudioDocument("http://www.cs.brown.edu", options);
- } else if (doc.data instanceof ImageField) {
- fieldTemplate = Docs.Create.ImageDocument("http://www.cs.brown.edu", options);
- }
- const docTemplate = docLayoutTemplate || creator?.(fieldTemplate ? [fieldTemplate] : [], { title: customName + "(" + doc.title + ")", isTemplateDoc: true, _width: _width + 20, _height: Math.max(100, _height + 45) });
-
- fieldTemplate && Doc.MakeMetadataFieldTemplate(fieldTemplate, docTemplate ? Doc.GetProto(docTemplate) : docTemplate);
- docTemplate && Doc.ApplyTemplateTo(docTemplate, doc, customName, undefined);
+ if (docLayoutTemplate) {
+ Doc.ApplyTemplateTo(docLayoutTemplate, doc, customName, undefined);
+ } else {
+ let fieldTemplate: Opt<Doc>;
+ if (doc.data instanceof RichTextField || typeof (doc.data) === "string") {
+ fieldTemplate = Docs.Create.TextDocument("", options);
+ } else if (doc.data instanceof PdfField) {
+ fieldTemplate = Docs.Create.PdfDocument("http://www.msn.com", options);
+ } else if (doc.data instanceof VideoField) {
+ fieldTemplate = Docs.Create.VideoDocument("http://www.cs.brown.edu", options);
+ } else if (doc.data instanceof AudioField) {
+ fieldTemplate = Docs.Create.AudioDocument("http://www.cs.brown.edu", options);
+ } else if (doc.data instanceof ImageField) {
+ fieldTemplate = Docs.Create.ImageDocument("http://www.cs.brown.edu", options);
+ }
+ const docTemplate = creator?.(fieldTemplate ? [fieldTemplate] : [], { title: customName + "(" + doc.title + ")", isTemplateDoc: true, _width: _width + 20, _height: Math.max(100, _height + 45) });
+ fieldTemplate && Doc.MakeMetadataFieldTemplate(fieldTemplate, docTemplate ? Doc.GetProto(docTemplate) : docTemplate);
+ docTemplate && Doc.ApplyTemplateTo(docTemplate, doc, customName, undefined);
+ }
}
export function makeCustomView(doc: Doc, custom: boolean, layout: string) {
Doc.setNativeView(doc);
@@ -1344,27 +1366,34 @@ export namespace DocUtils {
if (layoutKey && layoutKey !== "layout" && layoutKey !== "layout_icon") doc.deiconifyLayout = layoutKey.replace("layout_", "");
}
- export function pileup(docList: Doc[], x?: number, y?: number) {
+ export function pileup(docList: Doc[], x?: number, y?: number, size: number = 55, create: boolean = true) {
let w = 0, h = 0;
runInAction(() => {
docList.forEach(d => {
DocUtils.iconify(d);
- w = Math.max(d[WidthSym](), w);
- h = Math.max(d[HeightSym](), h);
+ w = Math.max(NumCast(d._width), w);
+ h = Math.max(NumCast(d._height), h);
+ });
+ docList.forEach((d, i) => {
+ d.x = Math.cos(Math.PI * 2 * i / docList.length) * size;
+ d.y = Math.sin(Math.PI * 2 * i / docList.length) * size;
+ d._timecodeToShow = undefined; // bcz: this should be automatic somehow.. along with any other properties that were logically associated with the original collection
});
- h = Math.max(h, w * 4 / 3); // converting to an icon does not update the height right away. so this is a fallback hack to try to do something reasonable
+ const aggBounds = aggregateBounds(docList.map(d => ({ x: NumCast(d.x), y: NumCast(d.y), width: NumCast(d._width), height: NumCast(d._height) })), 0, 0);
docList.forEach((d, i) => {
- d.x = Math.cos(Math.PI * 2 * i / docList.length) * 10 - w / 2;
- d.y = Math.sin(Math.PI * 2 * i / docList.length) * 10 - h / 2;
+ d.x = NumCast(d.x) - ((aggBounds.r + aggBounds.x) / 2);
+ d.y = NumCast(d.y) - ((aggBounds.b + aggBounds.y) / 2);
d._timecodeToShow = undefined; // bcz: this should be automatic somehow.. along with any other properties that were logically associated with the original collection
});
});
- const newCollection = Docs.Create.PileDocument(docList, { title: "pileup", x: (x || 0) - 55, y: (y || 0) - 55, _width: 110, _height: 100, _overflow: "visible" });
- newCollection.x = NumCast(newCollection.x) + NumCast(newCollection._width) / 2 - 55;
- newCollection.y = NumCast(newCollection.y) + NumCast(newCollection._height) / 2 - 55;
- newCollection._width = newCollection._height = 110;
- newCollection._jitterRotation = 10;
- return newCollection;
+ if (create) {
+ const newCollection = Docs.Create.PileDocument(docList, { title: "pileup", x: (x || 0) - size, y: (y || 0) - size, _width: size * 2, _height: size * 2, });
+ newCollection.x = NumCast(newCollection.x) + NumCast(newCollection._width) / 2 - size;
+ newCollection.y = NumCast(newCollection.y) + NumCast(newCollection._height) / 2 - size;
+ newCollection._width = newCollection._height = size * 2;
+ newCollection._jitterRotation = 10;
+ return newCollection;
+ }
}
export function LeavePushpin(doc: Doc, annotationField: string) {