aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorusodhi <61431818+usodhi@users.noreply.github.com>2020-12-10 22:28:43 +0530
committerusodhi <61431818+usodhi@users.noreply.github.com>2020-12-10 22:28:43 +0530
commit563d86f03f63f60ec47aef23d2022c660ee18697 (patch)
treeefd71242ac43dba47e7d44da3d4874dcc8f71d3e
parent49491180cfbc03b72867970043b674dc1362cc81 (diff)
parent3412313dcde569f1f23616fa5e8a92c3985e0449 (diff)
merging
-rw-r--r--src/client/views/GestureOverlay.tsx1
-rw-r--r--src/client/views/MainView.tsx9
-rw-r--r--src/client/views/OverlayView.tsx1
-rw-r--r--src/client/views/Palette.tsx1
-rw-r--r--src/client/views/PropertiesView.tsx3
-rw-r--r--src/client/views/ScriptBox.tsx1
-rw-r--r--src/client/views/TemplateMenu.tsx1
-rw-r--r--src/client/views/collections/CollectionCarouselView.tsx2
-rw-r--r--src/client/views/collections/CollectionDockingView.tsx2
-rw-r--r--src/client/views/collections/CollectionLinearView.tsx1
-rw-r--r--src/client/views/collections/CollectionSchemaView.tsx1
-rw-r--r--src/client/views/collections/CollectionStackingView.tsx1
-rw-r--r--src/client/views/collections/CollectionTreeView.tsx3
-rw-r--r--src/client/views/collections/CollectionView.tsx2
-rw-r--r--src/client/views/collections/SchemaTable.tsx1
-rw-r--r--src/client/views/collections/TabDocView.tsx23
-rw-r--r--src/client/views/collections/TreeView.tsx78
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx18
-rw-r--r--src/client/views/collections/collectionFreeForm/MarqueeView.tsx394
-rw-r--r--src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx1
-rw-r--r--src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx1
-rw-r--r--src/client/views/nodes/AudioBox.tsx92
-rw-r--r--src/client/views/nodes/CollectionFreeFormDocumentView.tsx232
-rw-r--r--src/client/views/nodes/ContentFittingDocumentView.tsx1
-rw-r--r--src/client/views/nodes/DocHolderBox.tsx4
-rw-r--r--src/client/views/nodes/DocumentView.tsx52
-rw-r--r--src/client/views/nodes/FieldView.tsx3
-rw-r--r--src/client/views/nodes/FilterBox.tsx1
-rw-r--r--src/client/views/nodes/FontIconBox.tsx2
-rw-r--r--src/client/views/nodes/KeyValuePair.tsx1
-rw-r--r--src/client/views/nodes/LinkBox.tsx2
-rw-r--r--src/client/views/nodes/LinkDocPreview.tsx11
-rw-r--r--src/client/views/nodes/PresBox.tsx39
-rw-r--r--src/client/views/nodes/formattedText/DashDocView.tsx1
-rw-r--r--src/client/views/nodes/formattedText/FormattedTextBox.tsx142
-rw-r--r--src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx1
-rw-r--r--src/client/views/nodes/formattedText/RichTextSchema.tsx1
-rw-r--r--src/client/views/pdf/PDFViewer.tsx1
-rw-r--r--src/client/views/presentationview/PresElementBox.tsx3
-rw-r--r--src/fields/Doc.ts1
-rw-r--r--src/fields/ScriptField.ts17
-rw-r--r--src/mobile/AudioUpload.tsx1
-rw-r--r--src/mobile/MobileInterface.tsx1
-rw-r--r--src/server/websocket.ts4
44 files changed, 456 insertions, 702 deletions
diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx
index 35dedf016..c60060095 100644
--- a/src/client/views/GestureOverlay.tsx
+++ b/src/client/views/GestureOverlay.tsx
@@ -889,7 +889,6 @@ export class GestureOverlay extends Touchable {
<DocumentView
Document={doc}
DataDoc={undefined}
- LibraryPath={emptyPath}
addDocument={undefined}
addDocTab={returnFalse}
rootSelected={returnTrue}
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 747bde64d..9b3d5c6ae 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -244,7 +244,6 @@ export class MainView extends React.Component {
return <DocumentView
Document={this.mainContainer!}
DataDoc={undefined}
- LibraryPath={emptyPath}
addDocument={undefined}
addDocTab={this.addDocTabFunc}
pinToPres={emptyFunction}
@@ -294,7 +293,7 @@ export class MainView extends React.Component {
flyoutWidthFunc = () => this._flyoutWidth;
sidebarScreenToLocal = () => new Transform(0, -this.topOffset, 1);
mainContainerXf = () => this.sidebarScreenToLocal().translate(-this.leftOffset, 0);
- addDocTabFunc = (doc: Doc, where: string, libraryPath?: Doc[]): boolean => {
+ addDocTabFunc = (doc: Doc, where: string): boolean => {
return where === "close" ? CollectionDockingView.CloseSplit(doc) :
doc.dockingConfig ? CurrentUserUtils.openDashboard(Doc.UserDoc(), doc) : CollectionDockingView.AddSplit(doc, "right");
}
@@ -308,7 +307,6 @@ export class MainView extends React.Component {
<DocumentView
Document={this._sidebarContent.proto || this._sidebarContent}
DataDoc={undefined}
- LibraryPath={emptyPath}
addDocument={undefined}
addDocTab={this.addDocTabFunc}
pinToPres={emptyFunction}
@@ -342,7 +340,6 @@ export class MainView extends React.Component {
<DocumentView
Document={Doc.UserDoc().menuStack as Doc}
DataDoc={undefined}
- LibraryPath={emptyPath}
addDocument={undefined}
addDocTab={this.addDocTabFunc}
pinToPres={emptyFunction}
@@ -457,7 +454,6 @@ export class MainView extends React.Component {
<CollectionLinearView
Document={this.userDoc.dockedBtns}
DataDoc={undefined}
- LibraryPath={emptyPath}
fieldKey={"data"}
dropAction={"alias"}
annotationsKey={""}
@@ -532,7 +528,6 @@ export class MainView extends React.Component {
isSelected={returnTrue}
active={returnTrue}
select={this.select}
- LibraryPath={emptyPath}
addDocument={undefined}
addDocTab={this.addDocTabFunc}
pinToPres={emptyFunction}
@@ -565,7 +560,6 @@ export class MainView extends React.Component {
ContainingCollectionView={undefined}
ContainingCollectionDoc={undefined}
Document={DocumentLinksButton.invisibleWebDoc}
- LibraryPath={emptyPath}
dropAction={"move"}
isSelected={returnFalse}
select={returnFalse}
@@ -632,7 +626,6 @@ export class MainView extends React.Component {
ContainingCollectionView={undefined}
ContainingCollectionDoc={undefined}
Document={invisibleDoc}
- LibraryPath={emptyPath}
dropAction={"move"}
isSelected={returnFalse}
select={returnFalse}
diff --git a/src/client/views/OverlayView.tsx b/src/client/views/OverlayView.tsx
index 37e5b55eb..b7bd88344 100644
--- a/src/client/views/OverlayView.tsx
+++ b/src/client/views/OverlayView.tsx
@@ -182,7 +182,6 @@ export class OverlayView extends React.Component {
return <div className="overlayView-doc" ref={dref} key={d[Id]} onPointerDown={onPointerDown} style={{ top: d.type === 'presentation' ? 0 : undefined, width: NumCast(d._width), height: NumCast(d._height), transform: `translate(${d.x}px, ${d.y}px)` }}>
<DocumentView
Document={d}
- LibraryPath={emptyPath}
ChromeHeight={returnZero}
rootSelected={returnTrue}
bringToFront={emptyFunction}
diff --git a/src/client/views/Palette.tsx b/src/client/views/Palette.tsx
index 536af2776..b31cfd7d2 100644
--- a/src/client/views/Palette.tsx
+++ b/src/client/views/Palette.tsx
@@ -40,7 +40,6 @@ export default class Palette extends React.Component<PaletteProps> {
<DocumentView
Document={this.props.thumbDoc}
DataDoc={undefined}
- LibraryPath={emptyPath}
addDocument={undefined}
addDocTab={returnFalse}
rootSelected={returnTrue}
diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx
index 14fa6ff7c..c022f6684 100644
--- a/src/client/views/PropertiesView.tsx
+++ b/src/client/views/PropertiesView.tsx
@@ -37,7 +37,7 @@ const _global = (window /* browser */ || global /* node */) as any;
interface PropertiesViewProps {
width: number;
height: number;
- styleProvider?: (doc: Opt<Doc>, props: Opt<DocumentViewProps>, property: string, layerProvider?: (doc: Doc, assign?: boolean) => boolean) => any;
+ styleProvider?: (doc: Opt<Doc>, props: Opt<DocumentViewProps>, property: string) => any;
}
@observer
@@ -267,7 +267,6 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
<ContentFittingDocumentView
Document={layoutDoc}
DataDoc={this.dataDoc}
- LibraryPath={emptyPath}
renderDepth={1}
rootSelected={returnFalse}
treeViewDoc={undefined}
diff --git a/src/client/views/ScriptBox.tsx b/src/client/views/ScriptBox.tsx
index 2c185be86..e2b5d8dc3 100644
--- a/src/client/views/ScriptBox.tsx
+++ b/src/client/views/ScriptBox.tsx
@@ -12,7 +12,6 @@ import { CompileScript } from "../util/Scripting";
import { ScriptField } from "../../fields/ScriptField";
import { DragManager } from "../util/DragManager";
import { EditableView } from "./EditableView";
-import { getEffectiveTypeRoots } from "typescript";
export interface ScriptBoxProps {
onSave: (text: string, onError: (error: string) => void) => void;
diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx
index 68f30d58c..9c5c70c60 100644
--- a/src/client/views/TemplateMenu.tsx
+++ b/src/client/views/TemplateMenu.tsx
@@ -136,7 +136,6 @@ export class TemplateMenu extends React.Component<TemplateMenuProps> {
rootSelected={returnFalse}
onCheckedClick={this.scriptField}
onChildClick={this.scriptField}
- LibraryPath={emptyPath}
dropAction={undefined}
active={returnTrue}
parentActive={returnFalse}
diff --git a/src/client/views/collections/CollectionCarouselView.tsx b/src/client/views/collections/CollectionCarouselView.tsx
index 62c1bce3f..16ccdc6f4 100644
--- a/src/client/views/collections/CollectionCarouselView.tsx
+++ b/src/client/views/collections/CollectionCarouselView.tsx
@@ -65,7 +65,7 @@ export class CollectionCarouselView extends CollectionSubView(CarouselDocument)
</div>
<div className="collectionCarouselView-caption" key="caption"
style={{
- background: StrCast(this.layoutDoc._captionBackgroundColor, this.props.styleProvider?.(this.props.Document, this.props, "backgroundColor", this.props.layerProvider)),
+ background: StrCast(this.layoutDoc._captionBackgroundColor, this.props.styleProvider?.(this.props.Document, this.props, "backgroundColor")),
color: StrCast(this.layoutDoc._captionColor, StrCast(this.layoutDoc.color)),
borderRadius: StrCast(this.layoutDoc._captionBorderRounding),
}}>
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index 57b038c73..eee939c07 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -90,7 +90,7 @@ export class CollectionDockingView extends CollectionSubView(doc => doc) {
}
@undoBatch
- public static OpenFullScreen(doc: Doc, libraryPath?: Doc[]) {
+ public static OpenFullScreen(doc: Doc) {
const instance = CollectionDockingView.Instance;
if (doc._viewType === CollectionViewType.Docking && doc.layoutKey === "layout") {
return CurrentUserUtils.openDashboard(Doc.UserDoc(), doc);
diff --git a/src/client/views/collections/CollectionLinearView.tsx b/src/client/views/collections/CollectionLinearView.tsx
index b427e35c3..c7c510306 100644
--- a/src/client/views/collections/CollectionLinearView.tsx
+++ b/src/client/views/collections/CollectionLinearView.tsx
@@ -140,7 +140,6 @@ export class CollectionLinearView extends CollectionSubView(LinearDocument) {
<ContentFittingDocumentView
Document={pair.layout}
DataDoc={pair.data}
- LibraryPath={this.props.LibraryPath}
addDocument={this.props.addDocument}
moveDocument={this.props.moveDocument}
addDocTab={this.props.addDocTab}
diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx
index a1df9d214..8ae70ce20 100644
--- a/src/client/views/collections/CollectionSchemaView.tsx
+++ b/src/client/views/collections/CollectionSchemaView.tsx
@@ -404,7 +404,6 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) {
FreezeDimensions={true}
dontCenter={"y"}
focus={emptyFunction}
- LibraryPath={this.props.LibraryPath}
renderDepth={this.props.renderDepth}
rootSelected={this.rootSelected}
PanelWidth={this.previewWidth}
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 4b3393e14..0e4029764 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -195,7 +195,6 @@ export class CollectionStackingView extends CollectionSubView<StackingDocument,
styleProvider={this.props.styleProvider}
LayoutTemplate={this.props.ChildLayoutTemplate}
LayoutTemplateString={this.props.ChildLayoutString}
- LibraryPath={this.props.LibraryPath}
FreezeDimensions={this.props.freezeChildDimensions}
renderDepth={this.props.renderDepth + 1}
PanelWidth={width}
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index add008952..572aae260 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -163,7 +163,6 @@ export class CollectionTreeView extends CollectionSubView<Document, Partial<coll
Document={this.doc}
DataDoc={undefined}
LayoutTemplateString={FormattedTextBox.LayoutString("text")}
- LibraryPath={emptyPath}
renderDepth={this.props.renderDepth + 1}
rootSelected={returnTrue}
treeViewDoc={undefined}
@@ -216,7 +215,7 @@ export class CollectionTreeView extends CollectionSubView<Document, Partial<coll
render() {
TraceMobx();
if (!(this.doc instanceof Doc)) return (null);
- const background = this.props.styleProvider?.(this.doc, this.props, "backgroundColor", this.props.layerProvider);
+ const background = this.props.styleProvider?.(this.doc, this.props, "backgroundColor");
const paddingX = `${NumCast(this.doc._xPadding, 10)}px`;
const paddingTop = `${NumCast(this.doc._yPadding, 20)}px`;
// const pointerEvents = !this.props.active() && !SnappingManager.GetIsDragging() && !this._isChildActive ? "none" : undefined;
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 0a9eeab50..8f402c427 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -399,7 +399,7 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
ChildLayoutString: this.childLayoutString,
};
const boxShadow = Doc.UserDoc().renderStyle === "comic" || this.props.Document.treeViewOutlineMode || this.collectionViewType === CollectionViewType.Linear ? undefined :
- this.props.styleProvider?.(this.props.Document, this.props, "boxShadow", this.props.layerProvider);
+ this.props.styleProvider?.(this.props.Document, this.props, "boxShadow");
return (<div className={"collectionView"} onContextMenu={this.onContextMenu}
style={{ pointerEvents: this.props.layerProvider?.(this.props.Document) === false ? "none" : undefined, boxShadow }}>
{this.showIsTagged()}
diff --git a/src/client/views/collections/SchemaTable.tsx b/src/client/views/collections/SchemaTable.tsx
index 087d106c5..664b6115a 100644
--- a/src/client/views/collections/SchemaTable.tsx
+++ b/src/client/views/collections/SchemaTable.tsx
@@ -573,7 +573,6 @@ export class SchemaTable extends React.Component<SchemaTableProps> {
fitToBox={true}
FreezeDimensions={true}
focus={emptyFunction}
- LibraryPath={emptyPath}
renderDepth={this.props.renderDepth}
rootSelected={() => false}
PanelWidth={() => 150}
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index 1026f043c..e1fd47592 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -32,7 +32,6 @@ import React = require("react");
import { List } from '../../../fields/List';
import { DocumentType } from '../../documents/DocumentTypes';
import Color = require('color');
-import { InkTool } from '../../../fields/InkField';
const _global = (window /* browser */ || global /* node */) as any;
interface TabDocViewProps {
@@ -289,7 +288,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
// "replace:right" - will replace the stack on the right named "right" if it exists, or create a stack on the right with that name,
// "replace:monkeys" - will replace any tab that has the label 'monkeys', or a tab with that label will be created by default on the right
// inPlace - will add the document to any collection along the path from the document to the docking view that has a field isInPlaceContainer. if none is found, inPlace adds a tab to current stack
- addDocTab = (doc: Doc, location: string, libraryPath?: Doc[]) => {
+ addDocTab = (doc: Doc, location: string) => {
SelectionManager.DeselectAll();
const locationFields = doc._viewType === CollectionViewType.Docking ? ["dashboard"] : location.split(":");
const locationParams = locationFields.length > 1 ? locationFields[1] : "";
@@ -336,7 +335,6 @@ export class TabDocView extends React.Component<TabDocViewProps> {
<div className="miniMap" style={{ width: miniSize, height: miniSize, background: this.tabColor }}>
<CollectionFreeFormView
Document={this._document!}
- LibraryPath={emptyPath}
CollectionView={undefined}
ContainingCollectionView={undefined}
ContainingCollectionDoc={undefined}
@@ -417,9 +415,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
}
}
- @undoBatch
- @action
- static toggleBackground = (doc: Doc) => {
+ static toggleBackground = undoBatch(action((doc: Doc) => {
const layers = StrListCast(doc.layers);
if (!layers.includes("background")) {
if (!layers.length) doc.layers = new List<string>(["background"]);
@@ -434,11 +430,11 @@ export class TabDocView extends React.Component<TabDocViewProps> {
// Doc.SetNativeWidth(this.props.Document[DataSym], wid);
// Doc.SetNativeHeight(this.props.Document[DataSym], hgt);
}
- }
+ }));
//
// a preliminary implementation of a dash style sheet for setting rendering properties of documents nested within a Tab
//
- public static styleProvider = (doc: Opt<Doc>, props: DocumentViewProps | undefined, property: string, layerProvider?: (doc: Doc, assign?: boolean) => boolean): any => {
+ public static styleProvider = (doc: Opt<Doc>, props: DocumentViewProps | undefined, property: string): any => {
switch (property) {
case "backgroundColor": {
if (Doc.UserDoc().renderStyle === "comic") return undefined;
@@ -460,11 +456,11 @@ export class TabDocView extends React.Component<TabDocViewProps> {
default: docColor = TabDocView.darkScheme ? "black" : "white"; break;
}
}
- if (docColor && (!doc || layerProvider?.(doc) === false)) docColor = Color(docColor).fade(0.5).toString();
+ if (docColor && (!doc || props?.layerProvider?.(doc) === false)) docColor = Color(docColor).fade(0.5).toString();
return docColor;
}
case "widgetColor": return TabDocView.darkScheme ? "lightgrey" : "dimgrey";
- case "hidden": return (BoolCast(doc?.hidden) /* || layerProvider?.(doc) === false*/);
+ case "hidden": return (BoolCast(doc?.hidden) /* || props?.layerProvider?.(doc) === false*/);
case "boxShadow": {
switch (doc?.type) {
case DocumentType.COL: return StrListCast(doc.layers).includes("background") ? undefined :
@@ -475,7 +471,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
case "docContents": return undefined;
default:
if (property.startsWith("pointerEvents")) {
- const layer = doc && layerProvider?.(doc);
+ const layer = doc && props?.layerProvider?.(doc);
if (doc?.Opacity === 0 || doc?.type === DocumentType.INK || doc?.isInkMask) return "none";
if (layer === false && !property.includes(":selected") && !SnappingManager.GetIsDragging()) return "none";
if (doc?.type !== DocumentType.INK && layer === true) return "all";
@@ -492,7 +488,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
}
}
}
- public static miniStyleProvider = (doc: Opt<Doc>, props: Opt<DocumentViewProps>, property: string, layerProvider?: (doc: Doc, assign?: boolean) => boolean): any => {
+ public static miniStyleProvider = (doc: Opt<Doc>, props: Opt<DocumentViewProps>, property: string): any => {
if (doc) {
switch (property) {
case "docContents":
@@ -502,7 +498,7 @@ export class TabDocView extends React.Component<TabDocViewProps> {
return <div style={{ width: doc[WidthSym](), height: doc[HeightSym](), position: "absolute", display: "block", background }} />;
default:
if (property.startsWith("pointerEvents")) return "none";
- return TabDocView.styleProvider(doc, props, property, layerProvider);
+ return TabDocView.styleProvider(doc, props, property);
}
}
}
@@ -510,7 +506,6 @@ export class TabDocView extends React.Component<TabDocViewProps> {
TraceMobx();
return !this._activated || !this._document || this._document._viewType === CollectionViewType.Docking ? (null) :
<><DocumentView key={this._document[Id]}
- LibraryPath={emptyPath}
Document={this._document}
getView={this.setView}
DataDoc={!Doc.AreProtosEqual(this._document[DataSym], this._document) ? this._document[DataSym] : undefined}
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index 31f028727..675ba60c0 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -39,7 +39,7 @@ export interface TreeViewProps {
removeDoc: ((doc: Doc | Doc[]) => boolean) | undefined;
moveDocument: DragManager.MoveFunction;
dropAction: dropActionType;
- addDocTab: (doc: Doc, where: string, libraryPath?: Doc[]) => boolean;
+ addDocTab: (doc: Doc, where: string) => boolean;
pinToPres: (document: Doc) => void;
panelWidth: () => number;
panelHeight: () => number;
@@ -376,15 +376,29 @@ export class TreeView extends React.Component<TreeViewProps> {
if (["links", "annotations", this.fieldKey].includes(expandKey)) {
const remDoc = (doc: Doc | Doc[]) => this.remove(doc, expandKey);
const localAdd = (doc: Doc, addBefore?: Doc, before?: boolean) => {
+ // if there's a sort ordering specified that can be modified on drop (eg, zorder can be modified, alphabetical can't),
+ // then the modification would be done here
+ const ordering = StrCast(this.doc[this.fieldKey + "-sortCriteria"]);
+ if (ordering === "zorder") {
+ const docs = TreeView.sortDocs(this.childDocs || ([] as Doc[]), ordering);
+ doc.zIndex = addBefore ? (before ? NumCast(addBefore.zIndex) - 0.5 : NumCast(addBefore.zIndex) + 0.5) : 1000;
+ docs.push(doc);
+ docs.sort((a, b) => NumCast(a.zIndex) > NumCast(b.zIndex) ? 1 : -1);
+ docs.forEach((d, i) => d.zIndex = i);
+ }
const added = Doc.AddDocToList(this.dataDoc, expandKey, doc, addBefore, before, false, true);
added && (doc.context = this.doc.context);
return added;
};
const addDoc = (doc: Doc | Doc[], addBefore?: Doc, before?: boolean) => (doc instanceof Doc ? [doc] : doc).reduce((flg, doc) => flg && localAdd(doc, addBefore, before), true);
const docs = expandKey === "links" ? this.childLinks : expandKey === "annotations" ? this.childAnnos : this.childDocs;
- const sortKey = `${this.fieldKey}-sortAscending`;
+ const sortKey = `${this.fieldKey}-sortCriteria`;
return <ul key={expandKey + "more"} className={this.doc.treeViewHideTitle ? "no-indent" : ""} onClick={(e) => {
- !this.outlineMode && (this.doc[sortKey] = (this.doc[sortKey] ? false : (this.doc[sortKey] === false ? undefined : true)));
+ !this.outlineMode && (this.doc[sortKey] =
+ (this.doc[sortKey] === "ascending" ? "descending" :
+ (this.doc[sortKey] === "descending" ? "zorder" :
+ (this.doc[sortKey] === "zorder" ? undefined :
+ "ascending"))));
e.stopPropagation();
}}>
{!docs ? (null) :
@@ -507,7 +521,6 @@ export class TreeView extends React.Component<TreeViewProps> {
Document={this.doc}
DataDoc={undefined}
treeViewDoc={this.props.treeView.props.Document}
- LibraryPath={emptyPath}
addDocument={undefined}
addDocTab={this.props.addDocTab}
rootSelected={returnTrue}
@@ -584,7 +597,6 @@ export class TreeView extends React.Component<TreeViewProps> {
focus={asText ? this.refocus : returnFalse}
dontRegisterView={asText ? undefined : this.props.dontRegisterView}
ScreenToLocalTransform={this.docTransform}
- LibraryPath={emptyPath}
renderDepth={this.props.renderDepth + 1}
rootSelected={returnTrue}
treeViewDoc={undefined}
@@ -614,9 +626,9 @@ export class TreeView extends React.Component<TreeViewProps> {
}
@computed get renderBorder() {
- const sorting = this.doc[`${this.fieldKey}-sortAscending`];
+ const sorting = this.doc[`${this.fieldKey}-sortCriteria`];
return <div className={`treeView-border${this.outlineMode ? "outline" : ""}`}
- style={{ borderColor: sorting === undefined ? undefined : sorting ? "crimson" : "blue" }}>
+ style={{ borderColor: sorting === undefined ? undefined : sorting === "ascending" ? "crimson" : sorting === "descending" ? "blue" : "green" }}>
{!this.treeViewOpen ? (null) : this.renderContent}
</div>;
}
@@ -656,6 +668,34 @@ export class TreeView extends React.Component<TreeViewProps> {
</div>;
}
+ public static sortDocs(childDocs: Doc[], criterion: string | undefined) {
+ const docs = childDocs.slice();
+ if (criterion) {
+ const sortAlphaNum = (a: string, b: string): 0 | 1 | -1 => {
+ const reN = /[0-9]*$/;
+ const aA = a.replace(reN, ""); // get rid of trailing numbers
+ const bA = b.replace(reN, "");
+ if (aA === bA) { // if header string matches, then compare numbers numerically
+ const aN = parseInt(a.match(reN)![0], 10);
+ const bN = parseInt(b.match(reN)![0], 10);
+ return aN === bN ? 0 : aN > bN ? 1 : -1;
+ } else {
+ return aA > bA ? 1 : -1;
+ }
+ };
+ docs.sort(function (d1, d2): 0 | 1 | -1 {
+ const a = (criterion === "ascending" ? d2 : d1);
+ const b = (criterion === "ascending" ? d1 : d2);
+ const first = a[criterion === "zorder" ? "zIndex" : "title"];
+ const second = b[criterion === "zorder" ? "zIndex" : "title"];
+ if (typeof first === 'number' && typeof second === 'number') return (first - second) > 0 ? 1 : -1;
+ if (typeof first === 'string' && typeof second === 'string') return sortAlphaNum(first, second);
+ return criterion ? 1 : -1;
+ });
+ }
+ return docs;
+ }
+
public static GetChildElements(
childDocs: Doc[],
treeView: CollectionTreeView,
@@ -691,29 +731,7 @@ export class TreeView extends React.Component<TreeViewProps> {
childDocs = childDocs.filter(d => viewSpecScript.script.run({ doc: d }, console.log).result);
}
- const docs = childDocs.slice();
- const ascending = containingCollection?.[key + "-sortAscending"];
- if (ascending !== undefined) {
- const sortAlphaNum = (a: string, b: string): 0 | 1 | -1 => {
- const reN = /[0-9]*$/;
- const aA = a.replace(reN, ""); // get rid of trailing numbers
- const bA = b.replace(reN, "");
- if (aA === bA) { // if header string matches, then compare numbers numerically
- const aN = parseInt(a.match(reN)![0], 10);
- const bN = parseInt(b.match(reN)![0], 10);
- return aN === bN ? 0 : aN > bN ? 1 : -1;
- } else {
- return aA > bA ? 1 : -1;
- }
- };
- docs.sort(function (a, b): 0 | 1 | -1 {
- const first = (ascending ? b : a).title;
- const second = (ascending ? a : b).title;
- if (typeof first === 'number' && typeof second === 'number') return (first - second) > 0 ? 1 : -1;
- if (typeof first === 'string' && typeof second === 'string') return sortAlphaNum(first, second);
- return ascending ? 1 : -1;
- });
- }
+ const docs = TreeView.sortDocs(childDocs, StrCast(containingCollection?.[key + "-sortCriteria"]));
const rowWidth = () => panelWidth() - 20;
return docs.filter(child => child instanceof Doc).map((child, i) => {
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index ab0c3964b..136600164 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -12,7 +12,7 @@ import { ScriptField } from "../../../../fields/ScriptField";
import { BoolCast, Cast, FieldValue, NumCast, ScriptCast, StrCast } from "../../../../fields/Types";
import { TraceMobx } from "../../../../fields/util";
import { GestureUtils } from "../../../../pen-gestures/GestureUtils";
-import { aggregateBounds, intersectRect, returnFalse, returnOne, returnZero, setupMoveUpEvents, Utils, returnVal } from "../../../../Utils";
+import { aggregateBounds, intersectRect, returnFalse, returnOne, returnZero, setupMoveUpEvents, Utils, returnVal, returnTrue } from "../../../../Utils";
import { CognitiveServices } from "../../../cognitive_services/CognitiveServices";
import { DocServer } from "../../../DocServer";
import { Docs, DocUtils } from "../../../documents/Documents";
@@ -222,14 +222,17 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
const zsorted = this.childLayoutPairs.map(pair => pair.layout).slice().sort((doc1, doc2) => NumCast(doc1.zIndex) - NumCast(doc2.zIndex));
zsorted.forEach((doc, index) => doc.zIndex = doc.isInkMask ? 5000 : index + 1);
const dvals = CollectionFreeFormDocumentView.getValues(refDoc, NumCast(refDoc.activeFrame, 1000));
- const dropPos = this.Document._currentFrame !== undefined ? [dvals.x, dvals.y] : [NumCast(refDoc.x), NumCast(refDoc.y)];
+ const dropPos = this.Document._currentFrame !== undefined ? [dvals.x || 0, dvals.y || 0] : [NumCast(refDoc.x), NumCast(refDoc.y)];
for (let i = 0; i < docDragData.droppedDocuments.length; i++) {
const d = docDragData.droppedDocuments[i];
const layoutDoc = Doc.Layout(d);
if (this.Document._currentFrame !== undefined) {
CollectionFreeFormDocumentView.setupKeyframes([d], this.Document._currentFrame, false);
const vals = CollectionFreeFormDocumentView.getValues(d, NumCast(d.activeFrame, 1000));
- CollectionFreeFormDocumentView.setValues(this.Document._currentFrame, d, x + vals.x - dropPos[0], y + vals.y - dropPos[1], vals.h, vals.w, this.Document.editScrollProgressivize ? vals.scroll : undefined, vals.opacity);
+ vals.x = x + (vals.x || 0) - dropPos[0];
+ vals.y = y + (vals.y || 0) - dropPos[1];
+ vals._scrollTop = this.Document.editScrollProgressivize ? vals._scrollTop : undefined;
+ CollectionFreeFormDocumentView.setValues(this.Document._currentFrame, d, vals);
} else {
d.x = x + NumCast(d.x) - dropPos[0];
d.y = y + NumCast(d.y) - dropPos[1];
@@ -393,8 +396,8 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
}
}
- getClusterColor = (doc: Opt<Doc>, props: Opt<DocumentViewProps>, property: string, layerProvider?: (doc: Doc, assign?: boolean) => boolean) => {
- let clusterColor = this.props.styleProvider?.(doc, props, property, layerProvider); // bcz: check 'props' used to be renderDepth + 1
+ getClusterColor = (doc: Opt<Doc>, props: Opt<DocumentViewProps>, property: string) => {
+ let clusterColor = this.props.styleProvider?.(doc, props, property); // bcz: check 'props' used to be renderDepth + 1
if (property !== "backgroundColor") return clusterColor;
const cluster = NumCast(doc?.cluster);
if (this.Document._useClusters) {
@@ -979,11 +982,11 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
pw && ph && (this.Document[this.scaleFieldKey] = scale * Math.min(pw / NumCast(doc._width), ph / NumCast(doc._height)));
}
- @computed get libraryPath() { return this.props.LibraryPath ? [...this.props.LibraryPath, this.props.Document] : []; }
@computed get backgroundActive() { return this.props.layerProvider?.(this.layoutDoc) === false && (this.props.ContainingCollectionView?.active() || this.props.active()); }
onChildClickHandler = () => this.props.childClickScript || ScriptCast(this.Document.onChildClick);
onChildDoubleClickHandler = () => this.props.childDoubleClickScript || ScriptCast(this.Document.onChildDoubleClick);
- backgroundHalo = computedFn(function (doc: Doc) { return BoolCast(this.Document._useClusters) || (NumCast(doc.group, -1) !== -1); }).bind(this);
+ // @ts-ignore
+ backgroundHalo = computedFn(function (doc: Doc) { return this.Document._useClusters || NumCast(doc.group, -1) !== -1; }).bind(this);
parentActive = (outsideReaction: boolean) => this.props.active(outsideReaction) || this.props.parentActive?.(outsideReaction) || this.backgroundActive || this.layoutDoc._viewType === CollectionViewType.Pile ? true : false;
getChildDocumentViewProps(childLayout: Doc, childData?: Doc): DocumentViewProps {
return {
@@ -996,7 +999,6 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
fitToBox: false,
DataDoc: childData,
Document: childLayout,
- LibraryPath: this.libraryPath,
LayoutTemplate: childLayout.z ? undefined : this.props.ChildLayoutTemplate,
LayoutTemplateString: childLayout.z ? undefined : this.props.ChildLayoutString,
FreezeDimensions: this.props.freezeChildDimensions,
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index eb781ed0a..a963b9158 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -1,31 +1,32 @@
import { action, computed, observable } from "mobx";
import { observer } from "mobx-react";
-import { AclAddonly, AclAdmin, AclEdit, DataSym, Doc, DocListCast, Opt } from "../../../../fields/Doc";
+import { AclAddonly, AclAdmin, AclEdit, DataSym, Doc, Opt } from "../../../../fields/Doc";
+import { Id } from "../../../../fields/FieldSymbols";
import { InkData, InkField, InkTool } from "../../../../fields/InkField";
import { List } from "../../../../fields/List";
import { RichTextField } from "../../../../fields/RichTextField";
import { SchemaHeaderField } from "../../../../fields/SchemaHeaderField";
import { Cast, FieldValue, NumCast, StrCast } from "../../../../fields/Types";
import { GetEffectiveAcl } from "../../../../fields/util";
-import { Utils } from "../../../../Utils";
+import { Utils, intersectRect } from "../../../../Utils";
import { CognitiveServices } from "../../../cognitive_services/CognitiveServices";
import { Docs, DocumentOptions, DocUtils } from "../../../documents/Documents";
+import { DocumentType } from "../../../documents/DocumentTypes";
+import { CurrentUserUtils } from "../../../util/CurrentUserUtils";
import { DocumentManager } from "../../../util/DocumentManager";
import { SelectionManager } from "../../../util/SelectionManager";
import { Transform } from "../../../util/Transform";
import { undoBatch, UndoManager } from "../../../util/UndoManager";
import { ContextMenu } from "../../ContextMenu";
import { FormattedTextBox } from "../../nodes/formattedText/FormattedTextBox";
+import { PresBox, PresMovement } from "../../nodes/PresBox";
import { PreviewCursor } from "../../PreviewCursor";
import { CollectionDockingView } from "../CollectionDockingView";
import { SubCollectionViewProps } from "../CollectionSubView";
-import { CollectionView, CollectionViewType } from "../CollectionView";
+import { CollectionView } from "../CollectionView";
import { MarqueeOptionsMenu } from "./MarqueeOptionsMenu";
import "./MarqueeView.scss";
import React = require("react");
-import { Id } from "../../../../fields/FieldSymbols";
-import { CurrentUserUtils } from "../../../util/CurrentUserUtils";
-import { PresBox, PresMovement } from "../../nodes/PresBox";
interface MarqueeViewProps {
getContainerTransform: () => Transform;
@@ -38,20 +39,28 @@ interface MarqueeViewProps {
nudge?: (x: number, y: number) => boolean;
setPreviewCursor?: (func: (x: number, y: number, drag: boolean) => void) => void;
}
-
@observer
export class MarqueeView extends React.Component<SubCollectionViewProps & MarqueeViewProps>
{
+ private _commandExecuted = false;
@observable public static DragMarquee = false;
@observable _lastX: number = 0;
@observable _lastY: number = 0;
@observable _downX: number = 0;
@observable _downY: number = 0;
@observable _visible: boolean = false;
- _commandExecuted = false;
- @observable _pointsX: number[] = [];
- @observable _pointsY: number[] = [];
- @observable _freeHand: boolean = false;
+ @observable _lassoPts: [number, number][] = [];
+ @observable _lassoFreehand: boolean = false;
+
+ @computed get Transform() { return this.props.getTransform(); }
+ @computed get Bounds() {
+ const topLeft = this.Transform.transformPoint(this._downX < this._lastX ? this._downX : this._lastX, this._downY < this._lastY ? this._downY : this._lastY);
+ const size = this.Transform.transformDirection(this._lastX - this._downX, this._lastY - this._downY);
+ return { left: topLeft[0], top: topLeft[1], width: Math.abs(size[0]), height: Math.abs(size[1]) };
+ }
+ get inkDoc() { return this.props.Document; }
+ get ink() { return Cast(this.props.Document.ink, InkField); }
+ set ink(value: Opt<InkField>) { this.props.Document.ink = value; }
componentDidMount() {
this.props.setPreviewCursor?.(this.setPreviewCursor);
@@ -64,11 +73,9 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
document.removeEventListener("pointermove", this.onPointerMove, true);
}
document.removeEventListener("keydown", this.marqueeCommand, true);
- if (hideMarquee) {
- this._visible = false;
- }
- this._pointsX = [];
- this._pointsY = [];
+ hideMarquee && this.hideMarquee();
+
+ this._lassoPts = [];
}
@undoBatch
@@ -77,7 +84,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
//make textbox and add it to this collection
// tslint:disable-next-line:prefer-const
const cm = ContextMenu.Instance;
- const [x, y] = this.props.getTransform().transformPoint(this._downX, this._downY);
+ const [x, y] = this.Transform.transformPoint(this._downX, this._downY);
if (e.key === "?") {
cm.setDefaultItem("?", (str: string) => this.props.addDocTab(
Docs.Create.WebDocument(`https://bing.com/search?q=${str}`, { _fitWidth: true, _width: 400, x, y, _height: 512, _nativeWidth: 850, isAnnotating: false, title: "bing", useCors: true }), "add:right"));
@@ -115,7 +122,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
const indent = line.search(/\S|$/);
const newBox = Docs.Create.TextDocument(line, { _width: 200, _height: 35, x: x + indent / 3 * 10, y: ypos, title: line });
this.props.addDocument(newBox);
- ypos += 40 * this.props.getTransform().Scale;
+ ypos += 40 * this.Transform.Scale;
});
})();
e.stopPropagation();
@@ -187,6 +194,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
this.props.addDocument(newCol);
}
}
+
@action
onPointerDown = (e: React.PointerEvent): void => {
this._downX = this._lastX = e.clientX;
@@ -210,13 +218,12 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
onPointerMove = (e: PointerEvent): void => {
this._lastX = e.pageX;
this._lastY = e.pageY;
- this._pointsX.push(e.clientX);
- this._pointsY.push(e.clientY);
+ this._lassoPts.push([e.clientX, e.clientY]);
if (!e.cancelBubble) {
if (Math.abs(this._lastX - this._downX) > Utils.DRAG_THRESHOLD ||
Math.abs(this._lastY - this._downY) > Utils.DRAG_THRESHOLD) {
if (!this._commandExecuted) {
- this._visible = true;
+ this.showMarquee();
}
e.stopPropagation();
e.preventDefault();
@@ -267,6 +274,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
e.preventDefault();
}
}
+
clearSelection() {
if (window.getSelection) { window.getSelection()?.removeAllRanges(); }
else if (document.getSelection()) { document.getSelection()?.empty(); }
@@ -314,41 +322,11 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
}
}
- intersectRect(r1: { left: number, top: number, width: number, height: number },
- r2: { left: number, top: number, width: number, height: number }) {
- return !(r2.left > r1.left + r1.width || r2.left + r2.width < r1.left || r2.top > r1.top + r1.height || r2.top + r2.height < r1.top);
- }
-
- @computed
- get Bounds() {
- const left = this._downX < this._lastX ? this._downX : this._lastX;
- const top = this._downY < this._lastY ? this._downY : this._lastY;
- const topLeft = this.props.getTransform().transformPoint(left, top);
- const size = this.props.getTransform().transformDirection(this._lastX - this._downX, this._lastY - this._downY);
- return { left: topLeft[0], top: topLeft[1], width: Math.abs(size[0]), height: Math.abs(size[1]) };
- }
-
- get inkDoc() {
- return this.props.Document;
- }
-
- get ink() { // ink will be stored on the extension doc for the field (fieldKey) where the container's data is stored.
- return Cast(this.props.Document.ink, InkField);
- }
-
- set ink(value: InkField | undefined) {
- this.props.Document.ink = value;
- }
-
@action
- showMarquee = () => {
- this._visible = true;
- }
+ showMarquee = () => { this._visible = true; }
@action
- hideMarquee = () => {
- this._visible = false;
- }
+ hideMarquee = () => { this._visible = false; }
@undoBatch
@action
@@ -393,11 +371,10 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
this.hideMarquee();
}
- @undoBatch @action
+ @undoBatch
+ @action
pinWithView = (e: KeyboardEvent | React.PointerEvent | undefined) => {
const doc = this.props.Document;
- const bounds = this.Bounds;
- const selected = this.marqueeSelect(false);
const curPres = Cast(Doc.UserDoc().activePresentation, Doc) as Doc;
if (curPres) {
if (doc === curPres) { alert("Cannot pin presentation document to itself"); return; }
@@ -407,9 +384,9 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
pinDoc.groupWithUp = false;
pinDoc.context = curPres;
pinDoc.title = doc.title + " - Slide";
- const presArray: Doc[] = PresBox.Instance?.sortArray();
- const size: number = PresBox.Instance?._selectedArray.size;
- const presSelected: Doc | undefined = presArray && size ? presArray[size - 1] : undefined;
+ const presArray = PresBox.Instance?.sortArray();
+ const size = PresBox.Instance?._selectedArray.size;
+ const presSelected = presArray && size ? presArray[size - 1] : undefined;
Doc.AddDocToList(curPres, "data", pinDoc, presSelected);
if (curPres.expandBoolean) pinDoc.presExpandInlineButton = true;
if (!DocumentManager.Instance.getDocumentView(curPres)) {
@@ -420,14 +397,10 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
const index = PresBox.Instance?.childDocs.indexOf(pinDoc);
index && (curPres._itemIndex = index);
if (e instanceof KeyboardEvent ? e.key === "c" : true) {
- const x = this.Bounds.left + this.Bounds.width / 2;
- const y = this.Bounds.top + this.Bounds.height / 2;
- const panelWidth: number = this.props.PanelWidth();
- const panelHeight: number = this.props.PanelHeight();
- const scale = Math.min(Number(panelWidth) / this.Bounds.width, Number(panelHeight) / this.Bounds.height);
+ const scale = Math.min(this.props.PanelWidth() / this.Bounds.width, this.props.PanelHeight() / this.Bounds.height);
pinDoc.presPinView = true;
- pinDoc.presPinViewX = x;
- pinDoc.presPinViewY = y;
+ pinDoc.presPinViewX = this.Bounds.left + this.Bounds.width / 2;
+ pinDoc.presPinViewY = this.Bounds.top + this.Bounds.height / 2;
pinDoc.presPinViewScale = scale;
}
}
@@ -435,9 +408,9 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
this.hideMarquee();
}
- @undoBatch @action
+ @undoBatch
+ @action
collection = (e: KeyboardEvent | React.PointerEvent | undefined) => {
- const bounds = this.Bounds;
const selected = this.marqueeSelect(false);
if (e instanceof KeyboardEvent ? e.key === "c" : true) {
selected.map(action(d => {
@@ -447,8 +420,8 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
delete d.y;
delete d.activeFrame;
delete d.displayTimecode; // bcz: this should be automatic somehow.. along with any other properties that were logically associated with the original collection
- d.x = dx - bounds.left - bounds.width / 2;
- d.y = dy - bounds.top - bounds.height / 2;
+ d.x = dx - this.Bounds.left - this.Bounds.width / 2;
+ d.y = dy - this.Bounds.top - this.Bounds.height / 2;
return d;
}));
this.props.removeDocument(selected);
@@ -460,33 +433,23 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
this.hideMarquee();
}
- @undoBatch @action
+ @undoBatch
+ @action
syntaxHighlight = (e: KeyboardEvent | React.PointerEvent | undefined) => {
const selected = this.marqueeSelect(false);
if (e instanceof KeyboardEvent ? e.key === "i" : true) {
- const inks = selected.filter(s => s.proto?.type === "ink");
- const setDocs = selected.filter(s => s.proto?.type === "text" && s.color);
- const sets = setDocs.map((sd) => {
- return Cast(sd.data, RichTextField)?.Text as string;
- });
+ const inks = selected.filter(s => s.proto?.type === DocumentType.INK);
+ const setDocs = selected.filter(s => s.proto?.type === DocumentType.RTF && s.color);
+ const sets = setDocs.map((sd) => Cast(sd.data, RichTextField)?.Text as string);
const colors = setDocs.map(sd => FieldValue(sd.color) as string);
const wordToColor = new Map<string, string>();
- sets.forEach((st: string, i: number) => {
- const words = st.split(",");
- words.forEach(word => {
- wordToColor.set(word, colors[i]);
- });
- });
+ sets.forEach((st: string, i: number) => st.split(",").forEach(word => wordToColor.set(word, colors[i])));
const strokes: InkData[] = [];
- inks.forEach(i => {
- const d = Cast(i.data, InkField);
- const x = NumCast(i.x);
- const y = NumCast(i.y);
+ inks.filter(i => Cast(i.data, InkField)).forEach(i => {
+ const d = Cast(i.data, InkField, null);
const left = Math.min(...d?.inkData.map(pd => pd.X) ?? [0]);
const top = Math.min(...d?.inkData.map(pd => pd.Y) ?? [0]);
- if (d) {
- strokes.push(d.inkData.map(pd => ({ X: pd.X + x - left, Y: pd.Y + y - top })));
- }
+ strokes.push(d.inkData.map(pd => ({ X: pd.X + NumCast(i.x) - left, Y: pd.Y + NumCast(i.y) - top })));
});
CognitiveServices.Inking.Appliers.InterpretStrokes(strokes).then((results) => {
// const wordResults = results.filter((r: any) => r.category === "inkWord");
@@ -536,18 +499,16 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
}
}
- @undoBatch @action
+ @undoBatch
+ @action
summary = (e: KeyboardEvent | React.PointerEvent | undefined) => {
- const bounds = this.Bounds;
- const selected = this.marqueeSelect(false);
- selected.map(d => {
+ const selected = this.marqueeSelect(false).map(d => {
this.props.removeDocument(d);
- d.x = NumCast(d.x) - bounds.left;
- d.y = NumCast(d.y) - bounds.top;
- d.page = -1;
+ d.x = NumCast(d.x) - this.Bounds.left;
+ d.y = NumCast(d.y) - this.Bounds.top;
return d;
});
- const summary = Docs.Create.TextDocument("", { x: bounds.left, y: bounds.top, _width: 200, _height: 200, _fitToBox: true, _showSidebar: true, title: "overview" });
+ const summary = Docs.Create.TextDocument("", { x: this.Bounds.left, y: this.Bounds.top, _width: 200, _height: 200, _fitToBox: true, _showSidebar: true, title: "overview" });
const portal = Doc.MakeAlias(summary);
Doc.GetProto(summary)[Doc.LayoutFieldKey(summary) + "-annotations"] = new List<Doc>(selected);
Doc.GetProto(summary).layout_portal = CollectionView.LayoutString(Doc.LayoutFieldKey(summary) + "-annotations");
@@ -559,18 +520,18 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
this.props.addLiveTextDocument(summary);
MarqueeOptionsMenu.Instance.fadeOut(true);
}
+
@action
background = (e: KeyboardEvent | React.PointerEvent | undefined) => {
const newCollection = this.getCollection([], undefined, ["background"]);
this.props.addDocument(newCollection);
MarqueeOptionsMenu.Instance.fadeOut(true);
this.hideMarquee();
- setTimeout(() => this.props.selectDocuments([newCollection]), 0);
+ setTimeout(() => this.props.selectDocuments([newCollection]));
}
@undoBatch
- @action
- marqueeCommand = async (e: KeyboardEvent) => {
+ marqueeCommand = action((e: KeyboardEvent) => {
if (this._commandExecuted || (e as any).propagationIsStopped) {
return;
}
@@ -581,83 +542,30 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
this.delete();
e.stopPropagation();
}
- if (e.key === "c" || e.key === "b" || e.key === "t" || e.key === "s" || e.key === "S" || e.key === "p") {
+ if ("cbtsSp".indexOf(e.key) !== -1) {
this._commandExecuted = true;
e.stopPropagation();
e.preventDefault();
(e as any).propagationIsStopped = true;
- if (e.key === "c" || e.key === "t") {
- this.collection(e);
- }
- if (e.key === "s" || e.key === "S") {
- this.summary(e);
- }
- if (e.key === "b") {
- this.background(e);
- }
- if (e.key === "p") {
- this.pileup(e);
- }
+ if (e.key === "c" || e.key === "t") this.collection(e);
+ if (e.key === "s" || e.key === "S") this.summary(e);
+ if (e.key === "b") this.background(e);
+ if (e.key === "p") this.pileup(e);
this.cleanupInteractions(false);
}
if (e.key === "r" || e.key === " ") {
this._commandExecuted = true;
e.stopPropagation();
e.preventDefault();
- this.changeFreeHand(true);
+ this._lassoFreehand = !this._lassoFreehand;
}
- }
+ });
- @action
- changeFreeHand = (x: boolean) => {
- this._freeHand = !this._freeHand;
- }
- // @action
- // marqueeInkSelect(ink: Map<any, any>) {
- // let idata = new Map();
- // let centerShiftX = 0 - (this.Bounds.left + this.Bounds.width / 2); // moves each point by the offset that shifts the selection's center to the origin.
- // let centerShiftY = 0 - (this.Bounds.top + this.Bounds.height / 2);
- // ink.forEach((value: PointData, key: string, map: any) => {
- // if (InkingCanvas.IntersectStrokeRect(value, this.Bounds)) {
- // // let transform = this.props.container.props.ScreenToLocalTransform().scale(this.props.container.props.ContentScaling());
- // idata.set(key,
- // {
- // pathData: value.pathData.map(val => {
- // let tVal = this.props.getTransform().inverse().transformPoint(val.x, val.y);
- // return { x: tVal[0], y: tVal[1] };
- // // return { x: val.x + centerShiftX, y: val.y + centerShiftY }
- // }),
- // color: value.color,
- // width: value.width,
- // tool: value.tool,
- // page: -1
- // });
- // }
- // });
- // // InkSelectDecorations.Instance.SetSelected(idata);
- // return idata;
- // }
-
- // @action
- // marqueeInkDelete(ink?: Map<any, any>) {
- // // bcz: this appears to work but when you restart all the deleted strokes come back -- InkField isn't observing its changes so they aren't written to the DB.
- // // ink.forEach((value: StrokeData, key: string, map: any) =>
- // // InkingCanvas.IntersectStrokeRect(value, this.Bounds) && ink.delete(key));
-
- // if (ink) {
- // let idata = new Map();
- // ink.forEach((value: PointData, key: string, map: any) =>
- // !InkingCanvas.IntersectStrokeRect(value, this.Bounds) && idata.set(key, value));
- // this.ink = new InkField(idata);
- // }
- // }
touchesLine(r1: { left: number, top: number, width: number, height: number }) {
- for (var i = 0; i < this._pointsX.length; i++) {
- const topLeft = this.props.getTransform().transformPoint(this._pointsX[i], this._pointsY[i]);
- if (topLeft[0] > r1.left &&
- topLeft[0] < r1.left + r1.width &&
- topLeft[1] > r1.top &&
- topLeft[1] < r1.top + r1.height) {
+ for (const lassoPt of this._lassoPts) {
+ const topLeft = this.Transform.transformPoint(lassoPt[0], lassoPt[1]);
+ if (r1.left < topLeft[0] && topLeft[0] < r1.left + r1.width &&
+ r1.top < topLeft[1] && topLeft[1] < r1.top + r1.height) {
return true;
}
}
@@ -665,30 +573,22 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
}
boundingShape(r1: { left: number, top: number, width: number, height: number }) {
- const trueLeft = this.props.getTransform().transformPoint(Math.min(...this._pointsX), Math.min(...this._pointsY))[0];
- const trueTop = this.props.getTransform().transformPoint(Math.min(...this._pointsX), Math.min(...this._pointsY))[1];
- const trueRight = this.props.getTransform().transformPoint(Math.max(...this._pointsX), Math.max(...this._pointsY))[0];
- const trueBottom = this.props.getTransform().transformPoint(Math.max(...this._pointsX), Math.max(...this._pointsY))[1];
-
- if (r1.left > trueLeft && r1.top > trueTop && r1.left + r1.width < trueRight && r1.top + r1.height < trueBottom) {
- var hasTop = false;
- var hasLeft = false;
- var hasBottom = false;
- var hasRight = false;
- for (var i = 0; i < this._pointsX.length; i++) {
- const truePoint = this.props.getTransform().transformPoint(this._pointsX[i], this._pointsY[i]);
- if (!hasLeft && (truePoint[0] > trueLeft && truePoint[0] < r1.left) && (truePoint[1] > r1.top && truePoint[1] < r1.top + r1.height)) {
- hasLeft = true;
- }
- if (!hasTop && (truePoint[1] > trueTop && truePoint[1] < r1.top) && (truePoint[0] > r1.left && truePoint[0] < r1.left + r1.width)) {
- hasTop = true;
- }
- if (!hasRight && (truePoint[0] < trueRight && truePoint[0] > r1.left + r1.width) && (truePoint[1] > r1.top && truePoint[1] < r1.top + r1.height)) {
- hasRight = true;
- }
- if (!hasBottom && (truePoint[1] < trueBottom && truePoint[1] > r1.top + r1.height) && (truePoint[0] > r1.left && truePoint[0] < r1.left + r1.width)) {
- hasBottom = true;
- }
+ const xs = this._lassoPts.map(pair => pair[0]);
+ const ys = this._lassoPts.map(pair => pair[1]);
+ const tl = this.Transform.transformPoint(Math.min(...xs), Math.min(...ys));
+ const br = this.Transform.transformPoint(Math.max(...xs), Math.max(...ys));
+
+ if (r1.left > tl[0] && r1.top > tl[1] && r1.left + r1.width < br[0] && r1.top + r1.height < br[1]) {
+ let hasTop = false;
+ let hasLeft = false;
+ let hasBottom = false;
+ let hasRight = false;
+ for (const lassoPt of this._lassoPts) {
+ const truePoint = this.Transform.transformPoint(lassoPt[0], lassoPt[1]);
+ hasLeft = hasLeft || (truePoint[0] > tl[0] && truePoint[0] < r1.left) && (truePoint[1] > r1.top && truePoint[1] < r1.top + r1.height);
+ hasTop = hasTop || (truePoint[1] > tl[1] && truePoint[1] < r1.top) && (truePoint[0] > r1.left && truePoint[0] < r1.left + r1.width);
+ hasRight = hasRight || (truePoint[0] < br[0] && truePoint[0] > r1.left + r1.width) && (truePoint[1] > r1.top && truePoint[1] < r1.top + r1.height);
+ hasBottom = hasBottom || (truePoint[1] < br[1] && truePoint[1] > r1.top + r1.height) && (truePoint[0] > r1.left && truePoint[0] < r1.left + r1.width);
if (hasTop && hasLeft && hasBottom && hasRight) {
return true;
}
@@ -696,106 +596,40 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
}
return false;
}
+
marqueeSelect(selectBackgrounds: boolean = true) {
- const selRect = this.Bounds;
const selection: Doc[] = [];
- this.props.activeDocuments().filter(doc => this.props.layerProvider?.(doc) !== false && !doc.z).map(doc => {
+ const selectFunc = (doc: Doc) => {
const layoutDoc = Doc.Layout(doc);
- const x = NumCast(doc.x);
- const y = NumCast(doc.y);
- const w = NumCast(layoutDoc._width);
- const h = NumCast(layoutDoc._height);
- if (this._freeHand === false) {
- if (this.intersectRect({ left: x, top: y, width: w, height: h }, selRect)) {
- selection.push(doc);
- }
+ const bounds = { left: NumCast(doc.x), top: NumCast(doc.y), width: NumCast(layoutDoc._width), height: NumCast(layoutDoc._height) };
+ if (!this._lassoFreehand) {
+ intersectRect(bounds, this.Bounds) && selection.push(doc);
} else {
- if (this.touchesLine({ left: x, top: y, width: w, height: h }) ||
- this.boundingShape({ left: x, top: y, width: w, height: h })) {
- selection.push(doc);
- }
+ (this.touchesLine(bounds) || this.boundingShape(bounds)) && selection.push(doc);
}
- });
- if (!selection.length && selectBackgrounds) {
- this.props.activeDocuments().filter(doc => doc.z === undefined).map(doc => {
- const layoutDoc = Doc.Layout(doc);
- const x = NumCast(doc.x);
- const y = NumCast(doc.y);
- const w = NumCast(layoutDoc._width);
- const h = NumCast(layoutDoc._height);
- if (this.intersectRect({ left: x, top: y, width: w, height: h }, selRect)) {
- selection.push(doc);
- }
- });
- }
- if (!selection.length) {
- const left = this._downX < this._lastX ? this._downX : this._lastX;
- const top = this._downY < this._lastY ? this._downY : this._lastY;
- const topLeft = this.props.getContainerTransform().transformPoint(left, top);
- const size = this.props.getContainerTransform().transformDirection(this._lastX - this._downX, this._lastY - this._downY);
- const otherBounds = { left: topLeft[0], top: topLeft[1], width: Math.abs(size[0]), height: Math.abs(size[1]) };
- this.props.activeDocuments().filter(doc => doc.z !== undefined).map(doc => {
- const layoutDoc = Doc.Layout(doc);
- const x = NumCast(doc.x);
- const y = NumCast(doc.y);
- const w = NumCast(layoutDoc._width);
- const h = NumCast(layoutDoc._height);
- if (this._freeHand === false) {
- if (this.intersectRect({ left: x, top: y, width: w, height: h }, selRect)) {
- selection.push(doc);
- }
- } else {
- if (this.touchesLine({ left: x, top: y, width: w, height: h }) ||
- this.boundingShape({ left: x, top: y, width: w, height: h })) {
- selection.push(doc);
- }
- }
- });
- }
+ };
+ this.props.activeDocuments().filter(doc => this.props.layerProvider?.(doc) !== false && !doc.z).map(selectFunc);
+ if (!selection.length && selectBackgrounds) this.props.activeDocuments().filter(doc => doc.z === undefined).map(selectFunc);
+ if (!selection.length) this.props.activeDocuments().filter(doc => doc.z !== undefined).map(selectFunc);
return selection;
}
- @computed
- get marqueeDiv() {
- const p = this._visible ? this.props.getContainerTransform().transformPoint(this._downX < this._lastX ? this._downX : this._lastX, this._downY < this._lastY ? this._downY : this._lastY) : [0, 0];
- const v = this.props.getContainerTransform().transformDirection(this._lastX - this._downX, this._lastY - this._downY);
- /**
- * @RE - The commented out span below
- * This contains the "C for collection, ..." text on marquees.
- * Commented out by syip2 when the marquee menu was added.
- */
- if (!this._freeHand) {
- return <div className="marquee" style={{
- transform: `translate(${p[0]}px, ${p[1]}px)`,
- width: `${Math.abs(v[0])}`,
- height: `${Math.abs(v[1])}`, zIndex: 2000
- }} >
- <span className="marquee-legend"></span>
- </div>;
-
- } else {
- var str: string = "";
- for (var i = 0; i < this._pointsX.length; i++) {
- const pt = this.props.getContainerTransform().transformPoint(this._pointsX[i], this._pointsY[i]);
- str += pt[0].toString();
- str += ",";
- str += pt[1].toString();
- str += (" ");
- }
-
- //hardcoded height and width.
- return <div className="marquee" style={{ zIndex: 2000 }}>
- <svg height={2000} width={2000}>
- <polyline
- points={str}
- fill="none"
- stroke="black"
- strokeWidth="1"
- strokeDasharray="3"
- />
- </svg>
- </div>;
- }
+ @computed get marqueeDiv() {
+ const cpt = this._lassoFreehand || !this._visible ? [0, 0] : [this._downX < this._lastX ? this._downX : this._lastX, this._downY < this._lastY ? this._downY : this._lastY];
+ const p = this.props.getContainerTransform().transformPoint(cpt[0], cpt[1]);
+ const v = this._lassoFreehand ? [0, 0] : this.props.getContainerTransform().transformDirection(this._lastX - this._downX, this._lastY - this._downY);
+ return <div className="marquee" style={{
+ transform: `translate(${p[0]}px, ${p[1]}px)`,
+ width: Math.abs(v[0]),
+ height: Math.abs(v[1]),
+ zIndex: 2000
+ }}> {this._lassoFreehand ?
+ <svg height={2000} width={2000}>
+ <polyline points={this._lassoPts.reduce((s, pt) => s + pt[0] + "," + pt[1] + " ", "")} fill="none" stroke="black" strokeWidth="1" strokeDasharray="3" />
+ </svg>
+ :
+ <span className="marquee-legend" />}
+ </div>;
}
render() {
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
index 2e7cdf6d0..7ce269c92 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
@@ -219,7 +219,6 @@ export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocu
styleProvider={this.props.styleProvider}
LayoutTemplate={this.props.ChildLayoutTemplate}
LayoutTemplateString={this.props.ChildLayoutString}
- LibraryPath={this.props.LibraryPath}
FreezeDimensions={this.props.freezeChildDimensions}
renderDepth={this.props.renderDepth + 1}
PanelWidth={width}
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
index 4206a5171..7700ea128 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
@@ -219,7 +219,6 @@ export class CollectionMultirowView extends CollectionSubView(MultirowDocument)
styleProvider={this.props.styleProvider}
LayoutTemplate={this.props.ChildLayoutTemplate}
LayoutTemplateString={this.props.ChildLayoutString}
- LibraryPath={this.props.LibraryPath}
FreezeDimensions={this.props.freezeChildDimensions}
renderDepth={this.props.renderDepth + 1}
PanelWidth={width}
diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx
index 447668ee8..c89e21312 100644
--- a/src/client/views/nodes/AudioBox.tsx
+++ b/src/client/views/nodes/AudioBox.tsx
@@ -1,34 +1,34 @@
import React = require("react");
-import { FieldViewProps, FieldView } from './FieldView';
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import axios from "axios";
+import { action, computed, IReactionDisposer, observable, reaction, runInAction } from "mobx";
import { observer } from "mobx-react";
-import "./AudioBox.scss";
-import { Cast, DateCast, NumCast, FieldValue, ScriptCast } from "../../../fields/Types";
-import { AudioField, nullAudio } from "../../../fields/URLField";
-import { ViewBoxAnnotatableComponent } from "../DocComponent";
-import { makeInterface, createSchema } from "../../../fields/Schema";
-import { documentSchema } from "../../../fields/documentSchemas";
-import { Utils, returnTrue, emptyFunction, returnOne, returnTransparent, returnFalse, returnZero, formatTime, setupMoveUpEvents } from "../../../Utils";
-import { runInAction, observable, reaction, IReactionDisposer, computed, action, trace, toJS } from "mobx";
+import Waveform from "react-audio-waveform";
import { DateField } from "../../../fields/DateField";
-import { SelectionManager } from "../../util/SelectionManager";
import { Doc, DocListCast, Opt } from "../../../fields/Doc";
-import { ContextMenuProps } from "../ContextMenuItem";
-import { ContextMenu } from "../ContextMenu";
+import { documentSchema } from "../../../fields/documentSchemas";
import { Id } from "../../../fields/FieldSymbols";
-import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { DocumentView, DocumentViewProps } from "./DocumentView";
-import { Docs, DocUtils } from "../../documents/Documents";
+import { List } from "../../../fields/List";
+import { createSchema, listSpec, makeInterface } from "../../../fields/Schema";
import { ComputedField, ScriptField } from "../../../fields/ScriptField";
+import { Cast, DateCast, NumCast } from "../../../fields/Types";
+import { AudioField, nullAudio } from "../../../fields/URLField";
+import { emptyFunction, formatTime, returnFalse, returnOne, returnTrue, setupMoveUpEvents, Utils, numberRange } from "../../../Utils";
+import { Docs, DocUtils } from "../../documents/Documents";
import { Networking } from "../../Network";
-import { LinkAnchorBox } from "./LinkAnchorBox";
-import { List } from "../../../fields/List";
+import { CurrentUserUtils } from "../../util/CurrentUserUtils";
import { Scripting } from "../../util/Scripting";
-import Waveform from "react-audio-waveform";
-import axios from "axios";
+import { SelectionManager } from "../../util/SelectionManager";
import { SnappingManager } from "../../util/SnappingManager";
-import { CurrentUserUtils } from "../../util/CurrentUserUtils";
-import { LinkDocPreview } from "./LinkDocPreview";
+import { ContextMenu } from "../ContextMenu";
+import { ContextMenuProps } from "../ContextMenuItem";
+import { ViewBoxAnnotatableComponent } from "../DocComponent";
+import "./AudioBox.scss";
+import { DocumentView, DocumentViewProps } from "./DocumentView";
+import { FieldView, FieldViewProps } from './FieldView';
import { FormattedTextBoxComment } from "./formattedText/FormattedTextBoxComment";
+import { LinkAnchorBox } from "./LinkAnchorBox";
+import { LinkDocPreview } from "./LinkDocPreview";
declare class MediaRecorder {
// whatever MediaRecorder has
@@ -43,6 +43,7 @@ const AudioDocument = makeInterface(documentSchema, audioSchema);
export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioDocument>(AudioDocument) {
public static LayoutString(fieldKey: string) { return FieldView.LayoutString(AudioBox, fieldKey); }
public static Enabled = false;
+ public static NUMBER_OF_BUCKETS = 100;
static Instance: AudioBox;
static RangeScript: ScriptField;
@@ -76,7 +77,6 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
@observable _visible: boolean = false;
@observable _markerEnd: number = 0;
@observable _position: number = 0;
- @observable _buckets: Array<number> = new Array<number>();
@observable _waveHeight: Opt<number> = this.layoutDoc._height;
@observable private _paused: boolean = false;
@observable private static _scrubTime = 0;
@@ -508,6 +508,8 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
// returns the audio waveform
@computed get waveform() {
+ const audioBuckets = Cast(this.dataDoc.audioBuckets, listSpec("number"), []);
+ !audioBuckets.length && setTimeout(() => this.createWaveformBuckets());
return <Waveform
color={"darkblue"}
height={this._waveHeight}
@@ -515,44 +517,23 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
// pos={this.layoutDoc._currentTimecode} need to correctly resize parent to make this work (not very necessary for function)
pos={this.audioDuration}
duration={this.audioDuration}
- peaks={this._buckets.length === 100 ? this._buckets : undefined}
+ peaks={audioBuckets.length === AudioBox.NUMBER_OF_BUCKETS ? audioBuckets : undefined}
progressColor={"blue"} />;
}
// decodes the audio file into peaks for generating the waveform
- @action
- buckets = async () => {
- const audioCtx = new (window.AudioContext)();
-
+ createWaveformBuckets = async () => {
axios({ url: this.path, responseType: "arraybuffer" })
- .then(response => {
- const audioData = response.data;
-
- audioCtx.decodeAudioData(audioData, action(buffer => {
+ .then(response => (new (window.AudioContext)()).decodeAudioData(response.data,
+ action(buffer => {
const decodedAudioData = buffer.getChannelData(0);
- const NUMBER_OF_BUCKETS = 100;
- const bucketDataSize = Math.floor(decodedAudioData.length / NUMBER_OF_BUCKETS);
-
- for (let i = 0; i < NUMBER_OF_BUCKETS; i++) {
- const startingPoint = i * bucketDataSize;
- const endingPoint = i * bucketDataSize + bucketDataSize;
- let max = 0;
- for (let j = startingPoint; j < endingPoint; j++) {
- if (decodedAudioData[j] > max) {
- max = decodedAudioData[j];
- }
- }
- const size = Math.abs(max);
- this._buckets.push(size / 2);
- }
-
- }));
- });
- }
-
- // Returns the peaks of the audio waveform
- @computed get peaks() {
- return this.buckets();
+ const bucketDataSize = Math.floor(decodedAudioData.length / AudioBox.NUMBER_OF_BUCKETS);
+ const brange = Array.from(Array(bucketDataSize));
+ this.dataDoc.audioBuckets = new List<number>(
+ numberRange(AudioBox.NUMBER_OF_BUCKETS).map(i =>
+ brange.reduce((p, x, j) => Math.abs(Math.max(p, decodedAudioData[i * bucketDataSize + j])), 0) / 2));
+ }))
+ );
}
rangeScript = () => AudioBox.RangeScript;
@@ -561,7 +542,6 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
render() {
const interactive = SnappingManager.GetIsDragging() || this.active() ? "-interactive" : "";
this._first = true; // for indicating the first marker that is rendered
- this.path && this._buckets.length !== 100 ? this.peaks : null; // render waveform if audio is done recording
const markerDoc = (mark: Doc, script: undefined | (() => ScriptField)) => {
return <DocumentView {...this.props}
Document={mark}
@@ -596,7 +576,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
:
<button className={`audiobox-record${interactive}`} style={{ backgroundColor: "black" }}>
RECORD
- </button>}
+ </button>}
</div> :
<div className="audiobox-controls" >
<div className="audiobox-dictation"></div>
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index 94793ffff..b4b887617 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -1,25 +1,21 @@
-import { computed, IReactionDisposer, observable, reaction, trace, action } from "mobx";
+import { action, computed, observable } from "mobx";
import { observer } from "mobx-react";
-import { Doc, HeightSym, WidthSym } from "../../../fields/Doc";
+import { Doc, HeightSym, Opt, WidthSym } from "../../../fields/Doc";
+import { Document } from "../../../fields/documentSchemas";
+import { List } from "../../../fields/List";
+import { listSpec } from "../../../fields/Schema";
+import { ComputedField } from "../../../fields/ScriptField";
import { Cast, NumCast, StrCast } from "../../../fields/Types";
+import { TraceMobx } from "../../../fields/util";
+import { numberRange, returnVal } from "../../../Utils";
+import { DocumentType } from "../../documents/DocumentTypes";
import { Transform } from "../../util/Transform";
import { DocComponent } from "../DocComponent";
+import { InkingStroke } from "../InkingStroke";
import "./CollectionFreeFormDocumentView.scss";
+import { ContentFittingDocumentView } from "./ContentFittingDocumentView";
import { DocumentView, DocumentViewProps } from "./DocumentView";
import React = require("react");
-import { Document } from "../../../fields/documentSchemas";
-import { TraceMobx } from "../../../fields/util";
-import { ContentFittingDocumentView } from "./ContentFittingDocumentView";
-import { List } from "../../../fields/List";
-import { numberRange, smoothScroll, returnVal } from "../../../Utils";
-import { ComputedField } from "../../../fields/ScriptField";
-import { listSpec } from "../../../fields/Schema";
-import { DocumentType } from "../../documents/DocumentTypes";
-import { Zoom, Fade, Flip, Rotate, Bounce, Roll, LightSpeed } from 'react-reveal';
-import { PresBox, PresEffect } from "./PresBox";
-import { InkingStroke } from "../InkingStroke";
-import { SnappingManager } from "../../util/SnappingManager";
-import { InkTool } from "../../../fields/InkField";
export interface CollectionFreeFormDocumentViewProps extends DocumentViewProps {
dataProvider?: (doc: Doc, replica: string) => { x: number, y: number, zIndex?: number, opacity?: number, highlight?: boolean, z: number, transition?: string } | undefined;
@@ -62,98 +58,48 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
@computed get nativeWidth() { return returnVal(this.props.NativeWidth?.(), Doc.NativeWidth(this.layoutDoc, undefined, this.freezeDimensions)); }
@computed get nativeHeight() { return returnVal(this.props.NativeHeight?.(), Doc.NativeHeight(this.layoutDoc, undefined, this.freezeDimensions)); }
+ static animFields = ["_height", "_width", "x", "y", "_scrollTop", "opacity"];
public static getValues(doc: Doc, time: number) {
- const timecode = Math.round(time);
- return ({
- h: Cast(doc["h-indexed"], listSpec("number"), [NumCast(doc._height)]).reduce((p, h, i) => (i <= timecode && h !== undefined) || p === undefined ? h : p, undefined as any as number),
- w: Cast(doc["w-indexed"], listSpec("number"), [NumCast(doc._width)]).reduce((p, w, i) => (i <= timecode && w !== undefined) || p === undefined ? w : p, undefined as any as number),
- x: Cast(doc["x-indexed"], listSpec("number"), [NumCast(doc.x)]).reduce((p, x, i) => (i <= timecode && x !== undefined) || p === undefined ? x : p, undefined as any as number),
- y: Cast(doc["y-indexed"], listSpec("number"), [NumCast(doc.y)]).reduce((p, y, i) => (i <= timecode && y !== undefined) || p === undefined ? y : p, undefined as any as number),
- scroll: Cast(doc["scroll-indexed"], listSpec("number"), [NumCast(doc._scrollTop, 0)]).reduce((p, s, i) => (i <= timecode && s !== undefined) || p === undefined ? s : p, undefined as any as number),
- opacity: Cast(doc["opacity-indexed"], listSpec("number"), [NumCast(doc.opacity, 1)]).reduce((p, o, i) => i <= timecode || p === undefined ? o : p, undefined as any as number),
- });
+ return CollectionFreeFormDocumentView.animFields.reduce((p, val) => {
+ p[val] = Cast(`${val}-indexed`, listSpec("number"), [NumCast(doc[val])]).reduce((p, v, i) => (i <= Math.round(time) && v !== undefined) || p === undefined ? v : p, undefined as any as number);
+ return p;
+ }, {} as { [val: string]: Opt<number> });
}
- public static setValues(time: number, d: Doc, x?: number, y?: number, h?: number, w?: number, scroll?: number, opacity?: number) {
+ public static setValues(time: number, d: Doc, vals: { [val: string]: Opt<number> }) {
const timecode = Math.round(time);
- const hindexed = Cast(d["h-indexed"], listSpec("number"), []).slice();
- const windexed = Cast(d["w-indexed"], listSpec("number"), []).slice();
- const xindexed = Cast(d["x-indexed"], listSpec("number"), []).slice();
- const yindexed = Cast(d["y-indexed"], listSpec("number"), []).slice();
- const oindexed = Cast(d["opacity-indexed"], listSpec("number"), []).slice();
- const scrollIndexed = Cast(d["scroll-indexed"], listSpec("number"), []).slice();
- xindexed[timecode] = x as any as number;
- yindexed[timecode] = y as any as number;
- hindexed[timecode] = h as any as number;
- windexed[timecode] = w as any as number;
- oindexed[timecode] = opacity as any as number;
- if (scroll) scrollIndexed[timecode] = scroll as any as number;
- d["x-indexed"] = new List<number>(xindexed);
- d["y-indexed"] = new List<number>(yindexed);
- d["h-indexed"] = new List<number>(hindexed);
- d["w-indexed"] = new List<number>(windexed);
- d["opacity-indexed"] = new List<number>(oindexed);
- d["scroll-indexed"] = new List<number>(scrollIndexed);
- if (d.appearFrame) {
- if (d.appearFrame === timecode + 1) {
- d["text-color"] = "red";
- } else if (d.appearFrame < timecode + 1) {
- d["text-color"] = "grey";
- } else { d["text-color"] = "black"; }
- } else if (d.appearFrame === 0) {
- }
+ Object.keys(vals).forEach(val => {
+ const findexed = Cast(d[`${val}-indexed`], listSpec("number"), []).slice();
+ findexed[timecode] = vals[val] as any as number;
+ d[`${val}-indexed`] = new List<number>(findexed);
+ });
+ d.appearFrame && (d["text-color"] =
+ d.appearFrame === timecode + 1 ? "red" :
+ d.appearFrame < timecode + 1 ? "grey" : "black");
}
- // public static updateScrollframe(doc: Doc, time: number) {
- // console.log('update scroll frame');
- // const timecode = Math.round(time);
- // const scrollIndexed = Cast(doc['scroll-indexed'], listSpec("number"), null);
- // scrollIndexed?.length <= timecode + 1 && scrollIndexed.push(undefined as any as number);
- // setTimeout(() => doc.dataTransition = "inherit", 1010);
- // }
-
- // public static setupScroll(doc: Doc, timecode: number) {
- // const scrollList = new List<number>();
- // scrollList[timecode] = NumCast(doc._scrollTop);
- // doc["scroll-indexed"] = scrollList;
- // doc.activeFrame = ComputedField.MakeFunction("self._currentFrame");
- // doc._scrollTop = ComputedField.MakeInterpolated("scroll", "activeFrame");
- // }
-
-
public static updateKeyframe(docs: Doc[], time: number, targetDoc?: Doc) {
const timecode = Math.round(time);
- docs.forEach(doc => {
- const xindexed = Cast(doc['x-indexed'], listSpec("number"), null);
- const yindexed = Cast(doc['y-indexed'], listSpec("number"), null);
- const hindexed = Cast(doc['h-indexed'], listSpec("number"), null);
- const windexed = Cast(doc['w-indexed'], listSpec("number"), null);
- const opacityindexed = Cast(doc['opacity-indexed'], listSpec("number"), null);
- hindexed?.length <= timecode + 1 && hindexed.push(undefined as any as number);
- windexed?.length <= timecode + 1 && windexed.push(undefined as any as number);
- xindexed?.length <= timecode + 1 && xindexed.push(undefined as any as number);
- yindexed?.length <= timecode + 1 && yindexed.push(undefined as any as number);
- opacityindexed?.length <= timecode + 1 && opacityindexed.push(undefined as any as number);
- if (doc.appearFrame && targetDoc) {
- if (doc.appearFrame === timecode + 1) {
- doc["text-color"] = StrCast(targetDoc["pres-text-color"]);
- } else if (doc.appearFrame < timecode + 1) {
- doc["text-color"] = StrCast(targetDoc["pres-text-viewed-color"]);
- } else { doc["text-color"] = "black"; }
- } else if (doc.appearFrame === 0) {
- doc["text-color"] = "black";
- }
- doc.dataTransition = "all 1s";
- });
- setTimeout(() => docs.forEach(doc => doc.dataTransition = "inherit"), 1010);
+ docs.forEach(action(doc => {
+ doc._viewTransition = doc.dataTransition = "all 1s";
+ doc["text-color"] =
+ !doc.appearFrame || !targetDoc ? "black" :
+ doc.appearFrame === timecode + 1 ? StrCast(targetDoc["pres-text-color"]) :
+ doc.appearFrame < timecode + 1 ? StrCast(targetDoc["pres-text-viewed-color"]) :
+ "black";
+ CollectionFreeFormDocumentView.animFields.forEach(val => {
+ const findexed = Cast(doc[`${val}-indexed`], listSpec("number"), null);
+ findexed?.length <= timecode + 1 && findexed.push(undefined as any as number);
+ });
+ }));
+ setTimeout(() => docs.forEach(doc => { doc._viewTransition = undefined; doc.dataTransition = "inherit"; }), 1010);
}
public static gotoKeyframe(docs: Doc[]) {
- docs.forEach(doc => doc.dataTransition = "all 1s");
- setTimeout(() => docs.forEach(doc => doc.dataTransition = "inherit"), 1010);
+ docs.forEach(doc => doc._viewTransition = doc.dataTransition = "all 1s");
+ setTimeout(() => docs.forEach(doc => { doc._viewTransition = undefined; doc.dataTransition = "inherit"; }), 1010);
}
-
public static setupZoom(doc: Doc, targDoc: Doc) {
const width = new List<number>();
const height = new List<number>();
@@ -172,27 +118,12 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
public static setupKeyframes(docs: Doc[], currTimecode: number, makeAppear: boolean = false) {
docs.forEach(doc => {
if (doc.appearFrame === undefined) doc.appearFrame = currTimecode;
- const curTimecode = currTimecode;
- const xlist = new List<number>(numberRange(currTimecode + 1).map(i => undefined) as any as number[]);
- const ylist = new List<number>(numberRange(currTimecode + 1).map(i => undefined) as any as number[]);
- const wlist = new List<number>(numberRange(currTimecode + 1).map(i => undefined) as any as number[]);
- const hlist = new List<number>(numberRange(currTimecode + 1).map(i => undefined) as any as number[]);
- const olist = new List<number>(numberRange(currTimecode + 1).map(t => !doc.z && makeAppear && t < NumCast(doc.appearFrame) ? 0 : 1));
- wlist[curTimecode] = NumCast(doc._width);
- hlist[curTimecode] = NumCast(doc._height);
- xlist[curTimecode] = NumCast(doc.x);
- ylist[curTimecode] = NumCast(doc.y);
- doc["x-indexed"] = xlist;
- doc["y-indexed"] = ylist;
- doc["w-indexed"] = wlist;
- doc["h-indexed"] = hlist;
- doc["opacity-indexed"] = olist;
+ if (!doc["opacity-indexed"]) { // opacity is unlike other fields because it's value should not be undefined before it appears to enable it to fade-in
+ const olist = new List<number>(numberRange(currTimecode + 1).map(t => !doc.z && makeAppear && t < NumCast(doc.appearFrame) ? 0 : 1));
+ doc["opacity-indexed"] = olist;
+ }
+ CollectionFreeFormDocumentView.animFields.forEach(val => doc[val] = ComputedField.MakeInterpolated(val, "activeFrame", doc, currTimecode));
doc.activeFrame = ComputedField.MakeFunction("self.context?._currentFrame||0");
- doc._height = ComputedField.MakeInterpolated("h", "activeFrame");
- doc._width = ComputedField.MakeInterpolated("w", "activeFrame");
- doc.x = ComputedField.MakeInterpolated("x", "activeFrame");
- doc.y = ComputedField.MakeInterpolated("y", "activeFrame");
- doc.opacity = ComputedField.MakeInterpolated("opacity", "activeFrame");
doc.dataTransition = "inherit";
});
}
@@ -201,46 +132,6 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
this.props.Document.x = NumCast(this.props.Document.x) + x;
this.props.Document.y = NumCast(this.props.Document.y) + y;
}
-
- @computed get freeformNodeDiv() {
- const node = <DocumentView {...this.props}
- nudge={this.nudge}
- dragDivName={"collectionFreeFormDocumentView-container"}
- ContentScaling={this.contentScaling}
- ScreenToLocalTransform={this.getTransform}
- styleProvider={this.props.styleProvider}
- opacity={this.opacity}
- layerProvider={this.props.layerProvider}
- NativeHeight={this.NativeHeight}
- NativeWidth={this.NativeWidth}
- PanelWidth={this.panelWidth}
- PanelHeight={this.panelHeight} />;
- if (PresBox.Instance && this.layoutDoc === PresBox.Instance.childDocs[PresBox.Instance.itemIndex]?.presentationTargetDoc) {
- const effectProps = {
- left: this.layoutDoc.presEffectDirection === PresEffect.Left,
- right: this.layoutDoc.presEffectDirection === PresEffect.Right,
- top: this.layoutDoc.presEffectDirection === PresEffect.Top,
- bottom: this.layoutDoc.presEffectDirection === PresEffect.Bottom,
- opposite: true,
- delay: this.layoutDoc.presTransition,
- // when: this.layoutDoc === PresBox.Instance.childDocs[PresBox.Instance.itemIndex]?.presentationTargetDoc,
- };
- switch (this.layoutDoc.presEffect) {
- case "Zoom": return (<Zoom {...effectProps}>{node}</Zoom>); break;
- case PresEffect.Fade: return (<Fade {...effectProps}>{node}</Fade>); break;
- case PresEffect.Flip: return (<Flip {...effectProps}>{node}</Flip>); break;
- case PresEffect.Rotate: return (<Rotate {...effectProps}>{node}</Rotate>); break;
- case PresEffect.Bounce: return (<Bounce {...effectProps}>{node}</Bounce>); break;
- case PresEffect.Roll: return (<Roll {...effectProps}>{node}</Roll>); break;
- case "LightSpeed": return (<LightSpeed {...effectProps}>{node}</LightSpeed>); break;
- case PresEffect.None: return node; break;
- default: return node; break;
- }
- } else {
- return node;
- }
- }
-
contentScaling = () => this.nativeWidth > 0 && !this.props.fitToBox && !this.freezeDimensions ? this.width / this.nativeWidth : 1;
panelWidth = () => (this.sizeProvider?.width || this.props.PanelWidth?.());
panelHeight = () => (this.sizeProvider?.height || this.props.PanelHeight?.());
@@ -251,18 +142,30 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
NativeHeight = () => this.nativeHeight;
@computed get pointerEvents() {
if (this.props.pointerEvents === "none") return "none";
- return this.props.styleProvider?.(this.Document, this.props, !this._contentView?.docView?.isSelected() ? "pointerEvents:selected" : "pointerEvents", this.props.layerProvider);
+ return this.props.styleProvider?.(this.Document, this.props, !this._contentView?.docView?.isSelected() ? "pointerEvents:selected" : "pointerEvents");
}
render() {
TraceMobx();
- const backgroundColor = this.props.styleProvider?.(this.Document, this.props, "backgroundColor", this.props.layerProvider);
+ const backgroundColor = this.props.styleProvider?.(this.Document, this.props, "backgroundColor");
const borderRounding = StrCast(Doc.Layout(this.layoutDoc).borderRounding) || StrCast(this.layoutDoc.borderRounding) || StrCast(this.Document.borderRounding) || undefined;
+
+ const divProps = {
+ ...this.props,
+ nudge: this.nudge,
+ dragDivName: "collectionFreeFormDocumentView-container",
+ opacity: this.opacity,
+ ScreenToLocalTransform: this.getTransform,
+ NativeHeight: this.NativeHeight,
+ NativeWidth: this.NativeWidth,
+ PanelWidth: this.panelWidth,
+ PanelHeight: this.panelHeight
+ };
return <div className="collectionFreeFormDocumentView-container"
style={{
boxShadow:
this.Opacity === 0 ? undefined : // if it's not visible, then no shadow
this.layoutDoc.z ? `#9c9396 ${StrCast(this.layoutDoc.boxShadow, "10px 10px 0.9vw")}` : // if it's a floating doc, give it a big shadow
- this.props.backgroundHalo?.(this.props.Document) && this.props.Document.type !== DocumentType.INK ? (`${this.props.styleProvider?.(this.props.Document, this.props, "backgroundColor", this.props.layerProvider)} ${StrCast(this.layoutDoc.boxShadow, `0vw 0vw ${(Cast(this.layoutDoc.layers, listSpec("string"), []).includes("background") ? 100 : 50) / this.props.ContentScaling()}px`)}`) : // if it's just in a cluster, make the shadown roughly match the cluster border extent
+ this.props.backgroundHalo?.(this.props.Document) && this.props.Document.type !== DocumentType.INK ? (`${this.props.styleProvider?.(this.props.Document, this.props, "backgroundColor")} ${StrCast(this.layoutDoc.boxShadow, `0vw 0vw ${(Cast(this.layoutDoc.layers, listSpec("string"), []).includes("background") ? 100 : 50) / this.props.ContentScaling()}px`)}`) : // if it's just in a cluster, make the shadown roughly match the cluster border extent
Cast(this.layoutDoc.layers, listSpec("string"), []).includes('background') ? undefined : // if it's a background & has a cluster color, make the shadow spread really big
StrCast(this.layoutDoc.boxShadow, ""),
borderRadius: borderRounding,
@@ -286,18 +189,9 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
</svg>
</div>}
- {!this.props.fitToBox ?
- <>{this.freeformNodeDiv}</>
- : <ContentFittingDocumentView {...this.props}
- ref={action((r: ContentFittingDocumentView | null) => this._contentView = r)}
- ContainingCollectionDoc={this.props.ContainingCollectionDoc}
- DataDoc={this.props.DataDoc}
- ScreenToLocalTransform={this.getTransform}
- NativeHeight={this.NativeHeight}
- NativeWidth={this.NativeWidth}
- PanelWidth={this.panelWidth}
- PanelHeight={this.panelHeight}
- />}
+ {this.props.fitToBox ?
+ <ContentFittingDocumentView {...divProps} ref={action((r: ContentFittingDocumentView | null) => this._contentView = r)} /> :
+ <DocumentView {...divProps} ContentScaling={this.contentScaling} />}
</div>;
}
}
diff --git a/src/client/views/nodes/ContentFittingDocumentView.tsx b/src/client/views/nodes/ContentFittingDocumentView.tsx
index a54479f55..74d7cb24e 100644
--- a/src/client/views/nodes/ContentFittingDocumentView.tsx
+++ b/src/client/views/nodes/ContentFittingDocumentView.tsx
@@ -71,7 +71,6 @@ export class ContentFittingDocumentView extends React.Component<DocumentViewProp
DataDoc={this.props.DataDoc}
LayoutTemplate={this.props.LayoutTemplate}
LayoutTemplateString={this.props.LayoutTemplateString}
- LibraryPath={this.props.LibraryPath}
PanelWidth={this.PanelWidth}
PanelHeight={this.PanelHeight}
ContentScaling={returnOne}
diff --git a/src/client/views/nodes/DocHolderBox.tsx b/src/client/views/nodes/DocHolderBox.tsx
index f0a1a3278..e14093e70 100644
--- a/src/client/views/nodes/DocHolderBox.tsx
+++ b/src/client/views/nodes/DocHolderBox.tsx
@@ -118,7 +118,6 @@ export class DocHolderBox extends ViewBoxAnnotatableComponent<FieldViewProps, Do
<DocumentView
Document={containedDoc}
DataDoc={undefined}
- LibraryPath={emptyPath}
docFilters={this.props.docFilters}
docRangeFilters={this.props.docRangeFilters}
searchFilterDocs={this.props.searchFilterDocs}
@@ -147,7 +146,6 @@ export class DocHolderBox extends ViewBoxAnnotatableComponent<FieldViewProps, Do
<ContentFittingDocumentView
Document={containedDoc}
DataDoc={undefined}
- LibraryPath={emptyPath}
docFilters={this.props.docFilters}
docRangeFilters={this.props.docRangeFilters}
searchFilterDocs={this.props.searchFilterDocs}
@@ -184,7 +182,7 @@ export class DocHolderBox extends ViewBoxAnnotatableComponent<FieldViewProps, Do
onContextMenu={this.specificContextMenu}
onPointerDown={this.onPointerDown} onClick={this.onClick}
style={{
- background: this.props.styleProvider?.(containedDoc, this.props, "backgroundColor", this.props.layerProvider),
+ background: this.props.styleProvider?.(containedDoc, this.props, "backgroundColor"),
border: `#00000021 solid ${this.xPad}px`,
borderTop: `#0000005e solid ${this.yPad}px`,
borderBottom: `#0000005e solid ${this.yPad}px`,
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 8cf274651..5555c30e4 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -1,7 +1,6 @@
-import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { action, computed, observable, runInAction } from "mobx";
import { observer } from "mobx-react";
-import { AclAdmin, AclEdit, AclPrivate, DataSym, Doc, DocListCast, Field, HeightSym, Opt, WidthSym, StrListCast } from "../../../fields/Doc";
+import { AclAdmin, AclEdit, AclPrivate, DataSym, Doc, DocListCast, Field, Opt } from "../../../fields/Doc";
import { Document } from '../../../fields/documentSchemas';
import { Id } from '../../../fields/FieldSymbols';
import { InkTool } from '../../../fields/InkField';
@@ -12,7 +11,7 @@ import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from "../../../fields/Ty
import { GetEffectiveAcl, SharingPermissions, TraceMobx } from '../../../fields/util';
import { MobileInterface } from '../../../mobile/MobileInterface';
import { GestureUtils } from '../../../pen-gestures/GestureUtils';
-import { emptyFunction, OmitKeys, returnOne, returnTransparent, returnVal, Utils, returnFalse, returnTrue } from "../../../Utils";
+import { emptyFunction, OmitKeys, returnFalse, returnOne, returnTrue, returnVal, Utils } from "../../../Utils";
import { GooglePhotos } from '../../apis/google_docs/GooglePhotosClientUtils';
import { Docs, DocUtils } from "../../documents/Documents";
import { DocumentType } from '../../documents/DocumentTypes';
@@ -38,6 +37,7 @@ import { DocumentLinksButton } from './DocumentLinksButton';
import "./DocumentView.scss";
import { LinkAnchorBox } from './LinkAnchorBox';
import { LinkDescriptionPopup } from './LinkDescriptionPopup';
+import { PresBox } from './PresBox';
import { RadialMenu } from './RadialMenu';
import { TaskCompletionBox } from './TaskCompletedBox';
import React = require("react");
@@ -63,7 +63,6 @@ export interface DocumentViewProps {
getView?: (view: DocumentView) => any;
LayoutTemplateString?: string;
LayoutTemplate?: () => Opt<Doc>;
- LibraryPath: Doc[];
fitToBox?: boolean;
ignoreAutoHeight?: boolean;
contextMenuItems?: () => { script: ScriptField, label: string }[];
@@ -91,10 +90,10 @@ export interface DocumentViewProps {
parentActive: (outsideReaction: boolean) => boolean;
whenActiveChanged: (isActive: boolean) => void;
bringToFront: (doc: Doc, sendToBack?: boolean) => void;
- addDocTab: (doc: Doc, where: string, libraryPath?: Doc[]) => boolean;
+ addDocTab: (doc: Doc, where: string) => boolean;
pinToPres: (document: Doc) => void;
backgroundHalo?: (doc: Doc) => boolean;
- styleProvider?: (doc: Opt<Doc>, props: DocumentViewProps, property: string, layerProvider?: (doc: Doc, assign?: boolean) => boolean) => any;
+ styleProvider?: (doc: Opt<Doc>, props: DocumentViewProps, property: string) => any;
forceHideLinkButton?: () => boolean;
opacity?: () => number | undefined;
ChromeHeight?: () => number;
@@ -387,7 +386,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
// depending on the followLinkLocation property of the source (or the link itself as a fallback);
public static followLinkClick = async (linkDoc: Opt<Doc>, sourceDoc: Doc, docView: {
focus: DocFocusFunc,
- addDocTab: (doc: Doc, where: string, libraryPath?: Doc[]) => boolean,
+ addDocTab: (doc: Doc, where: string) => boolean,
ContainingCollectionDoc?: Doc
}, shiftKey: boolean, altKey: boolean) => {
const batch = UndoManager.StartBatch("follow link click");
@@ -657,7 +656,6 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
this.Document.onClick = this.layoutDoc.onClick = undefined;
}
-
@undoBatch
noOnClick = (): void => {
this.Document.ignoreClick = false;
@@ -934,7 +932,6 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
backgroundHalo={this.props.backgroundHalo}
dontRegisterView={this.props.dontRegisterView}
fitToBox={this.props.fitToBox}
- LibraryPath={this.props.LibraryPath}
addDocument={this.props.addDocument}
removeDocument={this.props.removeDocument}
moveDocument={this.props.moveDocument}
@@ -1085,7 +1082,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
}
@computed get pointerEvents() {
if (this.props.pointerEvents === "none") return "none";
- return this.props.styleProvider?.(this.Document, this.props, this.isSelected() ? "pointerEvents:selected" : "pointerEvents", this.props.layerProvider);
+ return this.props.styleProvider?.(this.Document, this.props, this.isSelected() ? "pointerEvents:selected" : "pointerEvents");
}
@undoBatch
@action
@@ -1105,13 +1102,12 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
}), 400);
});
-
- render() {
+ @computed get renderDoc() {
TraceMobx();
if (!(this.props.Document instanceof Doc)) return (null);
if (GetEffectiveAcl(this.props.Document[DataSym]) === AclPrivate) return (null);
- if (this.props.styleProvider?.(this.layoutDoc, this.props, "hidden", this.props.layerProvider)) return null;
- const backgroundColor = this.props.styleProvider?.(this.layoutDoc, this.props, "backgroundColor", this.props.layerProvider);
+ if (this.props.styleProvider?.(this.layoutDoc, this.props, "hidden")) return null;
+ const backgroundColor = this.props.styleProvider?.(this.layoutDoc, this.props, "backgroundColor");
const opacity = Cast(this.layoutDoc._opacity, "number", Cast(this.layoutDoc.opacity, "number", Cast(this.Document.opacity, "number", null)));
const finalOpacity = this.props.opacity ? this.props.opacity() : opacity;
const finalColor = this.layoutDoc.type === DocumentType.FONTICON || this.layoutDoc._viewType === CollectionViewType.Linear ? undefined : backgroundColor;
@@ -1125,23 +1121,17 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
let highlighting = fullDegree && this.layoutDoc.type !== DocumentType.FONTICON && this.layoutDoc._viewType !== CollectionViewType.Linear && this.props.Document.type !== DocumentType.INK;
highlighting = highlighting && this.props.focus !== emptyFunction && this.layoutDoc.title !== "[pres element template]"; // bcz: hack to turn off highlighting onsidebar panel documents. need to flag a document as not highlightable in a more direct way
const topmost = this.topMost ? "-topmost" : "";
- return this.props.styleProvider?.(this.rootDoc, this.props, "docContents", this.props.layerProvider) ?? <div className={`documentView-node${topmost}`}
+ return this.props.styleProvider?.(this.rootDoc, this.props, "docContents") ?? <div className={`documentView-node${topmost}`}
id={this.props.Document[Id]}
- ref={this._mainCont} onKeyDown={this.onKeyDown}
+ onKeyDown={this.onKeyDown}
onContextMenu={this.onContextMenu} onPointerDown={this.onPointerDown} onClick={this.onClick}
onPointerEnter={action(e => !SnappingManager.GetIsDragging() && Doc.BrushDoc(this.props.Document))}
onPointerLeave={action(e => {
let entered = false;
- const target = document.elementFromPoint(e.nativeEvent.x, e.nativeEvent.y);
- for (let child: any = target; child; child = child?.parentElement) {
- if (child === this.ContentDiv) {
- entered = true;
- }
+ for (let child = document.elementFromPoint(e.nativeEvent.x, e.nativeEvent.y); !entered && child; child = child.parentElement) {
+ entered = entered || child === this.ContentDiv;
}
- // if (this.props.Document !== DocumentLinksButton.StartLink?.Document) {
!entered && Doc.UnBrushDoc(this.props.Document);
- //}
-
})}
style={{
transformOrigin: this._animateScalingTo ? "center center" : undefined,
@@ -1161,12 +1151,14 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
fontFamily: StrCast(this.Document._fontFamily, "inherit"),
fontSize: !this.props.treeViewDoc ? Cast(this.Document._fontSize, "string", null) : undefined,
}}>
- {this.onClickHandler && this.props.ContainingCollectionView?.props.Document._viewType === CollectionViewType.Time ? <>
- {this.innards}
- <div className="documentView-conentBlocker" />
- </> :
- this.innards}
- {!this.props.treeViewDoc && this.props.styleProvider?.(this.rootDoc, this.props, this.isSelected() ? "decorations:selected" : "decorations", this.props.layerProvider) || (null)}
+ {this.innards}
+ {this.onClickHandler && this.props.ContainingCollectionView?.props.Document._viewType === CollectionViewType.Time ? <div className="documentView-contentBlocker" /> : (null)}
+ {!this.props.treeViewDoc && this.props.styleProvider?.(this.rootDoc, this.props, this.isSelected() ? "decorations:selected" : "decorations") || (null)}
+ </div>;
+ }
+ render() {
+ return <div className="documentView-effectsWrapper" ref={this._mainCont} >
+ {PresBox.EffectsProvider(this.layoutDoc, this.renderDoc) || this.renderDoc}
</div>;
}
}
diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx
index ed91cf47d..5cd752fdb 100644
--- a/src/client/views/nodes/FieldView.tsx
+++ b/src/client/views/nodes/FieldView.tsx
@@ -25,7 +25,6 @@ export interface FieldViewProps {
ContainingCollectionDoc: Opt<Doc>;
Document: Doc;
DataDoc?: Doc;
- LibraryPath: Doc[];
layerProvider?: (doc: Doc, assign?: boolean) => boolean;
contentsActive?: (setActive: () => boolean) => void;
onClick?: () => ScriptField;
@@ -43,7 +42,7 @@ export interface FieldViewProps {
pinToPres: (document: Doc) => void;
removeDocument?: (document: Doc | Doc[]) => boolean;
moveDocument?: (document: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (document: Doc | Doc[]) => boolean) => boolean;
- styleProvider?: (document: Opt<Doc>, props: Opt<DocumentViewProps>, property: string, layerProvider?: (doc: Doc, assign?: boolean) => boolean) => any;
+ styleProvider?: (document: Opt<Doc>, props: Opt<DocumentViewProps>, property: string) => any;
ScreenToLocalTransform: () => Transform;
bringToFront: (doc: Doc, sendToBack?: boolean) => void;
parentActive: (outsideReaction: boolean) => boolean;
diff --git a/src/client/views/nodes/FilterBox.tsx b/src/client/views/nodes/FilterBox.tsx
index 6f0828a7d..0161f51fd 100644
--- a/src/client/views/nodes/FilterBox.tsx
+++ b/src/client/views/nodes/FilterBox.tsx
@@ -193,7 +193,6 @@ export class FilterBox extends ViewBoxBaseComponent<FieldViewProps, FilterBoxDoc
ContainingCollectionView={this.props.ContainingCollectionView}
PanelWidth={this.props.PanelWidth}
PanelHeight={this.props.PanelHeight}
- LibraryPath={emptyPath}
rootSelected={this.props.rootSelected}
renderDepth={1}
dropAction={this.props.dropAction}
diff --git a/src/client/views/nodes/FontIconBox.tsx b/src/client/views/nodes/FontIconBox.tsx
index c9ee4126e..a1bb0604e 100644
--- a/src/client/views/nodes/FontIconBox.tsx
+++ b/src/client/views/nodes/FontIconBox.tsx
@@ -61,7 +61,7 @@ export class FontIconBox extends DocComponent<FieldViewProps, FontIconDocument>(
render() {
const label = StrCast(this.rootDoc.label, StrCast(this.rootDoc.title));
const color = StrCast(this.layoutDoc.color, this._foregroundColor);
- const backgroundColor = this.props.styleProvider?.(this.rootDoc, this.props, "backgroundColor", this.props.layerProvider);
+ const backgroundColor = this.props.styleProvider?.(this.rootDoc, this.props, "backgroundColor");
const shape = StrCast(this.layoutDoc.iconShape, label ? "round" : "circle");
const icon = StrCast(this.dataDoc.icon, "user") as any;
const presSize = shape === 'round' ? 25 : 30;
diff --git a/src/client/views/nodes/KeyValuePair.tsx b/src/client/views/nodes/KeyValuePair.tsx
index 5e1f8fcea..aaf544c50 100644
--- a/src/client/views/nodes/KeyValuePair.tsx
+++ b/src/client/views/nodes/KeyValuePair.tsx
@@ -55,7 +55,6 @@ export class KeyValuePair extends React.Component<KeyValuePairProps> {
const props: FieldViewProps = {
Document: this.props.doc,
DataDoc: this.props.doc,
- LibraryPath: [],
docFilters: returnEmptyFilter,
docRangeFilters: returnEmptyFilter,
searchFilterDocs: returnEmptyDoclist,
diff --git a/src/client/views/nodes/LinkBox.tsx b/src/client/views/nodes/LinkBox.tsx
index 1b181cef1..bf19457da 100644
--- a/src/client/views/nodes/LinkBox.tsx
+++ b/src/client/views/nodes/LinkBox.tsx
@@ -17,7 +17,7 @@ export class LinkBox extends ViewBoxBaseComponent<FieldViewProps, LinkDocument>(
public static LayoutString(fieldKey: string) { return FieldView.LayoutString(LinkBox, fieldKey); }
render() {
return <div className={`linkBox-container${this.active() ? "-interactive" : ""}`}
- style={{ background: this.props.styleProvider?.(this.props.Document, this.props, "backgroundColor", this.props.layerProvider) }} >
+ style={{ background: this.props.styleProvider?.(this.props.Document, this.props, "backgroundColor") }} >
<CollectionTreeView {...this.props}
ChromeHeight={returnZero}
diff --git a/src/client/views/nodes/LinkDocPreview.tsx b/src/client/views/nodes/LinkDocPreview.tsx
index 0256d394e..f66811098 100644
--- a/src/client/views/nodes/LinkDocPreview.tsx
+++ b/src/client/views/nodes/LinkDocPreview.tsx
@@ -12,12 +12,13 @@ import { ContentFittingDocumentView } from "./ContentFittingDocumentView";
import { DocumentLinksButton } from './DocumentLinksButton';
import React = require("react");
import { DocumentViewProps } from './DocumentView';
+import { Id } from '../../../fields/FieldSymbols';
interface Props {
linkDoc?: Doc;
linkSrc?: Doc;
href?: string;
- styleProvider?: (doc: Opt<Doc>, props: Opt<DocumentViewProps>, property: string, layerProvider?: (doc: Doc, assign?: boolean) => boolean) => any;
+ styleProvider?: (doc: Opt<Doc>, props: Opt<DocumentViewProps>, property: string) => any;
addDocTab: (document: Doc, where: string) => boolean;
location: number[];
}
@@ -64,8 +65,11 @@ export class LinkDocPreview extends React.Component<Props> {
runInAction(() => {
this._toolTipText = "";
LinkDocPreview.TargetDoc = this._targetDoc = target;
- if (anchor !== this._targetDoc && anchor && this._targetDoc) {
- this._targetDoc._scrollPreviewY = NumCast(anchor?.y);
+ if (this._targetDoc) {
+ this._targetDoc._scrollToPreviewLinkID = linkDoc?.[Id];
+ if (anchor !== this._targetDoc && anchor) {
+ this._targetDoc._scrollPreviewY = NumCast(anchor?.y);
+ }
}
});
}
@@ -90,7 +94,6 @@ export class LinkDocPreview extends React.Component<Props> {
:
<ContentFittingDocumentView
Document={this._targetDoc}
- LibraryPath={emptyPath}
fitToBox={true}
moveDocument={returnFalse}
rootSelected={returnFalse}
diff --git a/src/client/views/nodes/PresBox.tsx b/src/client/views/nodes/PresBox.tsx
index a4f79571e..5985225e3 100644
--- a/src/client/views/nodes/PresBox.tsx
+++ b/src/client/views/nodes/PresBox.tsx
@@ -1,10 +1,11 @@
import React = require("react");
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { Tooltip } from "@material-ui/core";
-import { action, computed, observable, runInAction, ObservableMap, IReactionDisposer, reaction } from "mobx";
+import { action, computed, IReactionDisposer, observable, ObservableMap, reaction, runInAction } from "mobx";
import { observer } from "mobx-react";
import { ColorState, SketchPicker } from "react-color";
-import { Doc, DocCastAsync, DocListCast, DocListCastAsync } from "../../../fields/Doc";
+import { Bounce, Fade, Flip, LightSpeed, Roll, Rotate, Zoom } from 'react-reveal';
+import { Doc, DocListCast, DocListCastAsync } from "../../../fields/Doc";
import { documentSchema } from "../../../fields/documentSchemas";
import { InkTool } from "../../../fields/InkField";
import { List } from "../../../fields/List";
@@ -12,7 +13,7 @@ import { PrefetchProxy } from "../../../fields/Proxy";
import { listSpec, makeInterface } from "../../../fields/Schema";
import { ScriptField } from "../../../fields/ScriptField";
import { BoolCast, Cast, NumCast, StrCast } from "../../../fields/Types";
-import { returnFalse, returnOne, returnZero } from "../../../Utils";
+import { returnFalse, returnOne } from "../../../Utils";
import { Docs } from "../../documents/Documents";
import { DocumentType } from "../../documents/DocumentTypes";
import { CurrentUserUtils } from "../../util/CurrentUserUtils";
@@ -28,7 +29,6 @@ import { CollectionFreeFormDocumentView } from "./CollectionFreeFormDocumentView
import { FieldView, FieldViewProps } from './FieldView';
import "./PresBox.scss";
import Color = require("color");
-import { clear } from "console";
export enum PresMovement {
Zoom = "zoom",
@@ -38,6 +38,8 @@ export enum PresMovement {
}
export enum PresEffect {
+ Zoom = "Zoom",
+ Lightspeed = "Lightspeed",
Fade = "Fade in",
Flip = "Flip",
Rotate = "Rotate",
@@ -71,6 +73,35 @@ const PresBoxDocument = makeInterface(documentSchema);
export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>(PresBoxDocument) {
public static LayoutString(fieldKey: string) { return FieldView.LayoutString(PresBox, fieldKey); }
+ static renderEffectsDoc(renderDoc: any, layoutDoc: Doc) {
+ const effectProps = {
+ left: layoutDoc.presEffectDirection === PresEffect.Left,
+ right: layoutDoc.presEffectDirection === PresEffect.Right,
+ top: layoutDoc.presEffectDirection === PresEffect.Top,
+ bottom: layoutDoc.presEffectDirection === PresEffect.Bottom,
+ opposite: true,
+ delay: layoutDoc.presTransition,
+ // when: this.layoutDoc === PresBox.Instance.childDocs[PresBox.Instance.itemIndex]?.presentationTargetDoc,
+ };
+ switch (layoutDoc.presEffect) {
+ case PresEffect.Zoom: return (<Zoom {...effectProps}>{renderDoc}</Zoom>);
+ case PresEffect.Fade: return (<Fade {...effectProps}>{renderDoc}</Fade>);
+ case PresEffect.Flip: return (<Flip {...effectProps}>{renderDoc}</Flip>);
+ case PresEffect.Rotate: return (<Rotate {...effectProps}>{renderDoc}</Rotate>);
+ case PresEffect.Bounce: return (<Bounce {...effectProps}>{renderDoc}</Bounce>);
+ case PresEffect.Roll: return (<Roll {...effectProps}>{renderDoc}</Roll>);
+ case PresEffect.Lightspeed: return (<LightSpeed {...effectProps}>{renderDoc}</LightSpeed>);
+ case PresEffect.None:
+ default: return renderDoc;
+ }
+ }
+ public static EffectsProvider(layoutDoc: Doc, renderDoc: any) {
+ return PresBox.Instance && layoutDoc === PresBox.Instance.childDocs[PresBox.Instance.itemIndex]?.presentationTargetDoc ?
+ PresBox.renderEffectsDoc(renderDoc, layoutDoc)
+ :
+ renderDoc;
+ }
+
@observable public static Instance: PresBox;
@observable _isChildActive = false;
diff --git a/src/client/views/nodes/formattedText/DashDocView.tsx b/src/client/views/nodes/formattedText/DashDocView.tsx
index 67bfd435b..450f0b6bc 100644
--- a/src/client/views/nodes/formattedText/DashDocView.tsx
+++ b/src/client/views/nodes/formattedText/DashDocView.tsx
@@ -228,7 +228,6 @@ export class DashDocView extends React.Component<IDashDocView> {
<DocumentView
Document={finalLayout}
DataDoc={resolvedDataDoc}
- LibraryPath={this._textBox.props.LibraryPath}
fitToBox={BoolCast(dashDoc._fitToBox)}
addDocument={returnFalse}
rootSelected={this._textBox.props.isSelected}
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 125447f28..22e3ac1e9 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -61,6 +61,7 @@ import { DocumentManager } from '../../../util/DocumentManager';
import { CollectionStackingView } from '../../collections/CollectionStackingView';
import { CollectionViewType } from '../../collections/CollectionView';
import { SnappingManager } from '../../../util/SnappingManager';
+import { LinkDocPreview } from '../LinkDocPreview';
export interface FormattedTextBoxProps {
makeLink?: () => Opt<Doc>; // bcz: hack: notifies the text document when the container has made a link. allows the text doc to react and setup a hyeprlink for any selected text
@@ -98,6 +99,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
private _currentTime: number = 0;
private _linkTime: number | null = null;
private _pause: boolean = false;
+ private _animatingScroll: number = 0; // hack to prevent scroll values from being written to document when scroll is animating
@computed get _recording() { return this.dataDoc?.audioState === "recording"; }
set _recording(value) {
@@ -815,6 +817,50 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
return this.active();//this.props.isSelected() || this._isChildActive || this.props.renderDepth === 0;
}
+ scrollToLinkId = (linkId: string) => {
+ const findLinkFrag = (frag: Fragment, editor: EditorView) => {
+ const nodes: Node[] = [];
+ let hadStart = start !== 0;
+ frag.forEach((node, index) => {
+ const examinedNode = findLinkNode(node, editor);
+ if (examinedNode?.node.textContent) {
+ nodes.push(examinedNode.node);
+ !hadStart && (start = index + examinedNode.start);
+ hadStart = true;
+ }
+ });
+ return { frag: Fragment.fromArray(nodes), start };
+ };
+ const findLinkNode = (node: Node, editor: EditorView) => {
+ if (!node.isText) {
+ const content = findLinkFrag(node.content, editor);
+ return { node: node.copy(content.frag), start: content.start };
+ }
+ const marks = [...node.marks];
+ const linkIndex = marks.findIndex(mark => mark.type === editor.state.schema.marks.linkAnchor);
+ return linkIndex !== -1 && marks[linkIndex].attrs.allLinks.find((item: { href: string }) => linkId === item.href.replace(/.*\/doc\//, "")) ? { node, start: 0 } : undefined;
+ };
+
+ let start = 0;
+ if (this._editorView && linkId) {
+ const editor = this._editorView;
+ const ret = findLinkFrag(editor.state.doc.content, editor);
+
+ if (ret.frag.size > 2 && ret.start >= 0) {
+ let selection = TextSelection.near(editor.state.doc.resolve(ret.start)); // default to near the start
+ if (ret.frag.firstChild) {
+ selection = TextSelection.between(editor.state.doc.resolve(ret.start), editor.state.doc.resolve(ret.start + ret.frag.firstChild.nodeSize)); // bcz: looks better to not have the target selected
+ }
+ editor.dispatch(editor.state.tr.setSelection(new TextSelection(selection.$from, selection.$from)).scrollIntoView());
+ const mark = editor.state.schema.mark(this._editorView.state.schema.marks.search_highlight);
+ setTimeout(() => editor.dispatch(editor.state.tr.addMark(selection.from, selection.to, mark)), 0);
+ setTimeout(() => this.unhighlightSearchTerms(), 2000);
+ }
+ Doc.SetInPlace(this.layoutDoc, "scrollToLinkID", undefined, false);
+ Doc.SetInPlace(this.layoutDoc, "_scrollToPreviewLinkID", undefined, false);
+ }
+ }
+
componentDidMount() {
this.props.contentsActive?.(this.IsActive);
this._cachedLinks = DocListCast(this.Document.links);
@@ -910,7 +956,13 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
search => search ? this.highlightSearchTerms([Doc.SearchQuery()], search.searchMatch < 0) : this.unhighlightSearchTerms(),
{ fireImmediately: Doc.IsSearchMatchUnmemoized(this.rootDoc) ? true : false });
- this._disposers.selected = reaction(() => this.props.isSelected(), action(() => this._recording = false));
+ this._disposers.selected = reaction(() => this.props.isSelected(),
+ action((selected) => {
+ this._recording = false;
+ if (RichTextMenu.Instance?.view === this._editorView && !selected) {
+ RichTextMenu.Instance?.updateMenu(undefined, undefined, undefined);
+ }
+ }));
if (!this.props.dontRegisterView) {
this._disposers.record = reaction(() => this._recording,
@@ -924,65 +976,36 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
}
);
}
- this._disposers.scrollToRegion = reaction(
- () => StrCast(this.layoutDoc.scrollToLinkID),
- async (scrollToLinkID) => {
- const findLinkFrag = (frag: Fragment, editor: EditorView) => {
- const nodes: Node[] = [];
- let hadStart = start !== 0;
- frag.forEach((node, index) => {
- const examinedNode = findLinkNode(node, editor);
- if (examinedNode?.node.textContent) {
- nodes.push(examinedNode.node);
- !hadStart && (start = index + examinedNode.start);
- hadStart = true;
- }
- });
- return { frag: Fragment.fromArray(nodes), start };
- };
- const findLinkNode = (node: Node, editor: EditorView) => {
- if (!node.isText) {
- const content = findLinkFrag(node.content, editor);
- return { node: node.copy(content.frag), start: content.start };
- }
- const marks = [...node.marks];
- const linkIndex = marks.findIndex(mark => mark.type === editor.state.schema.marks.linkAnchor);
- return linkIndex !== -1 && marks[linkIndex].attrs.allLinks.find((item: { href: string }) => scrollToLinkID === item.href.replace(/.*\/doc\//, "")) ? { node, start: 0 } : undefined;
- };
-
- let start = 0;
- if (this._editorView && scrollToLinkID) {
- const editor = this._editorView;
- const ret = findLinkFrag(editor.state.doc.content, editor);
-
- if (ret.frag.size > 2 && ret.start >= 0) {
- let selection = TextSelection.near(editor.state.doc.resolve(ret.start)); // default to near the start
- if (ret.frag.firstChild) {
- selection = TextSelection.between(editor.state.doc.resolve(ret.start), editor.state.doc.resolve(ret.start + ret.frag.firstChild.nodeSize)); // bcz: looks better to not have the target selected
- }
- editor.dispatch(editor.state.tr.setSelection(new TextSelection(selection.$from, selection.$from)).scrollIntoView());
- const mark = editor.state.schema.mark(this._editorView.state.schema.marks.search_highlight);
- setTimeout(() => editor.dispatch(editor.state.tr.addMark(selection.from, selection.to, mark)), 0);
- setTimeout(() => this.unhighlightSearchTerms(), 2000);
- }
- Doc.SetInPlace(this.layoutDoc, "scrollToLinkID", undefined, false);
- }
-
- },
- { fireImmediately: true }
+ this._disposers.previewScrollToRegion = reaction(() => StrCast(this.layoutDoc._scrollToPreviewLinkID),
+ scrollToLinkID => this.props.renderDepth === -1 && scrollToLinkID && this.scrollToLinkId(scrollToLinkID), { fireImmediately: true }
+ );
+ this._disposers.scrollToRegion = reaction(() => StrCast(this.layoutDoc.scrollToLinkID),
+ scrollToLinkID => scrollToLinkID && this.scrollToLinkId(scrollToLinkID), { fireImmediately: true }
);
this._disposers.scroll = reaction(() => NumCast(this.layoutDoc._scrollTop),
- pos => this._scrollRef.current?.scrollTo({ top: pos }), { fireImmediately: true }
+ pos => {
+ const durationMiliStr = StrCast(this.Document._viewTransition).match(/([0-9]*)ms/);
+ const durationSecStr = StrCast(this.Document._viewTransition).match(/([0-9.]*)s/);
+ const duration = durationMiliStr ? Number(durationMiliStr[1]) : durationSecStr ? Number(durationSecStr[1]) * 1000 : 0;
+ if (duration) {
+ this._animatingScroll++;
+ this._scrollRef.current && smoothScroll(duration, this._scrollRef.current, Math.abs(pos || 0));
+ setTimeout(() => this._animatingScroll--, duration);
+ } else {
+ this._scrollRef.current?.scrollTo({ top: pos });
+ }
+ }, { fireImmediately: true }
);
this._disposers.scrollY = reaction(() => Cast(this.layoutDoc._scrollY, "number", null),
- scrollY => {
- if (scrollY !== undefined) {
- const delay = this._scrollRef.current ? 0 : 250; // wait for mainCont and try again to scroll
- const durationStr = StrCast(this.Document._viewTransition).match(/([0-9]*)ms/);
- const duration = durationStr ? Number(durationStr[1]) : 1000;
- setTimeout(() => this._scrollRef.current && smoothScroll(duration, this._scrollRef.current, Math.abs(scrollY || 0)), delay);
- setTimeout(() => { this.Document._scrollTop = scrollY; this.Document._scrollY = undefined; }, duration + delay);
- }
+ pos => {
+ this.Document._scrollY = undefined;
+ pos !== undefined && setTimeout(() => this.layoutDoc._scrollTop = pos, this._scrollRef.current ? 0 : 250);
+ }, { fireImmediately: true }
+ );
+ this._disposers.scrollPreviewY = reaction(() => Cast(this.layoutDoc.scrollPreviewY, "number", null),
+ pos => {
+ this.Document.scrollPreviewY = undefined;
+ pos !== undefined && setTimeout(() => this.layoutDoc._scrollTop = pos, this._scrollRef.current ? 0 : 250);
}, { fireImmediately: true }
);
@@ -1233,6 +1256,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
componentWillUnmount() {
this.endUndoTypingBatch();
+ this.unhighlightSearchTerms();
Object.values(this._disposers).forEach(disposer => disposer?.());
this._editorView?.destroy();
FormattedTextBoxComment.tooltip && (FormattedTextBoxComment.tooltip.style.display = "none");
@@ -1529,7 +1553,9 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
eve.stopPropagation(); // drag n drop of text within text note will generate a new note if not caughst, as will dragging in from outside of Dash.
}
onscrolled = (ev: React.UIEvent) => {
- this.layoutDoc._scrollTop = this._scrollRef.current!.scrollTop;
+ if (!LinkDocPreview.TargetDoc && !FormattedTextBoxComment.linkDoc && !this._animatingScroll) {
+ this.layoutDoc._scrollTop = this._scrollRef.current!.scrollTop;
+ }
}
@action
tryUpdateHeight(limitHeight?: number) {
@@ -1572,7 +1598,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
const annotated = DocListCast(this.dataDoc[this.annotationKey]).filter(d => d?.author).length;
return !this.props.isSelected() && !(annotated && !this.sidebarWidth()) ? (null) :
<div className="formattedTextBox-sidebar-handle"
- style={{ left: `max(0px, calc(100% - ${this.sidebarWidthPercent} ${this.sidebarWidth() ? "- 5px" : "- 10px"}))`, background: annotated ? "lightBlue" : this.props.styleProvider?.(this.props.Document, this.props, "widgetColor", this.props.layerProvider) }}
+ style={{ left: `max(0px, calc(100% - ${this.sidebarWidthPercent} ${this.sidebarWidth() ? "- 5px" : "- 10px"}))`, background: annotated ? "lightBlue" : this.props.styleProvider?.(this.props.Document, this.props, "widgetColor") }}
onPointerDown={this.sidebarDown}
/>;
}
diff --git a/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx b/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx
index 3e5a40084..1d7b7ec91 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx
@@ -297,7 +297,6 @@ export class FormattedTextBoxComment {
<div className="FormattedTextBoxComment-preview-wrapper">
<ContentFittingDocumentView
Document={target}
- LibraryPath={emptyPath}
fitToBox={true}
moveDocument={returnFalse}
rootSelected={returnFalse}
diff --git a/src/client/views/nodes/formattedText/RichTextSchema.tsx b/src/client/views/nodes/formattedText/RichTextSchema.tsx
index b5d984aac..bb544e5e8 100644
--- a/src/client/views/nodes/formattedText/RichTextSchema.tsx
+++ b/src/client/views/nodes/formattedText/RichTextSchema.tsx
@@ -136,7 +136,6 @@ export class DashDocView {
ReactDOM.render(<DocumentView
Document={finalLayout}
DataDoc={resolvedDataDoc}
- LibraryPath={this._textBox.props.LibraryPath}
fitToBox={BoolCast(dashDoc._fitToBox)}
addDocument={returnFalse}
rootSelected={this._textBox.props.isSelected}
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index 48c7b1762..9b689eb6b 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -736,7 +736,6 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
transform: `scale(${this._zoomed})`
}}>
<CollectionFreeFormView {...OmitKeys(this.props, ["NativeWidth", "NativeHeight"]).omit}
- LibraryPath={this.props.ContainingCollectionView?.props.LibraryPath ?? emptyPath}
annotationsKey={this.annotationKey}
setPreviewCursor={this.setPreviewCursor}
PanelHeight={this.panelWidth}
diff --git a/src/client/views/presentationview/PresElementBox.tsx b/src/client/views/presentationview/PresElementBox.tsx
index 608740b46..37752d6ee 100644
--- a/src/client/views/presentationview/PresElementBox.tsx
+++ b/src/client/views/presentationview/PresElementBox.tsx
@@ -86,7 +86,6 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps, PresDoc
<ContentFittingDocumentView
Document={this.targetDoc}
DataDoc={this.targetDoc[DataSym] !== this.targetDoc && this.targetDoc[DataSym]}
- LibraryPath={emptyPath}
fitToBox={true}
styleProvider={this.props.styleProvider}
rootSelected={returnTrue}
@@ -323,7 +322,7 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps, PresDoc
</div>}
{miniView ? (null) : <div ref={miniView ? null : this._dragRef} className={`presItem-slide ${isSelected ? "active" : ""}`}
style={{
- backgroundColor: this.props.styleProvider?.(this.layoutDoc, this.props, "color", this.props.layerProvider),
+ backgroundColor: this.props.styleProvider?.(this.layoutDoc, this.props, "color"),
boxShadow: presBoxColor && presBoxColor !== "white" && presBoxColor !== "transparent" ? isSelected ? "0 0 0px 1.5px" + presBoxColor : undefined : undefined
}}>
<div className="presItem-name" style={{ maxWidth: showMore ? (toolbarWidth - 195) : toolbarWidth - 105, cursor: isSelected ? 'text' : 'grab' }}>
diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts
index ffb1bbf83..fdea47c84 100644
--- a/src/fields/Doc.ts
+++ b/src/fields/Doc.ts
@@ -36,6 +36,7 @@ export namespace Field {
export function toScriptString(field: Field): string {
if (typeof field === "string") return `"${field}"`;
if (typeof field === "number" || typeof field === "boolean") return String(field);
+ if (field === undefined || field === null) return "null";
return field[ToScriptString]();
}
export function toString(field: Field): string {
diff --git a/src/fields/ScriptField.ts b/src/fields/ScriptField.ts
index 024017302..c949e0791 100644
--- a/src/fields/ScriptField.ts
+++ b/src/fields/ScriptField.ts
@@ -7,7 +7,9 @@ import { Doc, Field, Opt } from "./Doc";
import { Plugins, setter } from "./util";
import { computedFn } from "mobx-utils";
import { ProxyField } from "./Proxy";
-import { Cast } from "./Types";
+import { Cast, NumCast } from "./Types";
+import { List } from "./List";
+import { numberRange } from "../Utils";
function optional(propSchema: PropSchema) {
return custom(value => {
@@ -188,12 +190,21 @@ export class ComputedField extends ScriptField {
const compiled = ScriptField.CompileScript(script, params, true, capturedVariables);
return compiled.compiled ? new ComputedField(compiled) : undefined;
}
- public static MakeInterpolated(fieldKey: string, interpolatorKey: string) {
+ public static MakeInterpolated(fieldKey: string, interpolatorKey: string, doc: Doc, curTimecode: number) {
+ if (!doc[`${fieldKey}-indexed`]) {
+ const flist = new List<number>(numberRange(curTimecode + 1).map(i => undefined) as any as number[]);
+ flist[curTimecode] = NumCast(doc[fieldKey]);
+ doc[`${fieldKey}-indexed`] = flist;
+ }
const getField = ScriptField.CompileScript(`getIndexVal(self['${fieldKey}-indexed'], self.${interpolatorKey})`, {}, true, {});
- const setField = ScriptField.CompileScript(`(self['${fieldKey}-indexed'])[self.${interpolatorKey}] = value`, { value: "any" }, true, {});
+ const setField = ScriptField.CompileScript(`setIndexVal(self['${fieldKey}-indexed'], self.${interpolatorKey}, value)`, { value: "any" }, true, {});
return getField.compiled ? new ComputedField(getField, setField?.compiled ? setField : undefined) : undefined;
}
}
+Scripting.addGlobal(function setIndexVal(list: any[], index: number, value: any) {
+ while (list.length <= index) list.push(undefined);
+ list[index] = value;
+}, "sets the value at a given index of a list", "(list: any[], index: number, value: any)");
Scripting.addGlobal(function getIndexVal(list: any[], index: number) {
return list?.reduce((p, x, i) => (i <= index && x !== undefined) || p === undefined ? x : p, undefined as any);
diff --git a/src/mobile/AudioUpload.tsx b/src/mobile/AudioUpload.tsx
index 604c9a5ab..21c156ac0 100644
--- a/src/mobile/AudioUpload.tsx
+++ b/src/mobile/AudioUpload.tsx
@@ -81,7 +81,6 @@ export class AudioUpload extends React.Component {
<DocumentView
Document={this._audioCol}
DataDoc={undefined}
- LibraryPath={emptyPath}
addDocument={undefined}
addDocTab={returnFalse}
pinToPres={emptyFunction}
diff --git a/src/mobile/MobileInterface.tsx b/src/mobile/MobileInterface.tsx
index ae88a2eaf..3d5c70ff7 100644
--- a/src/mobile/MobileInterface.tsx
+++ b/src/mobile/MobileInterface.tsx
@@ -202,7 +202,6 @@ export class MobileInterface extends React.Component {
<DocumentView
Document={this.mainContainer}
DataDoc={undefined}
- LibraryPath={emptyPath}
addDocument={returnFalse}
addDocTab={returnFalse}
pinToPres={emptyFunction}
diff --git a/src/server/websocket.ts b/src/server/websocket.ts
index 7d111f359..6850f0601 100644
--- a/src/server/websocket.ts
+++ b/src/server/websocket.ts
@@ -279,13 +279,13 @@ export namespace WebSocket {
const updatefield = Array.from(Object.keys(diff.diff.$set))[0];
const newListItems = diff.diff.$set[updatefield].fields;
const curList = (curListItems as any)?.fields?.[updatefield.replace("fields.", "")]?.fields.filter((item: any) => item !== undefined) || [];
- diff.diff.$set[updatefield].fields = [...curList, ...newListItems.filter((newItem: any) => newItem && !curList.some((curItem: any) => curItem.fieldId ? curItem.fieldId === newItem.fieldId : curItem.heading ? curItem.heading === newItem.heading : curItem === newItem))];
+ diff.diff.$set[updatefield].fields = [...curList, ...newListItems.filter((newItem: any) => newItem === null || !curList.some((curItem: any) => curItem.fieldId ? curItem.fieldId === newItem.fieldId : curItem.heading ? curItem.heading === newItem.heading : curItem === newItem))];
const sendBack = diff.diff.length !== diff.diff.$set[updatefield].fields.length;
delete diff.diff.length;
Database.Instance.update(diff.id, diff.diff,
() => {
if (sendBack) {
- console.log("RET BACK");
+ console.log("Warning: list modified during update. Composite list is being returned.");
const id = socket.id;
socket.id = "";
socket.broadcast.emit(MessageStore.UpdateField.Message, diff);