aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/PropertiesView.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/views/PropertiesView.tsx')
-rw-r--r--src/client/views/PropertiesView.tsx125
1 files changed, 66 insertions, 59 deletions
diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx
index c2c0d553b..fad2f5284 100644
--- a/src/client/views/PropertiesView.tsx
+++ b/src/client/views/PropertiesView.tsx
@@ -1,16 +1,17 @@
import React = require("react");
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { Checkbox, Tooltip } from "@material-ui/core";
+import { intersection } from "lodash";
import { action, computed, observable } from "mobx";
import { observer } from "mobx-react";
import { ColorState, SketchPicker } from "react-color";
-import { AclAddonly, AclAdmin, AclEdit, AclPrivate, AclReadonly, AclSym, DataSym, Doc, Field, HeightSym, WidthSym } from "../../fields/Doc";
+import { AclAddonly, AclAdmin, AclEdit, AclPrivate, AclReadonly, AclSym, AclUnset, DataSym, Doc, Field, HeightSym, WidthSym, Opt } from "../../fields/Doc";
import { Id } from "../../fields/FieldSymbols";
import { InkField } from "../../fields/InkField";
import { ComputedField } from "../../fields/ScriptField";
import { Cast, NumCast, StrCast } from "../../fields/Types";
-import { GetEffectiveAcl, SharingPermissions } from "../../fields/util";
-import { emptyFunction, emptyPath, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnOne, returnZero } from "../../Utils";
+import { GetEffectiveAcl, SharingPermissions, denormalizeEmail } from "../../fields/util";
+import { emptyFunction, emptyPath, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnOne } from "../../Utils";
import { DocumentType } from "../documents/DocumentTypes";
import { DocumentManager } from "../util/DocumentManager";
import { SelectionManager } from "../util/SelectionManager";
@@ -26,7 +27,7 @@ import { PresBox } from "./nodes/PresBox";
import { PropertiesButtons } from "./PropertiesButtons";
import { PropertiesDocContextSelector } from "./PropertiesDocContextSelector";
import "./PropertiesView.scss";
-import { intersection } from "lodash";
+import { CollectionViewType } from "./collections/CollectionView";
const higflyout = require("@hig/flyout");
export const { anchorPoints } = higflyout;
export const Flyout = higflyout.default;
@@ -35,6 +36,7 @@ const _global = (window /* browser */ || global /* node */) as any;
interface PropertiesViewProps {
width: number;
height: number;
+ backgroundColor: (doc: Opt<Doc>, renderDepth: number) => Opt<string>;
}
@observer
@@ -46,7 +48,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
@computed get selectedDoc() { return SelectionManager.SelectedSchemaDoc() || this.selectedDocumentView?.rootDoc; }
@computed get selectedDocumentView() {
if (SelectionManager.SelectedDocuments().length) return SelectionManager.SelectedDocuments()[0];
- if (PresBox.Instance && PresBox.Instance._selectedArray) return DocumentManager.Instance.getDocumentView(PresBox.Instance.rootDoc);
+ if (PresBox.Instance?._selectedArray.size) return DocumentManager.Instance.getDocumentView(PresBox.Instance.rootDoc);
return undefined;
}
@computed get isPres(): boolean {
@@ -60,7 +62,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
@observable openOptions: boolean = true;
@observable openSharing: boolean = true;
@observable openFields: boolean = true;
- @observable openLayout: boolean = true;
+ @observable openLayout: boolean = false;
@observable openContexts: boolean = true;
@observable openAppearance: boolean = true;
@observable openTransform: boolean = true;
@@ -91,9 +93,9 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
docWidth = () => {
if (this.selectedDoc) {
const layoutDoc = this.selectedDoc;
- const aspect = NumCast(layoutDoc._nativeHeight, layoutDoc._fitWidth ? 0 : layoutDoc[HeightSym]()) / NumCast(layoutDoc._nativeWidth, layoutDoc._fitWidth ? 1 : layoutDoc[WidthSym]());
- if (aspect) return Math.min(layoutDoc[WidthSym](), Math.min(this.MAX_EMBED_HEIGHT / aspect, this.props.width - 20));
- return NumCast(layoutDoc._nativeWidth) ? Math.min(layoutDoc[WidthSym](), this.props.width - 20) : this.props.width - 20;
+ const aspect = Doc.NativeAspect(layoutDoc, undefined, !layoutDoc._fitWidth);
+ if (aspect) return Math.min(layoutDoc[WidthSym](), Math.min(this.MAX_EMBED_HEIGHT * aspect, this.props.width - 20));
+ return Doc.NativeWidth(layoutDoc) ? Math.min(layoutDoc[WidthSym](), this.props.width - 20) : this.props.width - 20;
} else {
return 0;
}
@@ -103,17 +105,13 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
docHeight = () => {
if (this.selectedDoc && this.dataDoc) {
const layoutDoc = this.selectedDoc;
- return Math.max(70, Math.min(this.MAX_EMBED_HEIGHT, (() => {
- const aspect = NumCast(layoutDoc._nativeHeight, layoutDoc._fitWidth ? 0 : layoutDoc[HeightSym]()) / NumCast(layoutDoc._nativeWidth, layoutDoc._fitWidth ? 1 : layoutDoc[WidthSym]());
- if (aspect) return this.docWidth() * aspect;
- return layoutDoc._fitWidth ? (!this.dataDoc._nativeHeight ? NumCast(this.props.height) :
- Math.min(this.docWidth() * NumCast(layoutDoc.scrollHeight, NumCast(layoutDoc._nativeHeight)) / NumCast(layoutDoc._nativeWidth,
- NumCast(this.props.height)))) :
- NumCast(layoutDoc._height) ? NumCast(layoutDoc._height) : 50;
- })()));
- } else {
- return 0;
+ return Math.max(70, Math.min(this.MAX_EMBED_HEIGHT,
+ Doc.NativeAspect(layoutDoc, undefined, true) ? this.docWidth() / Doc.NativeAspect(layoutDoc, undefined, true) :
+ layoutDoc._fitWidth ? (!Doc.NativeHeight(this.dataDoc) ? NumCast(this.props.height) :
+ Math.min(this.docWidth() * NumCast(layoutDoc.scrollHeight, Doc.NativeHeight(layoutDoc)) / Doc.NativeWidth(layoutDoc) || NumCast(this.props.height))) :
+ NumCast(layoutDoc._height) || 50));
}
+ return 0;
}
@computed get expandedField() {
@@ -147,7 +145,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
</div>);
}
}
- rows.push(<div className="field" key={"newKeyValue"} style={{ marginTop: "3px" }}>
+ rows.push(<div className="propertiesView-field" key={"newKeyValue"} style={{ marginTop: "3px" }}>
<EditableView
key="editableView"
contents={"add key:value or #tags"}
@@ -175,14 +173,14 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
docs.forEach(doc => docvals.add(doc[key]));
const contents = Array.from(docvals.keys()).length > 1 ? "-multiple" : docs[0][key];
if (key[0] === "#") {
- rows.push(<div className="uneditable-field" key={key}>
+ rows.push(<div className="propertiesView-uneditable-field" key={key}>
<span style={{ fontWeight: "bold", whiteSpace: "nowrap" }}>{key}</span>
&nbsp;
</div>);
} else if (contents !== undefined) {
const value = Field.toString(contents as Field);
if (noviceReqFields.includes(key) || key.indexOf("lastModified") !== -1) {
- rows.push(<div className="uneditable-field" key={key}>
+ rows.push(<div className="propertiesView-uneditable-field" key={key}>
<span style={{ fontWeight: "bold", whiteSpace: "nowrap" }}>{key + ": "}</span>
<div style={{ whiteSpace: "nowrap", overflowX: "hidden" }}>{value}</div>
</div>);
@@ -203,7 +201,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
}
}
}
- rows.push(<div className="field" key={"newKeyValue"} style={{ marginTop: "3px" }}>
+ rows.push(<div className="propertiesView-field" key={"newKeyValue"} style={{ marginTop: "3px" }}>
<EditableView
key="editableView"
contents={"add key:value or #tags"}
@@ -256,7 +254,6 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
return !this.selectedDoc ? (null) : <PropertiesDocContextSelector Document={this.selectedDoc} hideTitle={true} addDocTab={(doc, where) => CollectionDockingView.AddSplit(doc, "right")} />;
}
- previewBackground = () => "lightgrey";
@computed get layoutPreview() {
if (SelectionManager.SelectedDocuments().length > 1) {
return "-- multiple selected --";
@@ -273,7 +270,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
renderDepth={1}
rootSelected={returnFalse}
treeViewDoc={undefined}
- backgroundColor={this.previewBackground}
+ backgroundColor={this.props.backgroundColor}
fitToBox={true}
FreezeDimensions={true}
dontCenter={true}
@@ -284,6 +281,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
focus={returnFalse}
ScreenToLocalTransform={this.getTransform}
docFilters={returnEmptyFilter}
+ docRangeFilters={returnEmptyFilter}
searchFilterDocs={returnEmptyDoclist}
ContainingCollectionDoc={undefined}
ContainingCollectionView={undefined}
@@ -320,13 +318,14 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
getPermissionsSelect(user: string, permission: string) {
const dropdownValues: string[] = Object.values(SharingPermissions);
if (permission === "-multiple-") dropdownValues.unshift(permission);
+ if (user === "Override") dropdownValues.unshift("None");
return <select className="permissions-select"
value={permission}
onChange={e => this.changePermissions(e, user)}>
- {dropdownValues.map(permission => {
+ {dropdownValues.filter(permission => permission !== SharingPermissions.View).map(permission => {
return (
<option key={permission} value={permission}>
- {permission}
+ {permission === SharingPermissions.Add ? "Can Augment" : permission}
</option>);
})}
</select>;
@@ -361,7 +360,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
/**
* @returns a row of the permissions panel
*/
- sharingItem(name: string, admin: boolean, permission: string) {
+ sharingItem(name: string, admin: boolean, permission: string, showExpansionIcon?: boolean) {
return <div className="propertiesView-sharingTable-item" key={name + permission}
// style={{ backgroundColor: this.selectedUser === name ? "#bcecfc" : "" }}
// onPointerDown={action(() => this.selectedUser = this.selectedUser === name ? "" : name)}
@@ -370,7 +369,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
{/* {name !== "Me" ? this.notifyIcon : null} */}
<div className="propertiesView-sharingTable-item-permission">
{admin && permission !== "Owner" ? this.getPermissionsSelect(name, permission) : permission}
- {permission === "Owner" ? this.expansionIcon : null}
+ {permission === "Owner" || showExpansionIcon ? this.expansionIcon : null}
</div>
</div>;
}
@@ -380,6 +379,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
*/
@computed get sharingTable() {
const AclMap = new Map<symbol, string>([
+ [AclUnset, "None"],
[AclPrivate, SharingPermissions.None],
[AclReadonly, SharingPermissions.View],
[AclAddonly, SharingPermissions.Add],
@@ -406,25 +406,20 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
// DocCastAsync(Doc.UserDoc().sidebarUsersDisplayed).then(sidebarUsersDisplayed => {
if (commonKeys.length) {
for (const key of commonKeys) {
- const name = key.substring(4).replace("_", ".");
+ const name = denormalizeEmail(key.substring(4));
const uniform = docs.every(doc => this.layoutDocAcls ? doc?.[AclSym]?.[key] === docs[0]?.[AclSym]?.[key] : doc?.[DataSym]?.[AclSym]?.[key] === docs[0]?.[DataSym]?.[AclSym]?.[key]);
- if (name !== Doc.CurrentUserEmail && name !== target.author && name !== "Public"/* && sidebarUsersDisplayed![name] !== false*/) {
+ if (name !== Doc.CurrentUserEmail && name !== target.author && name !== "Public" && name !== "Override"/* && sidebarUsersDisplayed![name] !== false*/) {
tableEntries.push(this.sharingItem(name, showAdmin, uniform ? AclMap.get(this.layoutDocAcls ? target[AclSym][key] : target[DataSym][AclSym][key])! : "-multiple-"));
}
}
}
- // 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));
- // }
- // }
- // })
-
+ const ownerSame = Doc.CurrentUserEmail !== target.author && docs.filter(doc => doc).every(doc => doc.author === docs[0].author);
// shifts the current user, owner, public to the top of the doc.
+ tableEntries.unshift(this.sharingItem("Override", showAdmin, docs.filter(doc => doc).every(doc => doc["acl-Override"] === docs[0]["acl-Override"]) ? (AclMap.get(target[AclSym]?.["acl-Override"]) || "None") : "-multiple-"));
tableEntries.unshift(this.sharingItem("Public", showAdmin, docs.filter(doc => doc).every(doc => doc["acl-Public"] === docs[0]["acl-Public"]) ? (AclMap.get(target[AclSym]?.["acl-Public"]) || SharingPermissions.None) : "-multiple-"));
- tableEntries.unshift(this.sharingItem("Me", showAdmin, docs.filter(doc => doc).every(doc => doc.author === Doc.CurrentUserEmail) ? "Owner" : effectiveAcls.every(acl => acl === effectiveAcls[0]) ? AclMap.get(effectiveAcls[0])! : "-multiple-"));
- if (Doc.CurrentUserEmail !== target.author && docs.filter(doc => doc).every(doc => doc.author === docs[0].author)) tableEntries.unshift(this.sharingItem(StrCast(target.author), showAdmin, "Owner"));
+ tableEntries.unshift(this.sharingItem("Me", showAdmin, docs.filter(doc => doc).every(doc => doc.author === Doc.CurrentUserEmail) ? "Owner" : effectiveAcls.every(acl => acl === effectiveAcls[0]) ? AclMap.get(effectiveAcls[0])! : "-multiple-", !ownerSame));
+ if (ownerSame) tableEntries.unshift(this.sharingItem(StrCast(target.author), showAdmin, "Owner"));
return <div className="propertiesView-sharingTable">
{tableEntries}
@@ -861,7 +856,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
if (this.selectedDoc && !this.isPres) {
return <div className="propertiesView" style={{
width: this.props.width,
- minWidth: this.props.width
+ minWidth: this.props.width,
//overflowY: this.scrolling ? "scroll" : "visible"
}} >
<div className="propertiesView-title" style={{ width: this.props.width }}>
@@ -896,14 +891,21 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
</div>
{!this.openSharing ? (null) :
<div className="propertiesView-sharing-content">
- {!novice ? (<div className="propertiesView-acls-checkbox">
- <Checkbox
- color="primary"
- onChange={action(() => this.layoutDocAcls = !this.layoutDocAcls)}
- checked={this.layoutDocAcls}
- />;
- <div className="propertiesView-acls-checkbox-text">Layout</div>
- </div>) : (null)}
+ <div className="propertiesView-buttonContainer">
+ {!novice ? (<div className="propertiesView-acls-checkbox">
+ <Checkbox
+ color="primary"
+ onChange={action(() => this.layoutDocAcls = !this.layoutDocAcls)}
+ checked={this.layoutDocAcls}
+ />
+ <div className="propertiesView-acls-checkbox-text">Layout</div>
+ </div>) : (null)}
+ <Tooltip title={<><div className="dash-tooltip">{"Re-distribute sharing settings"}</div></>}>
+ <button onPointerDown={() => SharingManager.Instance.distributeOverCollection(this.selectedDoc!)}>
+ <FontAwesomeIcon icon="redo-alt" color="white" size="1x" />
+ </button>
+ </Tooltip>
+ </div>
{this.sharingTable}
</div>}
</div>
@@ -981,8 +983,11 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
</div>;
}
if (this.isPres) {
- const selectedItem: boolean = PresBox.Instance?._selectedArray.length > 0;
+ const selectedItem: boolean = PresBox.Instance?._selectedArray.size > 0;
const type = PresBox.Instance.activeItem?.type;
+ const viewType = PresBox.Instance.activeItem?._viewType;
+ const pannable: boolean = (type === DocumentType.COL && viewType === CollectionViewType.Freeform) || type === DocumentType.IMG;
+ const scrollable: boolean = type === DocumentType.PDF || type === DocumentType.WEB || type === DocumentType.RTF || viewType === CollectionViewType.Stacking;
return <div className="propertiesView" style={{ width: this.props.width }}>
<div className="propertiesView-title" style={{ width: this.props.width }}>
Presentation
@@ -990,7 +995,9 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
<div className="propertiesView-name">
{this.editableTitle}
<div className="propertiesView-presSelected">
- {PresBox.Instance?._selectedArray.length} selected
+ <div className="propertiesView-selectedCount">
+ {PresBox.Instance?._selectedArray.size} selected
+ </div>
<div className="propertiesView-selectedList">
{PresBox.Instance?.listOfSelected}
</div>
@@ -1009,7 +1016,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
{PresBox.Instance.transitionDropdown}
</div> : null}
</div>}
- {!selectedItem || type === DocumentType.VID || type === DocumentType.AUDIO ? (null) : <div className="propertiesView-presTrails">
+ {/* {!selectedItem || type === DocumentType.VID || type === DocumentType.AUDIO ? (null) : <div className="propertiesView-presTrails">
<div className="propertiesView-presTrails-title"
onPointerDown={action(() => this.openPresProgressivize = !this.openPresProgressivize)}
style={{ backgroundColor: this.openPresProgressivize ? "black" : "" }}>
@@ -1021,21 +1028,21 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
{this.openPresProgressivize ? <div className="propertiesView-presTrails-content">
{PresBox.Instance.progressivizeDropdown}
</div> : null}
- </div>}
- {!selectedItem || (type !== DocumentType.COL && type !== DocumentType.VID && type !== DocumentType.AUDIO) ? (null) : <div className="propertiesView-presTrails">
+ </div>} */}
+ {/* {!selectedItem || (!scrollable && !pannable) ? (null) : <div className="propertiesView-presTrails">
<div className="propertiesView-presTrails-title"
onPointerDown={action(() => { this.openSlideOptions = !this.openSlideOptions; })}
style={{ backgroundColor: this.openSlideOptions ? "black" : "" }}>
- &nbsp; <FontAwesomeIcon icon={"cog"} /> &nbsp; {PresBox.Instance.stringType} options
- <div className="propertiesView-presTrails-title-icon">
+ &nbsp; <FontAwesomeIcon icon={"cog"} /> &nbsp; {scrollable ? "Scroll options" : "Pan 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>} */}
+ {/* <div className="propertiesView-presTrails">
<div className="propertiesView-presTrails-title"
onPointerDown={action(() => { this.openAddSlide = !this.openAddSlide; })}
style={{ backgroundColor: this.openAddSlide ? "black" : "" }}>
@@ -1047,7 +1054,7 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
{this.openAddSlide ? <div className="propertiesView-presTrails-content">
{PresBox.Instance.newDocumentDropdown}
</div> : null}
- </div>
+ </div> */}
</div>;
}
}