aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/collections
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/views/collections')
-rw-r--r--src/client/views/collections/CollectionDockingView.scss76
-rw-r--r--src/client/views/collections/CollectionDockingView.tsx36
-rw-r--r--src/client/views/collections/CollectionLinearView.scss2
-rw-r--r--src/client/views/collections/CollectionMenu.scss1
-rw-r--r--src/client/views/collections/CollectionMenu.tsx62
-rw-r--r--src/client/views/collections/CollectionStackingView.tsx26
-rw-r--r--src/client/views/collections/CollectionStackingViewFieldColumn.tsx7
-rw-r--r--src/client/views/collections/CollectionSubView.tsx4
-rw-r--r--src/client/views/collections/CollectionTreeView.scss15
-rw-r--r--src/client/views/collections/CollectionView.tsx20
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx6
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss139
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx58
-rw-r--r--src/client/views/collections/collectionFreeForm/MarqueeView.tsx13
-rw-r--r--src/client/views/collections/collectionFreeForm/PropertiesView.scss105
-rw-r--r--src/client/views/collections/collectionFreeForm/PropertiesView.tsx528
16 files changed, 873 insertions, 225 deletions
diff --git a/src/client/views/collections/CollectionDockingView.scss b/src/client/views/collections/CollectionDockingView.scss
index 6ebd5103b..4204ef5bb 100644
--- a/src/client/views/collections/CollectionDockingView.scss
+++ b/src/client/views/collections/CollectionDockingView.scss
@@ -20,6 +20,82 @@
}
}
+.miniPres:hover {
+ opacity: 1;
+}
+
+.miniPres {
+ position: absolute;
+ overflow: hidden;
+ right: 10;
+ top: 10;
+ opacity: 0.1;
+ transition: all 0.4s;
+ /* border: solid 1px; */
+ color: white;
+ /* box-shadow: black 0.4vw 0.4vw 0.8vw; */
+
+ .miniPresOverlay {
+ display: grid;
+ grid-template-columns: auto auto auto auto auto auto auto auto;
+ grid-template-rows: 100%;
+ height: 100%;
+ justify-items: center;
+ align-items: center;
+
+ .miniPres-button-text {
+ display: flex;
+ height: 20;
+ font-weight: 400;
+ min-width: 100%;
+ border-radius: 5px;
+ align-items: center;
+ justify-content: center;
+ transition: all 0.3s;
+ }
+
+ .miniPres-button-frame {
+ justify-self: center;
+ align-self: center;
+ align-items: center;
+ display: grid;
+ grid-template-columns: auto auto auto;
+ justify-content: space-around;
+ font-size: 11;
+ margin-left: 7;
+ width: 30;
+ height: 85%;
+ background-color: rgba(91, 157, 221, 0.4);
+ border-radius: 5px;
+ }
+
+ .miniPres-divider {
+ width: 0.5px;
+ height: 80%;
+ border-right: solid 2px #5a5a5a;
+ }
+
+ .miniPres-button {
+ display: flex;
+ height: 20;
+ min-width: 20;
+ border-radius: 100%;
+ align-items: center;
+ justify-content: center;
+ transition: all 0.3s;
+ }
+
+ .miniPres-button:hover {
+ background-color: #5a5a5a;
+ }
+
+ .miniPres-button-text:hover {
+ background-color: #5a5a5a;
+ }
+ }
+}
+
+
.lm_title {
margin-top: 3px;
border-radius: 5px;
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index 533c8bffe..7e096fa37 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -30,6 +30,8 @@ import { SnappingManager } from '../../util/SnappingManager';
import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormView';
import { listSpec } from '../../../fields/Schema';
import { clamp } from 'lodash';
+import { PresBox } from '../nodes/PresBox';
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { InteractionUtils } from '../../util/InteractionUtils';
import { InkTool } from '../../../fields/InkField';
const _global = (window /* browser */ || global /* node */) as any;
@@ -793,10 +795,10 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
let scaling = 1;
if (!this.layoutDoc?._fitWidth && (!nativeW || !nativeH)) {
scaling = 1;
- } else if ((this.layoutDoc?._fitWidth) ||
- this._panelHeight / NumCast(this.layoutDoc!._nativeHeight) > this._panelWidth / NumCast(this.layoutDoc!._nativeWidth)) {
+ } else if (NumCast(this.layoutDoc!._nativeWidth) && ((this.layoutDoc?._fitWidth) ||
+ this._panelHeight / NumCast(this.layoutDoc!._nativeHeight) > this._panelWidth / NumCast(this.layoutDoc!._nativeWidth))) {
scaling = this._panelWidth / NumCast(this.layoutDoc!._nativeWidth);
- } else {
+ } else if (nativeW && nativeH) {
// if (this.layoutDoc!.type === DocumentType.PDF || this.layoutDoc!.type === DocumentType.WEB) {
// if ((this.layoutDoc?._fitWidth) ||
// this._panelHeight / NumCast(this.layoutDoc!._nativeHeight) > this._panelWidth / NumCast(this.layoutDoc!._nativeWidth)) {
@@ -807,7 +809,7 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
// }
const wscale = this.panelWidth() / nativeW;
scaling = wscale * nativeH > this._panelHeight ? this._panelHeight / nativeH : wscale;
- }
+ } else scaling = 1;
return scaling;
}
@@ -862,6 +864,31 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
return false;
}), emptyFunction, emptyFunction);
}
+ getCurrentFrame = (): number => {
+ const presTargetDoc = Cast(PresBox.Instance.childDocs[PresBox.Instance.itemIndex].presentationTargetDoc, Doc, null);
+ const currentFrame = Cast(presTargetDoc.currentFrame, "number", null);
+ return currentFrame;
+ }
+ renderMiniPres() {
+ return (
+ <div className="miniPres"
+ style={{ width: 250, height: 30, background: '#323232' }}
+ >
+ {<div className="miniPresOverlay">
+ <div className="miniPres-button" onClick={PresBox.Instance.back}><FontAwesomeIcon icon={"arrow-left"} /></div>
+ <div className="miniPres-button" onClick={() => PresBox.Instance.startAutoPres(PresBox.Instance.itemIndex)}><FontAwesomeIcon icon={PresBox.Instance.layoutDoc.presStatus === "auto" ? "pause" : "play"} /></div>
+ <div className="miniPres-button" onClick={PresBox.Instance.next}><FontAwesomeIcon icon={"arrow-right"} /></div>
+ <div className="miniPres-divider"></div>
+ <div className="miniPres-button-text">
+ Slide {PresBox.Instance.itemIndex + 1} / {PresBox.Instance.childDocs.length}
+ {PresBox.Instance.playButtonFrames}
+ </div>
+ <div className="miniPres-divider"></div>
+ <div className="miniPres-button-text" onClick={PresBox.Instance.updateMinimize}>EXIT</div>
+ </div>}
+ </div>
+ );
+ }
renderMiniMap() {
return <div className="miniMap" style={{
width: this.returnMiniSize(), height: this.returnMiniSize(), background: StrCast(this._document!._backgroundColor,
@@ -944,6 +971,7 @@ export class DockedFrameRenderer extends React.Component<DockedFrameProps> {
ContainingCollectionView={undefined}
ContainingCollectionDoc={undefined} />
{document._viewType === CollectionViewType.Freeform && !this._document?.hideMinimap ? this.renderMiniMap() : (null)}
+ {document._viewType === CollectionViewType.Freeform && this._document?.miniPres ? this.renderMiniPres() : (null)}
</>;
}
diff --git a/src/client/views/collections/CollectionLinearView.scss b/src/client/views/collections/CollectionLinearView.scss
index b8b72e756..f5c4299a9 100644
--- a/src/client/views/collections/CollectionLinearView.scss
+++ b/src/client/views/collections/CollectionLinearView.scss
@@ -2,7 +2,7 @@
@import "../_nodeModuleOverrides";
.collectionLinearView-outer {
- overflow: hidden;
+ overflow: visible;
height: 100%;
.collectionLinearView {
diff --git a/src/client/views/collections/CollectionMenu.scss b/src/client/views/collections/CollectionMenu.scss
index 0a316317f..b41cbe92d 100644
--- a/src/client/views/collections/CollectionMenu.scss
+++ b/src/client/views/collections/CollectionMenu.scss
@@ -368,6 +368,7 @@
}
}
+
.numKeyframe {
flex-direction: column;
padding-top: 5px;
diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index 4eb0088f6..53d2a136e 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -183,7 +183,7 @@ export class CollectionViewBaseChrome extends React.Component<CollectionMenuProp
initialize: (button: Doc) => { button['target-docFilters'] = this.target._docFilters instanceof ObjectField ? ObjectField.MakeCopy(this.target._docFilters as any as ObjectField) : ""; },
};
- @computed get _freeform_commands() { return Doc.UserDoc().noviceMode ? [this._viewCommand, this._saveFilterCommand] : [this._viewCommand, this._saveFilterCommand, this._contentCommand, this._templateCommand, this._narrativeCommand]; }
+ @computed get _freeform_commands() { return Doc.UserDoc().noviceMode ? [this._viewCommand] : [this._viewCommand, this._saveFilterCommand, this._contentCommand, this._templateCommand, this._narrativeCommand]; }
@computed get _stacking_commands() { return Doc.UserDoc().noviceMode ? undefined : [this._contentCommand, this._templateCommand]; }
@computed get _masonry_commands() { return Doc.UserDoc().noviceMode ? undefined : [this._contentCommand, this._templateCommand]; }
@computed get _schema_commands() { return Doc.UserDoc().noviceMode ? undefined : [this._templateCommand, this._narrativeCommand]; }
@@ -234,7 +234,8 @@ export class CollectionViewBaseChrome extends React.Component<CollectionMenuProp
@computed get subChrome() {
switch (this.props.type) {
- default:
+ default: return this.otherSubChrome;
+ case CollectionViewType.Invalid:
case CollectionViewType.Freeform: return (<CollectionFreeFormViewChrome key="collchrome" {...this.props} isOverlay={this.props.type === CollectionViewType.Invalid} />);
case CollectionViewType.Stacking: return (<CollectionStackingViewChrome key="collchrome" {...this.props} />);
case CollectionViewType.Schema: return (<CollectionSchemaViewChrome key="collchrome" {...this.props} />);
@@ -245,6 +246,21 @@ export class CollectionViewBaseChrome extends React.Component<CollectionMenuProp
case CollectionViewType.Docking: return (<CollectionDockingChrome key="collchrome" {...this.props} />);
}
}
+
+ @computed get otherSubChrome() {
+ const docType = this.props.docView.Document.type;
+ switch (docType) {
+ default: return (null);
+ case DocumentType.IMG: return (<CollectionFreeFormViewChrome key="collchrome" {...this.props} isOverlay={false} isDoc={true} />);
+ case DocumentType.PDF: return (<CollectionFreeFormViewChrome key="collchrome" {...this.props} isOverlay={false} isDoc={true} />);
+ case DocumentType.INK: return (<CollectionFreeFormViewChrome key="collchrome" {...this.props} isOverlay={false} isDoc={true} />);
+ case DocumentType.WEB: return (<CollectionFreeFormViewChrome key="collchrome" {...this.props} isOverlay={false} isDoc={true} />);
+ case DocumentType.VID: return (<CollectionFreeFormViewChrome key="collchrome" {...this.props} isOverlay={false} isDoc={true} />);
+ case DocumentType.RTF: return (<CollectionFreeFormViewChrome key="collchrome" {...this.props} isOverlay={this.props.type === CollectionViewType.Invalid} isDoc={true} />);
+ }
+ }
+
+
private dropDisposer?: DragManager.DragDropDisposer;
protected createDropTarget = (ele: HTMLDivElement) => {
this.dropDisposer?.();
@@ -390,7 +406,7 @@ export class CollectionDockingChrome extends React.Component<CollectionMenuProps
}
@observer
-export class CollectionFreeFormViewChrome extends React.Component<CollectionMenuProps & { isOverlay: boolean }> {
+export class CollectionFreeFormViewChrome extends React.Component<CollectionMenuProps & { isOverlay: boolean, isDoc?: boolean }> {
public static Instance: CollectionFreeFormViewChrome;
constructor(props: any) {
super(props);
@@ -565,6 +581,8 @@ export class CollectionFreeFormViewChrome extends React.Component<CollectionMenu
style={{ backgroundColor: this._colorBtn ? "121212" : "", zIndex: 1001 }}>
{/* <FontAwesomeIcon icon="pen-nib" size="lg" /> */}
<div className="color-previewII" style={{ backgroundColor: color }} />
+ {color === "" ? <p style={{ fontSize: 45, color: "red", marginTop: -16, marginLeft: -5, position: "fixed" }}>☒</p> : ""}
+
</button>)}
</div>;
}
@@ -578,40 +596,44 @@ export class CollectionFreeFormViewChrome extends React.Component<CollectionMenu
<button className="antimodeMenu-button" key={color}
onPointerDown={action(() => { this.changeColor(color, "fill"); this._fillBtn = false; this.editProperties(color, "fill"); })}
style={{ backgroundColor: this._fillBtn ? "121212" : "", zIndex: 1001 }}>
- <div className="color-previewII" style={{ backgroundColor: color }}></div>
+ <div className="color-previewII" style={{ backgroundColor: color }}>
+ {color === "" ? <p style={{ fontSize: 45, color: "red", marginTop: -16, marginLeft: -5, position: "fixed" }}>☒</p> : ""}
+ </div>
</button>)}
</div>;
}
+ @observable viewType = this.selectedDoc?._viewType;
+
render() {
return !this.props.docView.layoutDoc ? (null) :
<div className="collectionFreeFormMenu-cont">
- {this.props.docView.props.renderDepth !== 0 || this.isText ? (null) :
+ {this.props.docView.props.renderDepth !== 0 || this.isText || this.props.isDoc ? (null) :
<Tooltip key="map" title={<div className="dash-tooltip">Toggle Mini Map</div>} placement="bottom">
- <div className="backKeyframe" onClick={this.miniMap}>
+ <div className="backKeyframe" onClick={this.miniMap} style={{ marginRight: "5px" }}>
<FontAwesomeIcon icon={"map"} size={"lg"} />
</div>
</Tooltip>
}
- {!this.isText ? <Tooltip key="back" title={<div className="dash-tooltip">Back Frame</div>} placement="bottom">
+ {!this.isText && !this.props.isDoc ? <Tooltip key="back" title={<div className="dash-tooltip">Back Frame</div>} placement="bottom">
<div className="backKeyframe" onClick={this.prevKeyframe}>
<FontAwesomeIcon icon={"caret-left"} size={"lg"} />
</div>
</Tooltip> : null}
- {!this.isText ? <Tooltip key="num" title={<div className="dash-tooltip">Toggle View All</div>} placement="bottom">
+ {!this.isText && !this.props.isDoc ? <Tooltip key="num" title={<div className="dash-tooltip">Toggle View All</div>} placement="bottom">
<div className="numKeyframe" style={{ backgroundColor: this.document.editing ? "#759c75" : "#c56565" }}
onClick={action(() => this.document.editing = !this.document.editing)} >
{NumCast(this.document.currentFrame)}
</div>
</Tooltip> : null}
- {!this.isText ? <Tooltip key="fwd" title={<div className="dash-tooltip">Forward Frame</div>} placement="bottom">
+ {!this.isText && !this.props.isDoc ? <Tooltip key="fwd" title={<div className="dash-tooltip">Forward Frame</div>} placement="bottom">
<div className="fwdKeyframe" onClick={this.nextKeyframe}>
<FontAwesomeIcon icon={"caret-right"} size={"lg"} />
</div>
</Tooltip> : null}
- {!this.props.isOverlay || this.document.type !== DocumentType.WEB || this.isText ? (null) :
+ {!this.props.isOverlay || this.document.type !== DocumentType.WEB || this.isText || this.props.isDoc ? (null) :
<Tooltip key="hypothesis" title={<div className="dash-tooltip">Use Hypothesis</div>} placement="bottom">
<button className={"antimodeMenu-button"} key="hypothesis"
style={{
@@ -623,7 +645,7 @@ export class CollectionFreeFormViewChrome extends React.Component<CollectionMenu
</button>
</Tooltip>
}
- {(!this.props.isOverlay || this.props.docView.layoutDoc.isAnnotating) && !this.isText ?
+ {!this.isText ?
<>
{this.drawButtons}
{this.widthPicker}
@@ -649,6 +671,24 @@ export class CollectionStackingViewChrome extends React.Component<CollectionMenu
getKeySuggestions = async (value: string): Promise<string[]> => {
value = value.toLowerCase();
const docs = DocListCast(this.document[this.props.fieldKey]);
+
+ if (Doc.UserDoc().noviceMode) {
+ if (docs instanceof Doc) {
+ const keys = Object.keys(docs).filter(key => key.indexOf("title") >= 0 || key.indexOf("author") >= 0 ||
+ key.indexOf("creationDate") >= 0 || key.indexOf("lastModified") >= 0 ||
+ (key[0].toUpperCase() === key[0] && key.substring(0, 3) !== "ACL" && key !== "UseCors" && key[0] !== "_"));
+ return keys.filter(key => key.toLowerCase().indexOf(value.toLowerCase()) > -1);
+ } else {
+ const keys = new Set<string>();
+ docs.forEach(doc => Doc.allKeys(doc).forEach(key => keys.add(key)));
+ const noviceKeys = Array.from(keys).filter(key => key.indexOf("title") >= 0 ||
+ key.indexOf("author") >= 0 || key.indexOf("creationDate") >= 0 ||
+ key.indexOf("lastModified") >= 0 || (key[0].toUpperCase() === key[0] &&
+ key.substring(0, 3) !== "ACL" && key !== "UseCors" && key[0] !== "_"));
+ return noviceKeys.filter(key => key.toLowerCase().indexOf(value.toLowerCase()) > -1);
+ }
+ }
+
if (docs instanceof Doc) {
return Object.keys(docs).filter(key => key.toLowerCase().startsWith(value));
} else {
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index cca78cf9f..fe3d57bdb 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -184,7 +184,7 @@ export class CollectionStackingView extends CollectionSubView(StackingDocument)
if (found) {
const top = found.getBoundingClientRect().top;
const localTop = this.props.ScreenToLocalTransform().transformPoint(0, top);
- smoothScroll(500, this._mainCont!, localTop[1] + this._mainCont!.scrollTop);
+ smoothScroll(doc.presTransition || doc.presTransition === 0 ? NumCast(doc.presTransition) : 500, this._mainCont!, localTop[1] + this._mainCont!.scrollTop);
}
afterFocus && setTimeout(() => {
if (afterFocus?.()) { }
@@ -287,19 +287,31 @@ export class CollectionStackingView extends CollectionSubView(StackingDocument)
}
});
if (super.onInternalDrop(e, de)) {
- const newDoc = de.complete.docDragData.droppedDocuments[0];
+ const newDocs = de.complete.docDragData.droppedDocuments;
const docs = this.childDocList;
if (docs) {
- if (targInd === -1) targInd = docs.length;
- else targInd = docs.indexOf(this.filteredChildren[targInd]);
- const srcInd = docs.indexOf(newDoc);
- docs.splice(srcInd, 1);
- docs.splice((targInd > srcInd ? targInd - 1 : targInd) + plusOne, 0, newDoc);
+ newDocs.map((doc, i) => {
+ console.log(doc.title);
+ if (i === 0) {
+ if (targInd === -1) targInd = docs.length;
+ else targInd = docs.indexOf(this.filteredChildren[targInd]);
+ const srcInd = docs.indexOf(doc);
+ docs.splice(srcInd, 1);
+ docs.splice((targInd > srcInd ? targInd - 1 : targInd) + plusOne, 0, doc);
+ } else if (i < (newDocs.length / 2)) { //glr: for some reason dragged documents are duplicated
+ if (targInd === -1) targInd = docs.length;
+ else targInd = docs.indexOf(newDocs[0]) + 1;
+ const srcInd = docs.indexOf(doc);
+ docs.splice(srcInd, 1);
+ docs.splice((targInd > srcInd ? targInd - 1 : targInd) + plusOne, 0, doc);
+ }
+ });
}
}
}
return false;
}
+
@undoBatch
@action
onExternalDrop = async (e: React.DragEvent): Promise<void> => {
diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
index 4042a070d..f193a9787 100644
--- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
+++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx
@@ -12,6 +12,7 @@ import { NumCast, StrCast, Cast } from "../../../fields/Types";
import { ImageField } from "../../../fields/URLField";
import { TraceMobx } from "../../../fields/util";
import { Docs, DocUtils } from "../../documents/Documents";
+import { DocumentType } from "../../documents/DocumentTypes";
import { DragManager } from "../../util/DragManager";
import { Transform } from "../../util/Transform";
import { undoBatch } from "../../util/UndoManager";
@@ -346,7 +347,7 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
</div> : (null);
for (let i = 0; i < cols; i++) templatecols += `${style.columnWidth / style.numGroupColumns}px `;
const chromeStatus = this.props.parent.props.Document._chromeStatus;
-
+ const type = this.props.parent.props.Document.type;
return <>
{this.props.parent.Document._columnsHideIfEmpty ? (null) : headingView}
{
@@ -366,9 +367,9 @@ export class CollectionStackingViewFieldColumn extends React.Component<CSVFieldC
{this.props.parent.children(this.props.docList, uniqueHeadings.length)}
{singleColumn ? (null) : this.props.parent.columnDragger}
</div>
- {(chromeStatus !== 'view-mode' && chromeStatus !== 'disabled') ?
+ {(chromeStatus !== 'view-mode' && chromeStatus !== 'disabled' && type !== DocumentType.PRES) ?
<div key={`${heading}-add-document`} className="collectionStackingView-addDocumentButton"
- style={{ width: style.columnWidth / style.numGroupColumns }}>
+ style={{ width: style.columnWidth / style.numGroupColumns, marginBottom: 70 }}>
<EditableView {...newEditableViewProps} menuCallback={this.menuCallback} />
</div> : null}
</div>
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index 9a64298fb..0a1bb3594 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -396,8 +396,8 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
title: uriList,
_width: 400,
_height: 315,
- _nativeWidth: 600,
- _nativeHeight: 472.5
+ _nativeWidth: 850,
+ _nativeHeight: 962
}));
return;
}
diff --git a/src/client/views/collections/CollectionTreeView.scss b/src/client/views/collections/CollectionTreeView.scss
index 50f0534bd..c9bf82406 100644
--- a/src/client/views/collections/CollectionTreeView.scss
+++ b/src/client/views/collections/CollectionTreeView.scss
@@ -22,7 +22,7 @@
ul {
list-style: none;
padding-left: 20px;
- margin-bottom: 1px;// otherwise vertical scrollbars may pop up for no apparent reason....
+ margin-bottom: 1px; // otherwise vertical scrollbars may pop up for no apparent reason....
}
@@ -35,7 +35,7 @@
width: 15px;
color: $intermediate-color;
margin-top: 3px;
- transform: scale(1.3, 1.3);
+ transform: scale(1.3, 1.3);
border: #80808030 1px solid;
border-radius: 4px;
}
@@ -67,8 +67,10 @@
margin-left: 3px;
display: none;
}
+
.collectionTreeView-keyHeader:hover {
background: #797777;
+ cursor: pointer;
}
.collectionTreeView-subtitle {
@@ -89,8 +91,10 @@
height: 17px;
width: 15px;
}
+
.treeViewItem-openRight:hover {
background: #797777;
+ cursor: pointer;
}
.treeViewItem-border {
@@ -106,10 +110,12 @@
.editableView-container-editing-oneLine {
min-width: 15px;
}
+
.documentView-node-topmost {
width: unset;
}
- > svg {
+
+ >svg {
display: none;
}
@@ -119,7 +125,8 @@
.collectionTreeView-keyHeader {
display: inherit;
}
- > svg {
+
+ >svg {
display: inherit;
}
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 6e15cb887..4d1cb670c 100644
--- a/src/client/views/collections/CollectionView.tsx
+++ b/src/client/views/collections/CollectionView.tsx
@@ -17,7 +17,7 @@ import { listSpec } from '../../../fields/Schema';
import { ComputedField, ScriptField } from '../../../fields/ScriptField';
import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from '../../../fields/Types';
import { ImageField } from '../../../fields/URLField';
-import { TraceMobx, GetEffectiveAcl, SharingPermissions } from '../../../fields/util';
+import { TraceMobx, GetEffectiveAcl, SharingPermissions, distributeAcls } from '../../../fields/util';
import { emptyFunction, emptyPath, returnEmptyFilter, returnFalse, returnOne, returnZero, setupMoveUpEvents, Utils } from '../../../Utils';
import { Docs, DocUtils } from '../../documents/Documents';
import { DocumentType } from '../../documents/DocumentTypes';
@@ -148,16 +148,14 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
return false;
}
else {
- // if (this.props.Document[AclSym]) {
- // // change so it only adds if more restrictive
- // added.forEach(d => {
- // // const dataDoc = d[DataSym];
- // for (const [key, value] of Object.entries(this.props.Document[AclSym])) {
- // // key.substring(4).replace("_", ".") !== Doc.CurrentUserEmail && distributeAcls(key, this.AclMap.get(value) as SharingPermissions, d, true);
- // distributeAcls(key, this.AclMap.get(value) as SharingPermissions, d, true);
- // }
- // });
- // }
+ if (this.props.Document[AclSym]) {
+ added.forEach(d => {
+ for (const [key, value] of Object.entries(this.props.Document[AclSym])) {
+ if (d.author === Doc.CurrentUserEmail && !d.aliasOf) distributeAcls(key, SharingPermissions.Admin, d, true);
+ else distributeAcls(key, this.AclMap.get(value) as SharingPermissions, d, true);
+ }
+ });
+ }
if (effectiveAcl === AclAddonly) {
added.map(doc => Doc.AddDocToList(targetDataDoc, this.props.fieldKey, doc));
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
index bfe569853..3a2979696 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
@@ -54,15 +54,15 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
const bfield = afield === "anchor1" ? "anchor2" : "anchor1";
// really hacky stuff to make the LinkAnchorBox display where we want it to:
- // if there's an element in the DOM with a classname containing the link's id and a targetids attribute containing the other end of the link,
+ // if there's an element in the DOM with a classname containing the link's id and a data-targetids attribute containing the other end of the link,
// then that DOM element is a hyperlink source for the current anchor and we want to place our link box at it's top right
// otherwise, we just use the computed nearest point on the document boundary to the target Document
const linkId = this.props.LinkDocs[0][Id]; // this link's Id
const AanchorId = (this.props.LinkDocs[0][afield] as Doc)[Id]; // anchor a's id
const BanchorId = (this.props.LinkDocs[0][bfield] as Doc)[Id]; // anchor b's id
const linkEles = Array.from(window.document.getElementsByClassName(linkId));
- const targetAhyperlink = linkEles.find((ele: any) => ele.getAttribute("targetids")?.includes(AanchorId));
- const targetBhyperlink = linkEles.find((ele: any) => ele.getAttribute("targetids")?.includes(BanchorId));
+ const targetAhyperlink = linkEles.find((ele: any) => ele.dataset.targetids?.includes(AanchorId));
+ const targetBhyperlink = linkEles.find((ele: any) => ele.dataset.targetids?.includes(BanchorId));
if (!targetBhyperlink) {
this.props.A.rootDoc[afield + "_x"] = (apt.point.x - abounds.left) / abounds.width * 100;
this.props.A.rootDoc[afield + "_y"] = (apt.point.y - abounds.top) / abounds.height * 100;
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss
index 92aee3776..2b07c4efb 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss
@@ -13,16 +13,153 @@
}
.collectionfreeformview-viewdef {
- > .collectionFreeFormDocumentView-container {
+ >.collectionFreeFormDocumentView-container {
pointer-events: none;
+
.contentFittingDocumentDocumentView-previewDoc {
pointer-events: all;
}
}
+
+ svg.presPaths {
+ position: absolute;
+ z-index: 100000;
+ overflow: visible;
+ }
+
+ svg.presPaths-hidden {
+ display: none;
+ }
}
.collectionfreeformview-none {
touch-action: none;
+
+ svg.presPaths {
+ position: absolute;
+ z-index: 100000;
+ overflow: visible;
+ }
+
+ svg.presPaths-hidden {
+ display: none;
+ }
+}
+
+.pathOrder {
+ position: absolute;
+ z-index: 200000;
+
+ .pathOrder-frame {
+ position: absolute;
+ width: 40;
+ text-align: center;
+ font-size: 30;
+ background-color: #69a6db;
+ font-family: Roboto;
+ font-weight: 300;
+ }
+}
+
+.progressivizeButton {
+ position: absolute;
+ display: grid;
+ grid-template-columns: auto 20px auto;
+ transform: translate(-105%, 0);
+ align-items: center;
+ border: black solid 1px;
+ border-radius: 3px;
+ justify-content: center;
+ width: 40;
+ z-index: 30000;
+ height: 20;
+ overflow: hidden;
+ background-color: #d5dce2;
+ transition: all 1s;
+
+ .progressivizeButton-prev:hover {
+ color: #5a9edd;
+ }
+
+ .progressivizeButton-frame {
+ justify-self: center;
+ text-align: center;
+ width: 15px;
+ }
+
+ .progressivizeButton-next:hover {
+ color: #5a9edd;
+ }
+}
+
+.resizable {
+ background: rgba(0, 0, 0, 0.2);
+ width: 100px;
+ height: 100px;
+ position: absolute;
+ top: 100px;
+ left: 100px;
+
+ .resizers {
+ width: 100%;
+ height: 100%;
+ border: 3px solid #69a6db;
+ box-sizing: border-box;
+
+ .resizer {
+ position: absolute;
+ width: 10px;
+ height: 10px;
+ border-radius: 50%;
+ /*magic to turn square into circle*/
+ background: white;
+ border: 3px solid #69a6db;
+ }
+
+ .resizer.top-left {
+ left: -3px;
+ top: -3px;
+ cursor: nwse-resize;
+ /*resizer cursor*/
+ }
+
+ .resizer.top-right {
+ right: -3px;
+ top: -3px;
+ cursor: nesw-resize;
+ }
+
+ .resizer.bottom-left {
+ left: -3px;
+ bottom: -3px;
+ cursor: nesw-resize;
+ }
+
+ .resizer.bottom-right {
+ right: -3px;
+ bottom: -3px;
+ cursor: nwse-resize;
+ }
+ }
+}
+
+.progressivizeMove-frame {
+ width: 20px;
+ border-radius: 2px;
+ z-index: 100000;
+ color: white;
+ text-align: center;
+ background-color: #5a9edd;
+ transform: translate(-110%, 110%);
+}
+
+.progressivizeButton:hover {
+ box-shadow: 0px 2px 3px rgba(0, 0, 0, 0.5);
+
+ .progressivizeButton-frame {
+ background-color: #5a9edd;
+ color: white;
+ }
}
.collectionFreeform-customText {
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index badbc48a1..ef4b7b9d2 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -1,7 +1,7 @@
import { library } from "@fortawesome/fontawesome-svg-core";
import { faEye } from "@fortawesome/free-regular-svg-icons";
import { faBraille, faChalkboard, faCompass, faCompressArrowsAlt, faExpandArrowsAlt, faFileUpload, faPaintBrush, faTable, faUpload } from "@fortawesome/free-solid-svg-icons";
-import { action, computed, IReactionDisposer, observable, ObservableMap, reaction, runInAction } from "mobx";
+import { action, computed, IReactionDisposer, observable, ObservableMap, reaction, runInAction, trace } from "mobx";
import { observer } from "mobx-react";
import { computedFn } from "mobx-utils";
import { Doc, DocListCast, HeightSym, Opt, WidthSym } from "../../../../fields/Doc";
@@ -46,6 +46,7 @@ import "./CollectionFreeFormView.scss";
import MarqueeOptionsMenu from "./MarqueeOptionsMenu";
import { MarqueeView } from "./MarqueeView";
import React = require("react");
+import { PresBox } from "../../nodes/PresBox";
import { SearchUtil } from "../../../util/SearchUtil";
import { LinkManager } from "../../../util/LinkManager";
@@ -76,7 +77,7 @@ export type collectionFreeformViewProps = {
forceScaling?: boolean; // whether to force scaling of content (needed by ImageBox)
viewDefDivClick?: ScriptField;
childPointerEvents?: boolean;
- scaleField?: string; // used by formattedTextBox when displaying a sidebar freeform view which needs its own scale field
+ scaleField?: string;
noOverlay?: boolean; // used to suppress docs in the overlay (z) layer (ie, for minimap since overlay doesn't scale)
};
@@ -213,7 +214,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
const layoutDoc = Doc.Layout(d);
if (this.Document.currentFrame !== undefined) {
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.opacity);
+ CollectionFreeFormDocumentView.setValues(this.Document.currentFrame, d, x + vals.x - dropPos[0], y + vals.y - dropPos[1], vals.h, vals.w, vals.opacity);
} else {
d.x = x + NumCast(d.x) - dropPos[0];
d.y = y + NumCast(d.y) - dropPos[1];
@@ -911,7 +912,8 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
// !doc.z && NumCast(this.layoutDoc.scale) < 1 && this.scaleAtPt(DocumentView._focusHack, 1); // [NumCast(doc.x), NumCast(doc.y)], 1);
// } else {
if (DocListCast(this.dataDoc[this.props.fieldKey]).includes(doc)) {
- if (!doc.z) this.setPan(newPanX, newPanY, "transform 500ms", true); // docs that are floating in their collection can't be panned to from their collection -- need to propagate the pan to a parent freeform somehow
+ // glr: freeform transform speed can be set by adjusting presTransition field - needs a way of knowing when presentation is not active...
+ if (!doc.z) this.setPan(newPanX, newPanY, doc.presTransition || doc.presTransition === 0 ? `transform ${doc.presTransition}ms` : "transform 500ms", true); // docs that are floating in their collection can't be panned to from their collection -- need to propagate the pan to a parent freeform somehow
}
Doc.BrushDoc(this.props.Document);
this.props.focus(this.props.Document);
@@ -1257,7 +1259,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
this.props.ContainingCollectionView &&
optionItems.push({ description: "Promote Collection", event: this.promoteCollection, icon: "table" });
optionItems.push({ description: this.layoutDoc._lockedTransform ? "Unlock Transform" : "Lock Transform", event: this.toggleLockTransform, icon: this.layoutDoc._lockedTransform ? "unlock" : "lock" });
- appearanceItems.push({ description: "Use Background Color as Default", event: () => Cast(Doc.UserDoc().emptyCollection, Doc, null)._backgroundColor = StrCast(this.layoutDoc._backgroundColor), icon: "palette" });
+ optionItems.push({ description: "Use Background Color as Default", event: () => Cast(Doc.UserDoc().emptyCollection, Doc, null)._backgroundColor = StrCast(this.layoutDoc._backgroundColor), icon: "palette" });
if (!Doc.UserDoc().noviceMode) {
optionItems.push({ description: (!this.layoutDoc._nativeWidth || !this.layoutDoc._nativeHeight ? "Freeze" : "Unfreeze") + " Aspect", event: this.toggleNativeDimensions, icon: "snowflake" });
optionItems.push({ description: `${this.Document._freeformLOD ? "Enable LOD" : "Disable LOD"}`, event: () => this.Document._freeformLOD = !this.Document._freeformLOD, icon: "table" });
@@ -1399,6 +1401,9 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
<CollectionFreeFormViewPannableContents
centeringShiftX={this.centeringShiftX}
centeringShiftY={this.centeringShiftY}
+ presPaths={BoolCast(this.Document.presPathView)}
+ progressivize={BoolCast(this.Document.editProgressivize)}
+ zoomProgressivize={BoolCast(this.Document.editZoomProgressivize)}
transition={Cast(this.layoutDoc._viewTransition, "string", null)}
viewDefDivClick={this.props.viewDefDivClick}
zoomScaling={this.zoomScaling} panX={this.panX} panY={this.panY}>
@@ -1482,11 +1487,51 @@ interface CollectionFreeFormViewPannableContentsProps {
viewDefDivClick?: ScriptField;
children: () => JSX.Element[];
transition?: string;
+ presPaths?: boolean;
+ progressivize?: boolean;
+ zoomProgressivize?: boolean;
}
@observer
class CollectionFreeFormViewPannableContents extends React.Component<CollectionFreeFormViewPannableContentsProps>{
+ @computed get zoomProgressivize() {
+ return PresBox.Instance && this.props.zoomProgressivize ? PresBox.Instance.zoomProgressivizeContainer : (null);
+ }
+
+ @computed get progressivize() {
+ return PresBox.Instance && this.props.progressivize ? PresBox.Instance.progressivizeChildDocs : (null);
+ }
+
+ @computed get presPaths() {
+ const presPaths = "presPaths" + (this.props.presPaths ? "" : "-hidden");
+ return !(PresBox.Instance) ? (null) : (<>
+ {!this.props.presPaths ? (null) : <><div>{PresBox.Instance.order}</div>
+ <svg className={presPaths}>
+ <defs>
+ <marker id="arrow" markerWidth="3" overflow="visible" markerHeight="3" refX="5" refY="5" orient="auto" markerUnits="strokeWidth">
+ <path d="M0,0 L0,6 L9,3 z" fill="#69a6db" />
+ </marker>
+ <marker id="square" markerWidth="3" markerHeight="3" overflow="visible"
+ refX="5" refY="5" orient="auto" markerUnits="strokeWidth">
+ <path d="M 5,1 L 9,5 5,9 1,5 z" fill="#69a6db" />
+ </marker>
+ <marker id="markerSquare" markerWidth="7" markerHeight="7" refX="4" refY="4"
+ orient="auto" overflow="visible">
+ <rect x="1" y="1" width="5" height="5" fill="#69a6db" />
+ </marker>
+
+ <marker id="markerArrow" markerWidth="5" markerHeight="5" refX="2" refY="7"
+ orient="auto" overflow="visible">
+ <path d="M2,2 L2,13 L8,7 L2,2" fill="#69a6db" />
+ </marker>
+ </defs>;
+ {PresBox.Instance.paths}
+ </svg></>}
+ </>);
+ }
+
render() {
+ // trace();
const freeformclass = "collectionfreeformview" + (this.props.viewDefDivClick ? "-viewDef" : "-none");
const cenx = this.props.centeringShiftX();
const ceny = this.props.centeringShiftY();
@@ -1499,6 +1544,9 @@ class CollectionFreeFormViewPannableContents extends React.Component<CollectionF
transition: this.props.transition
}}>
{this.props.children()}
+ {this.presPaths}
+ {this.progressivize}
+ {this.zoomProgressivize}
</div>;
}
}
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index a32c8b363..88fe03efd 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -339,10 +339,21 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
this._visible = false;
}
+ @undoBatch
@action
delete = () => {
- this.props.removeDocument(this.marqueeSelect(false));
+ const recent = Cast(Doc.UserDoc().myRecentlyClosed, Doc) as Doc;
+ const selected = this.marqueeSelect(false);
SelectionManager.DeselectAll();
+
+ selected.map(doc => {
+ const effectiveAcl = GetEffectiveAcl(doc);
+ if (effectiveAcl === AclEdit || effectiveAcl === AclAdmin) { // deletes whatever you have the right to delete
+ recent && Doc.AddDocToList(recent, "data", doc, undefined, true, true);
+ this.props.removeDocument(doc);
+ }
+ });
+
this.cleanupInteractions(false);
MarqueeOptionsMenu.Instance.fadeOut(true);
this.hideMarquee();
diff --git a/src/client/views/collections/collectionFreeForm/PropertiesView.scss b/src/client/views/collections/collectionFreeForm/PropertiesView.scss
index 7df56115f..5e0c9fcbb 100644
--- a/src/client/views/collections/collectionFreeForm/PropertiesView.scss
+++ b/src/client/views/collections/collectionFreeForm/PropertiesView.scss
@@ -5,8 +5,8 @@
font-family: "Noto Sans";
cursor: auto;
- overflow-x: visible;
- overflow-y: visible;
+ overflow-x: hidden;
+ overflow-y: scroll;
.propertiesView-title {
background-color: rgb(159, 159, 159);
@@ -41,7 +41,7 @@
font-size: 12.5px;
&:hover {
- cursor: pointer;
+ cursor: text;
}
}
@@ -119,6 +119,19 @@
font-size: 10px;
padding: 10px;
margin-left: 5px;
+
+ .change-buttons {
+ display: flex;
+
+ button {
+ width: 5;
+ height: 5;
+ }
+
+ input {
+ width: 100%;
+ }
+ }
}
}
@@ -233,11 +246,15 @@
.propertiesView-sharingTable {
+ // whatever's commented out - add it back in when adding the buttons
+
+ // border: 1.5px solid black;
border: 1px solid black;
- padding: 5px;
- border-radius: 6px;
- /* width: 170px; */
- margin-right: 10px;
+ padding: 5px; // remove when adding buttons
+ border-radius: 6px; // remove when adding buttons
+ margin-right: 10px; // remove when adding buttons
+ // width: 100%;
+ // display: inline-table;
background-color: #ececec;
max-height: 130px;
overflow-y: scroll;
@@ -245,9 +262,11 @@
.propertiesView-sharingTable-item {
display: flex;
+ // padding: 5px;
padding: 3px;
align-items: center;
border-bottom: 0.5px solid grey;
+ cursor: pointer;
&:hover .propertiesView-sharingTable-item-name {
overflow-x: unset;
@@ -405,6 +424,43 @@
}
}
+
+ .propertiesView-presTrails {
+ border-bottom: 1px solid black;
+ //padding: 8.5px;
+
+ .propertiesView-presTrails-title {
+ font-weight: bold;
+ font-size: 12.5px;
+ padding: 4px;
+ display: flex;
+ color: white;
+ padding-left: 8px;
+ background-color: rgb(51, 51, 51);
+
+ &:hover {
+ cursor: pointer;
+ }
+
+ .propertiesView-presTrails-title-icon {
+ float: right;
+ right: 0;
+ position: absolute;
+ margin-left: 2px;
+ margin-right: 9px;
+
+ &:hover {
+ cursor: pointer;
+ }
+ }
+ }
+
+ .propertiesView-presTrails-content {
+ font-size: 10px;
+ padding: 10px;
+ margin-left: 5px;
+ }
+ }
}
.inking-button {
@@ -567,6 +623,27 @@
}
}
+.propertiesView-presSelected {
+ border-top: solid 1px darkgrey;
+ width: 100%;
+ padding-top: 5px;
+ font-family: Roboto;
+ font-weight: 500;
+ display: inline-flex;
+
+ .propertiesView-selectedList {
+ border-left: solid 1px darkgrey;
+ margin-left: 10px;
+ padding-left: 5px;
+
+ .selectedList-items {
+ font-size: 12;
+ font-weight: 300;
+ margin-top: 1;
+ }
+ }
+}
+
.widthAndDash {
.width {
@@ -596,6 +673,7 @@
display: flex;
margin-bottom: 3px;
+ margin-left: 4px;
.arrows-head {
@@ -629,7 +707,7 @@
.dashed {
display: flex;
- margin-left: 74px;
+ margin-left: 64px;
margin-bottom: 6px;
.dashed-title {
@@ -641,4 +719,15 @@
margin-top: 2px;
}
}
+}
+
+.editable-title {
+ border: none;
+ padding: 6px;
+ padding-bottom: 2px;
+
+
+ &:hover {
+ border: 0.75px solid rgb(122, 28, 28);
+ }
} \ No newline at end of file
diff --git a/src/client/views/collections/collectionFreeForm/PropertiesView.tsx b/src/client/views/collections/collectionFreeForm/PropertiesView.tsx
index 031dbf884..15900aa33 100644
--- a/src/client/views/collections/collectionFreeForm/PropertiesView.tsx
+++ b/src/client/views/collections/collectionFreeForm/PropertiesView.tsx
@@ -2,13 +2,11 @@ import React = require("react");
import { observer } from "mobx-react";
import "./PropertiesView.scss";
import { observable, action, computed, runInAction } from "mobx";
-import { Doc, Field, DocListCast, WidthSym, HeightSym, AclSym, AclPrivate, AclReadonly, AclAddonly, AclEdit, AclAdmin, Opt } from "../../../../fields/Doc";
-import { DocumentView } from "../../nodes/DocumentView";
+import { Doc, Field, WidthSym, HeightSym, AclSym, AclPrivate, AclReadonly, AclAddonly, AclEdit, AclAdmin, Opt, DocCastAsync } from "../../../../fields/Doc";
import { ComputedField } from "../../../../fields/ScriptField";
import { EditableView } from "../../EditableView";
import { KeyValueBox } from "../../nodes/KeyValueBox";
import { Cast, NumCast, StrCast } from "../../../../fields/Types";
-import { listSpec } from "../../../../fields/Schema";
import { ContentFittingDocumentView } from "../../nodes/ContentFittingDocumentView";
import { returnFalse, returnOne, emptyFunction, emptyPath, returnTrue, returnZero, returnEmptyFilter, Utils } from "../../../../Utils";
import { Id } from "../../../../fields/FieldSymbols";
@@ -16,18 +14,26 @@ import { Transform } from "../../../util/Transform";
import { PropertiesButtons } from "../../PropertiesButtons";
import { SelectionManager } from "../../../util/SelectionManager";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { Tooltip, Checkbox, Divider } from "@material-ui/core";
+import { Tooltip, Checkbox } from "@material-ui/core";
import SharingManager from "../../../util/SharingManager";
import { DocumentType } from "../../../documents/DocumentTypes";
-import FormatShapePane from "./FormatShapePane";
import { SharingPermissions, GetEffectiveAcl } from "../../../../fields/util";
import { InkField } from "../../../../fields/InkField";
-import { undoBatch } from "../../../util/UndoManager";
+import { undoBatch, UndoManager } from "../../../util/UndoManager";
import { ColorState, SketchPicker } from "react-color";
-import AntimodeMenu from "../../AntimodeMenu";
import "./FormatShapePane.scss";
-import { discovery_v1 } from "googleapis";
+import { PresBox } from "../../nodes/PresBox";
+import { DocumentManager } from "../../../util/DocumentManager";
+import FormatShapePane from "./FormatShapePane";
+const higflyout = require("@hig/flyout");
+export const { anchorPoints } = higflyout;
+export const Flyout = higflyout.default;
+const _global = (window /* browser */ || global /* node */) as any;
+
+// import * as fa from '@fortawesome/free-solid-svg-icons';
+// import { library } from "@fortawesome/fontawesome-svg-core";
+// library.add(fa.faPlus, fa.faMinus, fa.faCog);
interface PropertiesViewProps {
width: number;
@@ -39,14 +45,21 @@ interface PropertiesViewProps {
@observer
export class PropertiesView extends React.Component<PropertiesViewProps> {
+ private _widthUndo?: UndoManager.Batch;
@computed get MAX_EMBED_HEIGHT() { return 200; }
@computed get selectedDocumentView() {
if (SelectionManager.SelectedDocuments().length) {
return SelectionManager.SelectedDocuments()[0];
+ } else if (PresBox.Instance?._selectedArray.length) {
+ return DocumentManager.Instance.getDocumentView(PresBox.Instance.rootDoc);
} else { return undefined; }
}
+ @computed get isPres(): boolean {
+ if (this.selectedDoc?.type === DocumentType.PRES) return true;
+ return false;
+ }
@computed get selectedDoc() { return this.selectedDocumentView?.rootDoc; }
@computed get dataDoc() { return this.selectedDocumentView?.dataDoc; }
@@ -58,6 +71,18 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
@observable openLayout: boolean = true;
@observable openAppearance: boolean = true;
@observable openTransform: boolean = true;
+ // @observable selectedUser: string = "";
+ // @observable addButtonPressed: boolean = false;
+
+ //Pres Trails booleans:
+ @observable openPresTransitions: boolean = false;
+ @observable openPresProgressivize: boolean = false;
+ @observable openAddSlide: boolean = false;
+ @observable openSlideOptions: boolean = false;
+
+ @observable inActions: boolean = false;
+ @observable _controlBtn: boolean = false;
+ @observable _lock: boolean = false;
@computed get isInk() { return this.selectedDoc?.type === DocumentType.INK; }
@@ -156,7 +181,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
doc && Object.keys(doc).forEach(key => !(key in ids) && doc[key] !== ComputedField.undefined && (ids[key] = key));
const rows: JSX.Element[] = [];
for (const key of Object.keys(ids).slice().sort()) {
- if ((key[0] === key[0].toUpperCase() && key.substring(0, 3) !== "ACL")
+ if ((key[0] === key[0].toUpperCase() && key.substring(0, 3) !== "ACL" && key !== "UseCors")
|| key[0] === "#" || key === "author" ||
key === "creationDate" || key.indexOf("lastModified") !== -1) {
@@ -222,12 +247,23 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
return false;
}
+ @observable transform: Transform = Transform.Identity();
+ getTransform = () => { return this.transform; }
+ propertiesDocViewRef = (ref: HTMLDivElement) => {
+ const observer = new _global.ResizeObserver(action((entries: any) => {
+ const cliRect = ref.getBoundingClientRect();
+ this.transform = new Transform(-cliRect.x, -cliRect.y, 1);
+ }));
+ ref && observer.observe(ref);
+ }
+
+ previewBackground = () => "lightgrey";
@computed get layoutPreview() {
if (this.selectedDoc) {
const layoutDoc = Doc.Layout(this.selectedDoc);
const panelHeight = StrCast(Doc.LayoutField(layoutDoc)).includes("FormattedTextBox") ? this.rtfHeight : this.docHeight;
const panelWidth = StrCast(Doc.LayoutField(layoutDoc)).includes("FormattedTextBox") ? this.rtfWidth : this.docWidth;
- return <div style={{ display: "inline-block", height: panelHeight() }} key={this.selectedDoc[Id]}>
+ return <div ref={this.propertiesDocViewRef} style={{ pointerEvents: "none", display: "inline-block", height: panelHeight() }} key={this.selectedDoc[Id]}>
<ContentFittingDocumentView
Document={layoutDoc}
DataDoc={this.dataDoc}
@@ -235,8 +271,8 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
renderDepth={this.props.renderDepth + 1}
rootSelected={returnFalse}
treeViewDoc={undefined}
- backgroundColor={() => "lightgrey"}
- fitToBox={false}
+ backgroundColor={this.previewBackground}
+ fitToBox={true}
FreezeDimensions={true}
NativeWidth={layoutDoc.type ===
StrCast(Doc.LayoutField(layoutDoc)).includes("FormattedTextBox") ? this.rtfWidth : returnZero}
@@ -245,7 +281,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
PanelWidth={panelWidth}
PanelHeight={panelHeight}
focus={returnFalse}
- ScreenToLocalTransform={this.props.ScreenToLocalTransform}
+ ScreenToLocalTransform={this.getTransform}
docFilters={returnEmptyFilter}
ContainingCollectionDoc={undefined}
ContainingCollectionView={undefined}
@@ -259,6 +295,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
bringToFront={returnFalse}
ContentScaling={returnOne}
dontRegisterView={true}
+ dropAction={undefined}
/>
</div>;
} else {
@@ -266,13 +303,20 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
}
}
+ /**
+ * Handles the changing of a user's permissions from the permissions panel.
+ */
@undoBatch
changePermissions = (e: any, user: string) => {
SharingManager.Instance.shareFromPropertiesSidebar(user, e.currentTarget.value as SharingPermissions, this.selectedDoc!);
}
- getPermissionsSelect(user: string) {
+ /**
+ * @returns the options for the permissions dropdown.
+ */
+ getPermissionsSelect(user: string, permission: string) {
return <select className="permissions-select"
+ defaultValue={permission}
onChange={e => this.changePermissions(e, user)}>
{Object.values(SharingPermissions).map(permission => {
return (
@@ -283,16 +327,22 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
</select>;
}
+ /**
+ * @returns the notification icon. On clicking, it should notify someone of a document been shared with them.
+ */
@computed get notifyIcon() {
- return <Tooltip title={<><div className="dash-tooltip">Notify with message</div></>}>
+ return <Tooltip title={<div className="dash-tooltip">Notify with message</div>}>
<div className="notify-button">
<FontAwesomeIcon className="notify-button-icon" icon="bell" color="white" size="sm" />
</div>
</Tooltip>;
}
+ /**
+ * ... next to the owner that opens the main SharingManager interface on click.
+ */
@computed get expansionIcon() {
- return <Tooltip title={<><div className="dash-tooltip">{"Show more permissions"}</div></>}>
+ return <Tooltip title={<div className="dash-tooltip">{"Show more permissions"}</div>}>
<div className="expansion-button" onPointerDown={() => {
if (this.selectedDocumentView) {
SharingManager.Instance.open(this.selectedDocumentView);
@@ -303,17 +353,26 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
</Tooltip>;
}
- sharingItem(name: string, effectiveAcl: symbol, permission?: string) {
- return <div className="propertiesView-sharingTable-item">
+ /**
+ * @returns a row of the permissions panel
+ */
+ sharingItem(name: string, effectiveAcl: symbol, permission: string) {
+ return <div className="propertiesView-sharingTable-item" key={name + permission}
+ // style={{ backgroundColor: this.selectedUser === name ? "#bcecfc" : "" }}
+ // onPointerDown={action(() => this.selectedUser = this.selectedUser === name ? "" : name)}
+ >
<div className="propertiesView-sharingTable-item-name" style={{ width: name !== "Me" ? "85px" : "80px" }}> {name} </div>
{/* {name !== "Me" ? this.notifyIcon : null} */}
<div className="propertiesView-sharingTable-item-permission">
- {effectiveAcl === AclAdmin && permission !== "Owner" ? this.getPermissionsSelect(name) : permission}
+ {effectiveAcl === AclAdmin && permission !== "Owner" ? this.getPermissionsSelect(name, permission) : permission}
{permission === "Owner" ? this.expansionIcon : null}
</div>
</div>;
}
+ /**
+ * @returns the sharing and permissiosn panel.
+ */
@computed get sharingTable() {
const AclMap = new Map<symbol, string>([
[AclPrivate, SharingPermissions.None],
@@ -326,13 +385,24 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
const effectiveAcl = GetEffectiveAcl(this.selectedDoc!);
const tableEntries = [];
+ // DocCastAsync(Doc.UserDoc().sidebarUsersDisplayed).then(sidebarUsersDisplayed => {
if (this.selectedDoc![AclSym]) {
for (const [key, value] of Object.entries(this.selectedDoc![AclSym])) {
const name = key.substring(4).replace("_", ".");
- if (name !== Doc.CurrentUserEmail && name !== this.selectedDoc!.author) tableEntries.push(this.sharingItem(name, effectiveAcl, AclMap.get(value)!));
+ if (name !== Doc.CurrentUserEmail && name !== this.selectedDoc!.author/* && sidebarUsersDisplayed![name] !== false*/) {
+ tableEntries.push(this.sharingItem(name, effectiveAcl, AclMap.get(value)!));
+ }
}
}
+ // if (Doc.UserDoc().sidebarUsersDisplayed) {
+ // for (const [name, value] of Object.entries(sidebarUsersDisplayed!)) {
+ // if (value === true && !this.selectedDoc![`ACL-${name.substring(8).replace(".", "_")}`]) tableEntries.push(this.sharingItem(name.substring(8), effectiveAcl, SharingPermissions.None));
+ // }
+ // }
+ // })
+
+ // shifts the current user and the owner to the top of the doc.
tableEntries.unshift(this.sharingItem("Me", effectiveAcl, Doc.CurrentUserEmail === this.selectedDoc!.author ? "Owner" : StrCast(this.selectedDoc![`ACL-${Doc.CurrentUserEmail.replace(".", "_")}`])));
if (Doc.CurrentUserEmail !== this.selectedDoc!.author) tableEntries.unshift(this.sharingItem(StrCast(this.selectedDoc!.author), effectiveAcl, "Owner"));
@@ -349,20 +419,19 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
/>;
}
- @undoBatch
@action
toggleCheckbox = () => {
this.layoutFields = !this.layoutFields;
}
@computed get editableTitle() {
- return <EditableView
+ return <div className="editable-title"><EditableView
key="editableView"
contents={StrCast(this.selectedDoc?.title)}
height={25}
fontSize={14}
GetValue={() => StrCast(this.selectedDoc?.title)}
- SetValue={this.setTitle} />;
+ SetValue={this.setTitle} /> </div>;
}
@undoBatch
@@ -399,15 +468,14 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
var index = 0;
if (doc.type === DocumentType.INK && doc.x && doc.y && doc._width && doc._height && doc.data) {
doc.rotation = Number(doc.rotation) + Number(angle);
- const ink = Cast(doc.data, InkField)?.inkData;
- if (ink) {
-
+ const inks = Cast(doc.data, InkField)?.inkData;
+ if (inks) {
const newPoints: { X: number, Y: number }[] = [];
- for (var i = 0; i < ink.length; i++) {
- const newX = Math.cos(angle) * (ink[i].X - _centerPoints[index].X) - Math.sin(angle) * (ink[i].Y - _centerPoints[index].Y) + _centerPoints[index].X;
- const newY = Math.sin(angle) * (ink[i].X - _centerPoints[index].X) + Math.cos(angle) * (ink[i].Y - _centerPoints[index].Y) + _centerPoints[index].Y;
+ inks.forEach(ink => {
+ const newX = Math.cos(angle) * (ink.X - _centerPoints[index].X) - Math.sin(angle) * (ink.Y - _centerPoints[index].Y) + _centerPoints[index].X;
+ const newY = Math.sin(angle) * (ink.X - _centerPoints[index].X) + Math.cos(angle) * (ink.Y - _centerPoints[index].Y) + _centerPoints[index].Y;
newPoints.push({ X: newX, Y: newY });
- }
+ });
doc.data = new InkField(newPoints);
const xs = newPoints.map(p => p.X);
const ys = newPoints.map(p => p.Y);
@@ -424,23 +492,22 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
}
}
- @observable _controlBtn: boolean = false;
- @observable _lock: boolean = false;
+
@computed
get controlPointsButton() {
return <div className="inking-button">
- <Tooltip title={<><div className="dash-tooltip">{"Edit points"}</div></>}>
- <div className="inking-button-points" onPointerDown={action(() => this._controlBtn = !this._controlBtn)} style={{ backgroundColor: this._controlBtn ? "black" : "" }}>
+ <Tooltip title={<div className="dash-tooltip">{"Edit points"}</div>}>
+ <div className="inking-button-points" onPointerDown={action(() => FormatShapePane.Instance._controlBtn = !FormatShapePane.Instance._controlBtn)} style={{ backgroundColor: FormatShapePane.Instance._controlBtn ? "black" : "" }}>
<FontAwesomeIcon icon="bezier-curve" color="white" size="lg" />
</div>
</Tooltip>
- <Tooltip title={<><div className="dash-tooltip">{this._lock ? "Unlock points" : "Lock points"}</div></>}>
- <div className="inking-button-lock" onPointerDown={action(() => this._lock = !this._lock)} >
- <FontAwesomeIcon icon={this._lock ? "unlock" : "lock"} color="white" size="lg" />
+ <Tooltip title={<div className="dash-tooltip">{FormatShapePane.Instance._lock ? "Unlock ratio" : "Lock ratio"}</div>}>
+ <div className="inking-button-lock" onPointerDown={action(() => FormatShapePane.Instance._lock = !FormatShapePane.Instance._lock)} >
+ <FontAwesomeIcon icon={FormatShapePane.Instance._lock ? "lock" : "unlock"} color="white" size="lg" />
</div>
</Tooltip>
- <Tooltip title={<><div className="dash-tooltip">{"Rotate 90˚"}</div></>}>
+ <Tooltip title={<div className="dash-tooltip">{"Rotate 90˚"}</div>}>
<div className="inking-button-rotate" onPointerDown={action(() => this.rotate(Math.PI / 2))}>
<FontAwesomeIcon icon="undo" color="white" size="lg" />
</div>
@@ -492,12 +559,10 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
const oldX = NumCast(this.selectedDoc?.x);
const oldY = NumCast(this.selectedDoc?.y);
this.selectedDoc && (this.selectedDoc._width = oldWidth + (dirs === "up" ? 10 : - 10));
- this._lock && this.selectedDoc && (this.selectedDoc._height = (NumCast(this.selectedDoc?._width) / oldWidth * NumCast(this.selectedDoc?._height)));
+ FormatShapePane.Instance._lock && this.selectedDoc && (this.selectedDoc._height = (NumCast(this.selectedDoc?._width) / oldWidth * NumCast(this.selectedDoc?._height)));
const doc = this.selectedDoc;
if (doc?.type === DocumentType.INK && doc.x && doc.y && doc._height && doc._width) {
- console.log(doc.x, doc.y, doc._height, doc._width);
const ink = Cast(doc.data, InkField)?.inkData;
- console.log(ink);
if (ink) {
const newPoints: { X: number, Y: number }[] = [];
for (var j = 0; j < ink.length; j++) {
@@ -516,12 +581,10 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
const oX = NumCast(this.selectedDoc?.x);
const oY = NumCast(this.selectedDoc?.y);
this.selectedDoc && (this.selectedDoc._height = oHeight + (dirs === "up" ? 10 : - 10));
- this._lock && this.selectedDoc && (this.selectedDoc._width = (NumCast(this.selectedDoc?._height) / oHeight * NumCast(this.selectedDoc?._width)));
+ FormatShapePane.Instance._lock && this.selectedDoc && (this.selectedDoc._width = (NumCast(this.selectedDoc?._height) / oHeight * NumCast(this.selectedDoc?._width)));
const docu = this.selectedDoc;
if (docu?.type === DocumentType.INK && docu.x && docu.y && docu._height && docu._width) {
- console.log(docu.x, docu.y, docu._height, docu._width);
const ink = Cast(docu.data, InkField)?.inkData;
- console.log(ink);
if (ink) {
const newPoints: { X: number, Y: number }[] = [];
for (var j = 0; j < ink.length; j++) {
@@ -539,7 +602,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
getField(key: string) {
//if (this.selectedDoc) {
- return Field.toString(this.selectedDoc![key] as Field);
+ return Field.toString(this.selectedDoc?.[key] as Field);
// } else {
// return undefined as Opt<string>;
// }
@@ -556,17 +619,18 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
set shapeWid(value) {
const oldWidth = NumCast(this.selectedDoc?._width);
this.selectedDoc && (this.selectedDoc._width = Number(value));
- this._lock && this.selectedDoc && (this.selectedDoc._height = (NumCast(this.selectedDoc?._width) * NumCast(this.selectedDoc?._height)) / oldWidth);
+ FormatShapePane.Instance._lock && this.selectedDoc && (this.selectedDoc._height = (NumCast(this.selectedDoc?._width) * NumCast(this.selectedDoc?._height)) / oldWidth);
}
set shapeHgt(value) {
const oldHeight = NumCast(this.selectedDoc?._height);
this.selectedDoc && (this.selectedDoc._height = Number(value));
- this._lock && this.selectedDoc && (this.selectedDoc._width = (NumCast(this.selectedDoc?._height) * NumCast(this.selectedDoc?._width)) / oldHeight);
+ FormatShapePane.Instance._lock && this.selectedDoc && (this.selectedDoc._width = (NumCast(this.selectedDoc?._height) * NumCast(this.selectedDoc?._width)) / oldHeight);
}
- @computed get hgtInput() { return this.inputBoxDuo("hgt", this.shapeHgt, (val: string) => this.shapeHgt = val, "H:", "wid", this.shapeWid, (val: string) => this.shapeWid = val, "W:"); }
- @computed get XpsInput() { return this.inputBoxDuo("Xps", this.shapeXps, (val: string) => this.shapeXps = val, "X:", "Yps", this.shapeYps, (val: string) => this.shapeYps = val, "Y:"); }
- @computed get rotInput() { return this.inputBoxDuo("rot", this.shapeRot, (val: string) => { this.rotate(Number(val) - Number(this.shapeRot)); this.shapeRot = val; return true; }, "∠:", "rot", this.shapeRot, (val: string) => this.shapeRot = val, ""); }
+ @computed get hgtInput() { return this.inputBoxDuo("hgt", this.shapeHgt, (val: string) => { if (!isNaN(Number(val))) { this.shapeHgt = val; } return true; }, "H:", "wid", this.shapeWid, (val: string) => { if (!isNaN(Number(val))) { this.shapeWid = val; } return true; }, "W:"); }
+ @computed get XpsInput() { return this.inputBoxDuo("Xps", this.shapeXps, (val: string) => { if (val !== "0" && !isNaN(Number(val))) { this.shapeXps = val; } return true; }, "X:", "Yps", this.shapeYps, (val: string) => { if (val !== "0" && !isNaN(Number(val))) { this.shapeYps = val; } return true; }, "Y:"); }
+ @computed get rotInput() { return this.inputBoxDuo("rot", this.shapeRot, (val: string) => { if (!isNaN(Number(val))) { this.rotate(Number(val) - Number(this.shapeRot)); this.shapeRot = val; } return true; }, "∠:", "rot", this.shapeRot, (val: string) => { if (!isNaN(Number(val))) { this.rotate(Number(val) - Number(this.shapeRot)); this.shapeRot = val; } return true; }, ""); }
+
@observable private _fillBtn = false;
@observable private _lineBtn = false;
@@ -580,14 +644,18 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
set colorFil(value) { value && (this._lastFill = value); this.selectedDoc && (this.selectedDoc.fillColor = value ? value : undefined); }
set colorStk(value) { value && (this._lastLine = value); this.selectedDoc && (this.selectedDoc.color = value ? value : undefined); }
- colorButton(value: string, setter: () => {}) {
- return <div className="color-button" key="color" onPointerDown={undoBatch(action(e => setter()))}>
- <div className="color-button-preview" style={{
- backgroundColor: value ?? "121212", width: 15, height: 15,
- display: value === "" || value === "transparent" ? "none" : ""
- }} />
- {value === "" || value === "transparent" ? <p style={{ fontSize: 25, color: "red", marginTop: -14, position: "fixed" }}>☒</p> : ""}
- </div>;
+ colorButton(value: string, type: string, setter: () => {}) {
+ return <Flyout anchorPoint={anchorPoints.LEFT_TOP}
+ content={type === "fill" ? this.fillPicker : this.linePicker}>
+ <div className="color-button" key="color" onPointerDown={undoBatch(action(e => setter()))}>
+ <div className="color-button-preview" style={{
+ backgroundColor: value ?? "121212", width: 15, height: 15,
+ display: value === "" || value === "transparent" ? "none" : ""
+ }} />
+ {value === "" || value === "transparent" ? <p style={{ fontSize: 25, color: "red", marginTop: -14, position: "fixed" }}>☒</p> : ""}
+ </div>
+ </Flyout>;
+
}
@undoBatch
@@ -613,8 +681,8 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
color={type === "stk" ? this.colorStk : this.colorFil} />;
}
- @computed get fillButton() { return this.colorButton(this.colorFil, () => { this._fillBtn = !this._fillBtn; this._lineBtn = false; return true; }); }
- @computed get lineButton() { return this.colorButton(this.colorStk, () => { this._lineBtn = !this._lineBtn; this._fillBtn = false; return true; }); }
+ @computed get fillButton() { return this.colorButton(this.colorFil, "fill", () => { this._fillBtn = !this._fillBtn; this._lineBtn = false; return true; }); }
+ @computed get lineButton() { return this.colorButton(this.colorStk, "line", () => { this._lineBtn = !this._lineBtn; this._fillBtn = false; return true; }); }
@computed get fillPicker() { return this.colorPicker((color: string) => this.colorFil = color, "fil"); }
@computed get linePicker() { return this.colorPicker((color: string) => this.colorStk = color, "stk"); }
@@ -631,8 +699,8 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
<div className="stroke-button">{this.lineButton}</div>
</div>
</div>
- {this._fillBtn ? this.fillPicker : ""}
- {this._lineBtn ? this.linePicker : ""}
+ {/* {this._fillBtn ? this.fillPicker : ""}
+ {this._lineBtn ? this.linePicker : ""} */}
</div>;
}
@@ -683,7 +751,10 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
</div>
<input className="width-range" type="range"
defaultValue={Number(this.widthStk)} min={1} max={100}
- onChange={undoBatch(action((e) => this.widthStk = e.target.value))} />
+ onChange={(action((e) => this.widthStk = e.target.value))}
+ onMouseDown={(e) => { this._widthUndo = UndoManager.StartBatch("width undo"); }}
+ onMouseUp={(e) => { this._widthUndo?.end(); this._widthUndo = undefined; }}
+ />
</div>
<div className="arrows">
@@ -701,7 +772,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
</div>
</div>
<div className="dashed">
- <div className="dashed-title">Dash:</div>
+ <div className="dashed-title">Dashed Line:</div>
<input key="markHead" className="dashed-input"
type="checkbox" checked={this.dashdStk === "2"}
onChange={this.changeDash} />
@@ -730,121 +801,250 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
</div>;
}
- render() {
+ /**
+ * Handles adding and removing members from the sharing panel
+ */
+ // handleUserChange = (selectedUser: string, add: boolean) => {
+ // if (!Doc.UserDoc().sidebarUsersDisplayed) Doc.UserDoc().sidebarUsersDisplayed = new Doc;
+ // DocCastAsync(Doc.UserDoc().sidebarUsersDisplayed).then(sidebarUsersDisplayed => {
+ // sidebarUsersDisplayed![`display-${selectedUser}`] = add;
+ // !add && runInAction(() => this.selectedUser = "");
+ // });
+ // }
- if (!this.selectedDoc) {
+ render() {
+ if (!this.selectedDoc && !this.isPres) {
return <div className="propertiesView" style={{ width: this.props.width }}>
<div className="propertiesView-title" style={{ width: this.props.width }}>
No Document Selected
- <div className="propertiesView-title-icon" onPointerDown={this.props.onDown}>
- <FontAwesomeIcon icon="times" color="black" size="xs" />
- </div>
</div>
</div>;
- }
-
- const novice = Doc.UserDoc().noviceMode;
- return <div className="propertiesView" style={{ width: this.props.width }} >
- <div className="propertiesView-title" style={{ width: this.props.width }}>
- Properties
- <div className="propertiesView-title-icon" onPointerDown={this.props.onDown}>
- <FontAwesomeIcon icon="times" color="black" size="sm" />
- </div>
- </div>
- <div className="propertiesView-name">
- {this.editableTitle}
- </div>
- <div className="propertiesView-settings">
- <div className="propertiesView-settings-title"
- onPointerDown={() => runInAction(() => { this.openActions = !this.openActions; })}
- style={{ backgroundColor: this.openActions ? "black" : "" }}>
- Actions
- <div className="propertiesView-settings-title-icon">
- <FontAwesomeIcon icon={this.openActions ? "caret-down" : "caret-right"} size="lg" color="white" />
+ } else {
+ const novice = Doc.UserDoc().noviceMode;
+
+ if (this.selectedDoc && !this.isPres) {
+ return <div className="propertiesView" style={{
+ width: this.props.width,
+ // overflowY: this.inActions ? "visible" : "scroll"
+ }} >
+ <div className="propertiesView-title" style={{ width: this.props.width }}>
+ Properties
+ {/* <div className="propertiesView-title-icon" onPointerDown={this.props.onDown}>
+ <FontAwesomeIcon icon="times" color="black" size="sm" />
+ </div> */}
</div>
- </div>
- {!this.openActions ? (null) :
- <div className="propertiesView-settings-content">
- <PropertiesButtons />
- </div>}
- </div>
- <div className="propertiesView-sharing">
- <div className="propertiesView-sharing-title"
- onPointerDown={() => runInAction(() => { this.openSharing = !this.openSharing; })}
- style={{ backgroundColor: this.openSharing ? "black" : "" }}>
- Sharing {"&"} Permissions
- <div className="propertiesView-sharing-title-icon">
- <FontAwesomeIcon icon={this.openSharing ? "caret-down" : "caret-right"} size="lg" color="white" />
+ <div className="propertiesView-name">
+ {this.editableTitle}
</div>
- </div>
- {!this.openSharing ? (null) :
- <div className="propertiesView-sharing-content">
- {this.sharingTable}
- </div>}
- </div>
-
- {!this.isInk ? (null) :
- <div className="propertiesView-appearance">
- <div className="propertiesView-appearance-title"
- onPointerDown={() => runInAction(() => { this.openAppearance = !this.openAppearance; })}
- style={{ backgroundColor: this.openAppearance ? "black" : "" }}>
- Appearance
- <div className="propertiesView-appearance-title-icon">
- <FontAwesomeIcon icon={this.openAppearance ? "caret-down" : "caret-right"} size="lg" color="white" />
+ <div className="propertiesView-settings" onPointerEnter={() => runInAction(() => { this.inActions = true; })}
+ onPointerLeave={action(() => this.inActions = false)}>
+ <div className="propertiesView-settings-title"
+ onPointerDown={() => runInAction(() => { this.openActions = !this.openActions; })}
+ style={{ backgroundColor: this.openActions ? "black" : "" }}>
+ Actions
+ <div className="propertiesView-settings-title-icon">
+ <FontAwesomeIcon icon={this.openActions ? "caret-down" : "caret-right"} size="lg" color="white" />
+ </div>
+ </div>
+ {!this.openActions ? (null) :
+ <div className="propertiesView-settings-content">
+ <PropertiesButtons />
+ </div>}
+ </div>
+ <div className="propertiesView-sharing">
+ <div className="propertiesView-sharing-title"
+ onPointerDown={() => runInAction(() => { this.openSharing = !this.openSharing; })}
+ style={{ backgroundColor: this.openSharing ? "black" : "" }}>
+ Sharing {"&"} Permissions
+ <div className="propertiesView-sharing-title-icon">
+ <FontAwesomeIcon icon={this.openSharing ? "caret-down" : "caret-right"} size="lg" color="white" />
+ </div>
</div>
+ {!this.openSharing ? (null) :
+ <div className="propertiesView-sharing-content">
+ {this.sharingTable}
+ {/* <div className="change-buttons">
+ <button
+ onPointerDown={action(() => this.addButtonPressed = !this.addButtonPressed)}
+ >
+ <FontAwesomeIcon icon={fa.faPlus} size={"sm"} style={{ marginTop: -3, marginLeft: -3 }} />
+ </button>
+ <button
+ id="sharingProperties-removeUser"
+ onPointerDown={() => this.handleUserChange(this.selectedUser, false)}
+ style={{ backgroundColor: this.selectedUser ? "#121721" : "#777777" }}
+ ><FontAwesomeIcon icon={fa.faMinus} size={"sm"} style={{ marginTop: -3, marginLeft: -3 }} /></button>
+ <button onClick={() => SharingManager.Instance.open(this.selectedDocumentView!)}><FontAwesomeIcon icon={fa.faCog} size={"sm"} style={{ marginTop: -3, marginLeft: -3 }} /></button>
+ {this.addButtonPressed ?
+ // <input type="text" onKeyDown={this.handleKeyPress} /> :
+ <select onChange={e => this.handleUserChange(e.target.value, true)}>
+ <option selected disabled hidden>
+ Add users
+ </option>
+ {SharingManager.Instance.users.map(user =>
+ (<option value={user.user.email}>
+ {user.user.email}
+ </option>)
+ )}
+ {GroupManager.Instance.getAllGroups().map(group =>
+ (<option value={StrCast(group.groupName)}>
+ {StrCast(group.groupName)}
+ </option>))}
+ </select> :
+ null}
+ </div> */}
+ </div>}
</div>
- {!this.openAppearance ? (null) :
- <div className="propertiesView-appearance-content">
- {this.appearanceEditor}
+
+ {!this.isInk ? (null) :
+ <div className="propertiesView-appearance">
+ <div className="propertiesView-appearance-title"
+ onPointerDown={() => runInAction(() => { this.openAppearance = !this.openAppearance; })}
+ style={{ backgroundColor: this.openAppearance ? "black" : "" }}>
+ Appearance
+ <div className="propertiesView-appearance-title-icon">
+ <FontAwesomeIcon icon={this.openAppearance ? "caret-down" : "caret-right"} size="lg" color="white" />
+ </div>
+ </div>
+ {!this.openAppearance ? (null) :
+ <div className="propertiesView-appearance-content">
+ {this.appearanceEditor}
+ </div>}
</div>}
- </div>}
-
- {this.isInk ? <div className="propertiesView-transform">
- <div className="propertiesView-transform-title"
- onPointerDown={() => runInAction(() => { this.openTransform = !this.openTransform; })}
- style={{ backgroundColor: this.openTransform ? "black" : "" }}>
- Transform
- <div className="propertiesView-transform-title-icon">
- <FontAwesomeIcon icon={this.openTransform ? "caret-down" : "caret-right"} size="lg" color="white" />
+
+ {this.isInk ? <div className="propertiesView-transform">
+ <div className="propertiesView-transform-title"
+ onPointerDown={() => runInAction(() => { this.openTransform = !this.openTransform; })}
+ style={{ backgroundColor: this.openTransform ? "black" : "" }}>
+ Transform
+ <div className="propertiesView-transform-title-icon">
+ <FontAwesomeIcon icon={this.openTransform ? "caret-down" : "caret-right"} size="lg" color="white" />
+ </div>
+ </div>
+ {this.openTransform ? <div className="propertiesView-transform-content">
+ {this.transformEditor}
+ </div> : null}
+ </div> : null}
+
+ <div className="propertiesView-fields">
+ <div className="propertiesView-fields-title"
+ onPointerDown={() => runInAction(() => { this.openFields = !this.openFields; })}
+ style={{ backgroundColor: this.openFields ? "black" : "" }}>
+ <div className="propertiesView-fields-title-name">
+ Fields {"&"} Tags
+ <div className="propertiesView-fields-title-icon">
+ <FontAwesomeIcon icon={this.openFields ? "caret-down" : "caret-right"} size="lg" color="white" />
+ </div>
+ </div>
+ </div>
+ {!novice && this.openFields ? <div className="propertiesView-fields-checkbox">
+ {this.fieldsCheckbox}
+ <div className="propertiesView-fields-checkbox-text">Layout</div>
+ </div> : null}
+ {!this.openFields ? (null) :
+ <div className="propertiesView-fields-content">
+ {novice ? this.noviceFields : this.expandedField}
+ </div>}
</div>
- </div>
- {this.openTransform ? <div className="propertiesView-transform-content">
- {this.transformEditor}
- </div> : null}
- </div> : null}
-
- <div className="propertiesView-fields">
- <div className="propertiesView-fields-title"
- onPointerDown={() => runInAction(() => { this.openFields = !this.openFields; })}
- style={{ backgroundColor: this.openFields ? "black" : "" }}>
- <div className="propertiesView-fields-title-name">
- Fields {"&"} Tags
- <div className="propertiesView-fields-title-icon">
- <FontAwesomeIcon icon={this.openFields ? "caret-down" : "caret-right"} size="lg" color="white" />
+ <div className="propertiesView-layout">
+ <div className="propertiesView-layout-title"
+ onPointerDown={() => runInAction(() => { this.openLayout = !this.openLayout; })}
+ style={{ backgroundColor: this.openLayout ? "black" : "" }}>
+ Layout
+ <div className="propertiesView-layout-title-icon" onPointerDown={() => runInAction(() => { this.openLayout = !this.openLayout; })}>
+ <FontAwesomeIcon icon={this.openLayout ? "caret-down" : "caret-right"} size="lg" color="white" />
+ </div>
</div>
+ {this.openLayout ? <div className="propertiesView-layout-content" >{this.layoutPreview}</div> : null}
</div>
- </div>
- {!novice && this.openFields ? <div className="propertiesView-fields-checkbox">
- {this.fieldsCheckbox}
- <div className="propertiesView-fields-checkbox-text">Layout</div>
- </div> : null}
- {!this.openFields ? (null) :
- <div className="propertiesView-fields-content">
- {novice ? this.noviceFields : this.expandedField}
+ </div>;
+ }
+ if (this.isPres) {
+ const selectedItem: boolean = PresBox.Instance?._selectedArray.length > 0;
+ return <div className="propertiesView" style={{ width: this.props.width }} >
+ <div className="propertiesView-title" style={{ width: this.props.width }}>
+ Presentation
+ <div className="propertiesView-title-icon" onPointerDown={this.props.onDown}>
+ <FontAwesomeIcon icon="times" color="black" size="sm" />
+ </div>
+ </div>
+ <div className="propertiesView-name">
+ {this.editableTitle}
+ <div className="propertiesView-presSelected">
+ {PresBox.Instance?._selectedArray.length} selected
+ <div className="propertiesView-selectedList">
+ {PresBox.Instance?.listOfSelected}
+ </div>
+ </div>
+ </div>
+ {!selectedItem ? (null) : <div className="propertiesView-presTrails">
+ <div className="propertiesView-presTrails-title"
+ onPointerDown={() => runInAction(() => { this.openPresTransitions = !this.openPresTransitions; })}
+ style={{ backgroundColor: this.openPresTransitions ? "black" : "" }}>
+ &nbsp; <FontAwesomeIcon icon={"rocket"} /> &nbsp; Transitions
+ <div className="propertiesView-presTrails-title-icon">
+ <FontAwesomeIcon icon={this.openPresTransitions ? "caret-down" : "caret-right"} size="lg" color="white" />
+ </div>
+ </div>
+ {this.openPresTransitions ? <div className="propertiesView-presTrails-content">
+ {PresBox.Instance.transitionDropdown}
+ </div> : null}
</div>}
- </div>
- <div className="propertiesView-layout">
- <div className="propertiesView-layout-title"
- onPointerDown={() => runInAction(() => { this.openLayout = !this.openLayout; })}
- style={{ backgroundColor: this.openLayout ? "black" : "" }}>
- Layout
- <div className="propertiesView-layout-title-icon" onPointerDown={() => runInAction(() => { this.openLayout = !this.openLayout; })}>
- <FontAwesomeIcon icon={this.openLayout ? "caret-down" : "caret-right"} size="lg" color="white" />
+ {!selectedItem ? (null) : <div className="propertiesView-presTrails">
+ <div className="propertiesView-presTrails-title"
+ onPointerDown={() => runInAction(() => { this.openPresProgressivize = !this.openPresProgressivize; })}
+ style={{ backgroundColor: this.openPresProgressivize ? "black" : "" }}>
+ &nbsp; <FontAwesomeIcon icon={"tasks"} /> &nbsp; Progressivize
+ <div className="propertiesView-presTrails-title-icon">
+ <FontAwesomeIcon icon={this.openPresProgressivize ? "caret-down" : "caret-right"} size="lg" color="white" />
+ </div>
+ </div>
+ {this.openPresProgressivize ? <div className="propertiesView-presTrails-content">
+ {PresBox.Instance.progressivizeDropdown}
+ </div> : null}
+ </div>}
+ {!selectedItem ? (null) : <div className="propertiesView-presTrails">
+ <div className="propertiesView-presTrails-title"
+ onPointerDown={() => runInAction(() => { this.openSlideOptions = !this.openSlideOptions; })}
+ style={{ backgroundColor: this.openSlideOptions ? "black" : "" }}>
+ &nbsp; <FontAwesomeIcon icon={"cog"} /> &nbsp; {PresBox.Instance.stringType} options
+ <div className="propertiesView-presTrails-title-icon">
+ <FontAwesomeIcon icon={this.openSlideOptions ? "caret-down" : "caret-right"} size="lg" color="white" />
+ </div>
+ </div>
+ {this.openSlideOptions ? <div className="propertiesView-presTrails-content">
+ {PresBox.Instance.optionsDropdown}
+ </div> : null}
+ </div>}
+ <div className="propertiesView-presTrails">
+ <div className="propertiesView-presTrails-title"
+ onPointerDown={() => runInAction(() => { this.openAddSlide = !this.openAddSlide; })}
+ style={{ backgroundColor: this.openAddSlide ? "black" : "" }}>
+ &nbsp; <FontAwesomeIcon icon={"plus"} /> &nbsp; Add new slide
+ <div className="propertiesView-presTrails-title-icon">
+ <FontAwesomeIcon icon={this.openAddSlide ? "caret-down" : "caret-right"} size="lg" color="white" />
+ </div>
+ </div>
+ {this.openAddSlide ? <div className="propertiesView-presTrails-content">
+ {PresBox.Instance.newDocumentDropdown}
+ </div> : null}
</div>
- </div>
- {this.openLayout ? <div className="propertiesView-layout-content">{this.layoutPreview}</div> : null}
- </div>
- </div>;
+ <div className="propertiesView-sharing">
+ <div className="propertiesView-sharing-title"
+ onPointerDown={() => runInAction(() => { this.openSharing = !this.openSharing; })}
+ style={{ backgroundColor: this.openSharing ? "black" : "" }}>
+ Sharing {"&"} Permissions
+ <div className="propertiesView-sharing-title-icon">
+ <FontAwesomeIcon icon={this.openSharing ? "caret-down" : "caret-right"} size="lg" color="white" />
+ </div>
+ </div>
+ {this.openSharing ? <div className="propertiesView-sharing-content">
+ {this.sharingTable}
+ </div> : null}
+ </div>
+ </div>;
+ }
+ }
}
-} \ No newline at end of file
+} \ No newline at end of file