aboutsummaryrefslogtreecommitdiff
path: root/src/client/views
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/views')
-rw-r--r--src/client/views/DocComponent.tsx24
-rw-r--r--src/client/views/DocumentDecorations.tsx29
-rw-r--r--src/client/views/GlobalKeyHandler.ts1
-rw-r--r--src/client/views/MainView.tsx4
-rw-r--r--src/client/views/MainViewModal.tsx2
-rw-r--r--src/client/views/RecommendationsBox.scss69
-rw-r--r--src/client/views/RecommendationsBox.tsx201
-rw-r--r--src/client/views/TemplateMenu.tsx9
-rw-r--r--src/client/views/collections/CollectionDockingView.tsx1
-rw-r--r--src/client/views/collections/CollectionMenu.tsx12
-rw-r--r--src/client/views/collections/CollectionSubView.tsx2
-rw-r--r--src/client/views/collections/CollectionTreeView.tsx4
-rw-r--r--src/client/views/collections/CollectionView.tsx39
-rw-r--r--src/client/views/collections/collectionFreeForm/FormatShapePane.scss14
-rw-r--r--src/client/views/collections/collectionFreeForm/MarqueeView.tsx4
-rw-r--r--src/client/views/nodes/DocumentContentsView.tsx3
-rw-r--r--src/client/views/nodes/DocumentView.tsx33
-rw-r--r--src/client/views/nodes/LinkAnchorBox.tsx5
-rw-r--r--src/client/views/nodes/TaskCompletedBox.tsx2
-rw-r--r--src/client/views/nodes/WebBox.tsx11
-rw-r--r--src/client/views/nodes/formattedText/RichTextMenu.tsx16
-rw-r--r--src/client/views/nodes/formattedText/nodes_rts.ts21
-rw-r--r--src/client/views/pdf/PDFMenu.tsx2
-rw-r--r--src/client/views/pdf/PDFViewer.tsx11
24 files changed, 140 insertions, 379 deletions
diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx
index 4c82149e2..804c7a8d4 100644
--- a/src/client/views/DocComponent.tsx
+++ b/src/client/views/DocComponent.tsx
@@ -7,7 +7,7 @@ import { InteractionUtils } from '../util/InteractionUtils';
import { List } from '../../fields/List';
import { DateField } from '../../fields/DateField';
import { ScriptField } from '../../fields/ScriptField';
-import { GetEffectiveAcl, getPlaygroundMode, SharingPermissions } from '../../fields/util';
+import { GetEffectiveAcl, SharingPermissions } from '../../fields/util';
/// DocComponent returns a generic React base class used by views that don't have 'fieldKey' props (e.g.,CollectionFreeFormDocumentView, DocumentView)
@@ -150,25 +150,25 @@ export function ViewBoxAnnotatableComponent<P extends ViewBoxAnnotatableProps, T
const effectiveAcl = GetEffectiveAcl(this.dataDoc);
if (added.length) {
- if (effectiveAcl === AclPrivate || (effectiveAcl === AclReadonly && !getPlaygroundMode())) {
+ if (effectiveAcl === AclPrivate || effectiveAcl === AclReadonly) {
return false;
}
else {
- if (this.props.Document[AclSym]) {
- added.forEach(d => {
- const dataDoc = d[DataSym];
- dataDoc[AclSym] = d[AclSym] = this.props.Document[AclSym];
- for (const [key, value] of Object.entries(this.props.Document[AclSym])) {
- dataDoc[key] = d[key] = this.AclMap.get(value);
- }
- });
- }
+ // if (this.props.Document[AclSym]) {
+ // added.forEach(d => {
+ // const dataDoc = d[DataSym];
+ // dataDoc[AclSym] = d[AclSym] = this.props.Document[AclSym];
+ // for (const [key, value] of Object.entries(this.props.Document[AclSym])) {
+ // dataDoc[key] = d[key] = this.AclMap.get(value);
+ // }
+ // });
+ // }
if (effectiveAcl === AclAddonly) {
added.map(doc => Doc.AddDocToList(targetDataDoc, this.annotationKey, doc));
}
else {
added.map(doc => doc.context = this.props.Document);
- targetDataDoc[this.annotationKey] = new List<Doc>([...docList, ...added]);
+ (targetDataDoc[this.annotationKey] as List<Doc>).push(...added);
targetDataDoc[this.annotationKey + "-lastModified"] = new DateField(new Date(Date.now()));
}
}
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 190dbc8c3..7fc4a5c99 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -1,9 +1,9 @@
import { IconProp, library } from '@fortawesome/fontawesome-svg-core';
import { faCaretUp, faFilePdf, faFilm, faImage, faObjectGroup, faStickyNote, faTextHeight, faArrowAltCircleDown, faArrowAltCircleUp, faCheckCircle, faCloudUploadAlt, faLink, faShare, faStopCircle, faSyncAlt, faTag, faTimes, faAngleLeft, faAngleRight, faAngleDoubleLeft, faAngleDoubleRight, faPause } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { action, computed, observable, reaction, runInAction } from "mobx";
+import { action, computed, observable, reaction, runInAction, get } from "mobx";
import { observer } from "mobx-react";
-import { Doc, DataSym, Field, WidthSym, HeightSym } from "../../fields/Doc";
+import { Doc, DataSym, Field, WidthSym, HeightSym, AclEdit, AclAdmin } from "../../fields/Doc";
import { Document } from '../../fields/documentSchemas';
import { ScriptField } from '../../fields/ScriptField';
import { Cast, StrCast, NumCast } from "../../fields/Types";
@@ -23,6 +23,9 @@ import { SnappingManager } from '../util/SnappingManager';
import { HtmlField } from '../../fields/HtmlField';
import { InkField } from "../../fields/InkField";
import { Tooltip } from '@material-ui/core';
+import { GetEffectiveAcl } from '../../fields/util';
+import { DocumentIcon } from './nodes/DocumentIcon';
+import { render } from 'react-dom';
library.add(faCaretUp);
library.add(faObjectGroup);
@@ -89,7 +92,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
const transform = (documentView.props.ScreenToLocalTransform().scale(documentView.props.ContentScaling())).inverse();
var [sptX, sptY] = transform.transformPoint(0, 0);
let [bptX, bptY] = transform.transformPoint(documentView.props.PanelWidth(), documentView.props.PanelHeight());
- if (StrCast(Doc.Layout(documentView.props.Document).layout).includes("LinkAnchorBox")) {
+ if (documentView.props.LayoutTemplateString?.includes("LinkAnchorBox")) {
const docuBox = documentView.ContentDiv.getElementsByClassName("linkAnchorBox-cont");
if (docuBox.length) {
const rect = docuBox[0].getBoundingClientRect();
@@ -194,8 +197,11 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
SelectionManager.DeselectAll();
selected.map(dv => {
- recent && Doc.AddDocToList(recent, "data", dv.props.Document, undefined, true, true);
- dv.props.removeDocument?.(dv.props.Document);
+ const effectiveAcl = GetEffectiveAcl(dv.props.Document);
+ if (effectiveAcl === AclEdit || effectiveAcl === AclAdmin) { // deletes whatever you have the right to delete
+ recent && Doc.AddDocToList(recent, "data", dv.props.Document, undefined, true, true);
+ dv.props.removeDocument?.(dv.props.Document);
+ }
});
}
}
@@ -580,17 +586,18 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
if (SnappingManager.GetIsDragging() || bounds.r - bounds.x < 2 || bounds.x === Number.MAX_VALUE || !seldoc || this._hidden || isNaN(bounds.r) || isNaN(bounds.b) || isNaN(bounds.x) || isNaN(bounds.y)) {
return (null);
}
+ const canDelete = SelectionManager.SelectedDocuments().map(docView => GetEffectiveAcl(docView.props.ContainingCollectionDoc)).some(permission => permission === AclAdmin || permission === AclEdit);
const minimal = bounds.r - bounds.x < 100 ? true : false;
const maximizeIcon = minimal ? (
<Tooltip title={<><div className="dash-tooltip">Show context menu</div></>} placement="top">
<div className="documentDecorations-contextMenu" onPointerDown={this.onSettingsDown}>
<FontAwesomeIcon size="lg" icon="cog" />
- </div></Tooltip>) : (
- <Tooltip title={<><div className="dash-tooltip">Delete</div></>} placement="top">
- <div className="documentDecorations-closeButton" onClick={this.onCloseClick}>
- {/* Currently, this is set to be enabled if there is no ink selected. It might be interesting to think about minimizing ink if it's useful? -syip2*/}
- <FontAwesomeIcon className="documentdecorations-times" icon={faTimes} size="lg" />
- </div></Tooltip>);
+ </div></Tooltip>) : canDelete ? (
+ <Tooltip title={<><div className="dash-tooltip">Delete</div></>} placement="top">
+ <div className="documentDecorations-closeButton" onClick={this.onCloseClick}>
+ {/* Currently, this is set to be enabled if there is no ink selected. It might be interesting to think about minimizing ink if it's useful? -syip2*/}
+ <FontAwesomeIcon className="documentdecorations-times" icon={faTimes} size="lg" />
+ </div></Tooltip>) : (null);
const titleArea = this._edtingTitle ?
<>
diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts
index 086085db5..c9f95a538 100644
--- a/src/client/views/GlobalKeyHandler.ts
+++ b/src/client/views/GlobalKeyHandler.ts
@@ -105,7 +105,6 @@ export default class KeyManager {
}
doDeselect && SelectionManager.DeselectAll();
DictationManager.Controls.stop();
- // RecommendationsBox.Instance.closeMenu();
GoogleAuthenticationManager.Instance.cancel();
HypothesisAuthenticationManager.Instance.cancel();
SharingManager.Instance.close();
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 14d46c5e9..58478ce92 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -1,5 +1,5 @@
import { library } from '@fortawesome/fontawesome-svg-core';
-import { faHireAHelper } from '@fortawesome/free-brands-svg-icons';
+import { faHireAHelper, faBuffer } from '@fortawesome/free-brands-svg-icons';
import * as fa from '@fortawesome/free-solid-svg-icons';
import { ANTIMODEMENU_HEIGHT } from './globalCssVariables.scss';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
@@ -149,7 +149,7 @@ export class MainView extends React.Component {
fa.faFillDrip, fa.faLink, fa.faUnlink, fa.faBold, fa.faItalic, fa.faChevronLeft, fa.faUnderline, fa.faStrikethrough, fa.faSuperscript, fa.faSubscript,
fa.faIndent, fa.faEyeDropper, fa.faPaintRoller, fa.faBars, fa.faBrush, fa.faShapes, fa.faEllipsisH, fa.faHandPaper, fa.faMap, fa.faUser, faHireAHelper,
fa.faBezierCurve, fa.faCircle, fa.faLongArrowAltRight, fa.faPenFancy, fa.faAngleDoubleRight, fa.faAngleUp, fa.faAngleDown, fa.faPlayCircle, fa.faClock,
- fa.faRocket, fa.faExchangeAlt);
+ fa.faRocket, fa.faExchangeAlt, faBuffer);
this.initEventListeners();
this.initAuthenticationRouters();
}
diff --git a/src/client/views/MainViewModal.tsx b/src/client/views/MainViewModal.tsx
index 249715511..66ea2dbf8 100644
--- a/src/client/views/MainViewModal.tsx
+++ b/src/client/views/MainViewModal.tsx
@@ -10,7 +10,7 @@ export interface MainViewOverlayProps {
overlayStyle?: React.CSSProperties;
dialogueBoxDisplayedOpacity?: number;
overlayDisplayedOpacity?: number;
- closeOnExternalClick?: () => void;
+ closeOnExternalClick?: () => void; // the close method of a MainViewModal, triggered if there is a click on the overlay (closing the modal)
}
@observer
diff --git a/src/client/views/RecommendationsBox.scss b/src/client/views/RecommendationsBox.scss
deleted file mode 100644
index 7d89042a4..000000000
--- a/src/client/views/RecommendationsBox.scss
+++ /dev/null
@@ -1,69 +0,0 @@
-@import "globalCssVariables";
-
-.rec-content *{
- display: inline-block;
- margin: auto;
- width: 50;
- height: 150px;
- border: 1px dashed grey;
- padding: 10px 10px;
-}
-
-.rec-content {
- float: left;
- width: inherit;
- align-content: center;
-}
-
-.rec-scroll {
- overflow-y: scroll;
- overflow-x: hidden;
- position: absolute;
- pointer-events: all;
- // display: flex;
- z-index: 10000;
- box-shadow: gray 0.2vw 0.2vw 0.4vw;
- // flex-direction: column;
- background: whitesmoke;
- padding-bottom: 10px;
- padding-top: 20px;
- // border-radius: 15px;
- border: solid #BBBBBBBB 1px;
- width: 100%;
- text-align: center;
- // max-height: 250px;
- height: 100%;
- text-transform: uppercase;
- color: grey;
- letter-spacing: 2px;
-}
-
-.content {
- padding: 10px;
- display: flex;
- flex-direction: row;
- align-items: center;
- justify-content: center;
-}
-
-.image-background {
- pointer-events: none;
- background-color: transparent;
- width: 50%;
- text-align: center;
- margin-left: 5px;
-}
-
-// bcz: UGH!! Can't have global settings like this!!!
-// img{
-// width: 100%;
-// height: 100%;
-// }
-
-.score {
- // margin-left: 15px;
- width: 50%;
- height: 100%;
- text-align: center;
- margin-left: 10px;
-}
diff --git a/src/client/views/RecommendationsBox.tsx b/src/client/views/RecommendationsBox.tsx
deleted file mode 100644
index 196151e32..000000000
--- a/src/client/views/RecommendationsBox.tsx
+++ /dev/null
@@ -1,201 +0,0 @@
-import { observer } from "mobx-react";
-import React = require("react");
-import { observable, action, computed, runInAction } from "mobx";
-import Measure from "react-measure";
-import "./RecommendationsBox.scss";
-import { Doc, DocListCast, WidthSym, HeightSym } from "../../fields/Doc";
-import { DocumentIcon } from "./nodes/DocumentIcon";
-import { StrCast, NumCast } from "../../fields/Types";
-import { returnFalse, emptyFunction, returnEmptyString, returnOne, emptyPath, returnZero, returnEmptyFilter } from "../../Utils";
-import { Transform } from "../util/Transform";
-import { ObjectField } from "../../fields/ObjectField";
-import { DocumentView } from "./nodes/DocumentView";
-import { DocumentType } from '../documents/DocumentTypes';
-import { ClientRecommender } from "../ClientRecommender";
-import { DocServer } from "../DocServer";
-import { Id } from "../../fields/FieldSymbols";
-import { FieldView, FieldViewProps } from "./nodes/FieldView";
-import { DocumentManager } from "../util/DocumentManager";
-import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { library } from "@fortawesome/fontawesome-svg-core";
-import { faBullseye, faLink } from "@fortawesome/free-solid-svg-icons";
-import { DocUtils } from "../documents/Documents";
-
-export interface RecProps {
- documents: { preview: Doc, similarity: number }[];
- node: Doc;
-}
-
-library.add(faBullseye, faLink);
-
-@observer
-export class RecommendationsBox extends React.Component<FieldViewProps> {
-
- public static LayoutString(fieldKey: string) { return FieldView.LayoutString(RecommendationsBox, fieldKey); }
-
- // @observable private _display: boolean = false;
- @observable private _pageX: number = 0;
- @observable private _pageY: number = 0;
- @observable private _width: number = 0;
- @observable private _height: number = 0;
- @observable.shallow private _docViews: JSX.Element[] = [];
- // @observable private _documents: { preview: Doc, score: number }[] = [];
- private previewDocs: Doc[] = [];
-
- constructor(props: FieldViewProps) {
- super(props);
- }
-
- @action
- private DocumentIcon(doc: Doc) {
- const layoutresult = StrCast(doc.type);
- let renderDoc = doc;
- //let box: number[] = [];
- if (layoutresult.indexOf(DocumentType.COL) !== -1) {
- renderDoc = Doc.MakeDelegate(renderDoc);
- }
- const returnXDimension = () => 150;
- const returnYDimension = () => 150;
- const scale = () => returnXDimension() / NumCast(renderDoc._nativeWidth, returnXDimension());
- //let scale = () => 1;
- const newRenderDoc = Doc.MakeAlias(renderDoc); /// newRenderDoc -> renderDoc -> render"data"Doc -> TextProt
- newRenderDoc.height = NumCast(this.props.Document.documentIconHeight);
- newRenderDoc.autoHeight = false;
- const docview = <div>
- <DocumentView
- fitToBox={StrCast(doc.type).indexOf(DocumentType.COL) !== -1}
- Document={newRenderDoc}
- addDocument={returnFalse}
- LibraryPath={emptyPath}
- removeDocument={returnFalse}
- rootSelected={returnFalse}
- ScreenToLocalTransform={Transform.Identity}
- addDocTab={returnFalse}
- pinToPres={returnFalse}
- renderDepth={1}
- NativeHeight={returnZero}
- NativeWidth={returnZero}
- PanelWidth={returnXDimension}
- PanelHeight={returnYDimension}
- focus={emptyFunction}
- backgroundColor={returnEmptyString}
- parentActive={returnFalse}
- whenActiveChanged={returnFalse}
- bringToFront={emptyFunction}
- docFilters={returnEmptyFilter}
- ContainingCollectionView={undefined}
- ContainingCollectionDoc={undefined}
- ContentScaling={scale}
- />
- </div>;
- return docview;
-
- }
-
- // @action
- // closeMenu = () => {
- // this._display = false;
- // this.previewDocs.forEach(doc => DocServer.DeleteDocument(doc[Id]));
- // this.previewDocs = [];
- // }
-
- // @action
- // resetDocuments = () => {
- // this._documents = [];
- // }
-
- // @action
- // displayRecommendations(x: number, y: number) {
- // this._pageX = x;
- // this._pageY = y;
- // this._display = true;
- // }
-
- static readonly buffer = 20;
-
- // get pageX() {
- // const x = this._pageX;
- // if (x < 0) {
- // return 0;
- // }
- // const width = this._width;
- // if (x + width > window.innerWidth - RecommendationsBox.buffer) {
- // return window.innerWidth - RecommendationsBox.buffer - width;
- // }
- // return x;
- // }
-
- // get pageY() {
- // const y = this._pageY;
- // if (y < 0) {
- // return 0;
- // }
- // const height = this._height;
- // if (y + height > window.innerHeight - RecommendationsBox.buffer) {
- // return window.innerHeight - RecommendationsBox.buffer - height;
- // }
- // return y;
- // }
-
- // get createDocViews() {
- // return DocListCast(this.props.Document.data).map(doc => {
- // return (
- // <div className="content">
- // <span style={{ height: NumCast(this.props.Document.documentIconHeight) }} className="image-background">
- // {this.DocumentIcon(doc)}
- // </span>
- // <span className="score">{NumCast(doc.score).toFixed(4)}</span>
- // <div style={{ marginRight: 50 }} onClick={() => DocumentManager.Instance.jumpToDocument(doc, false)}>
- // <FontAwesomeIcon className="documentdecorations-icon" icon={"bullseye"} size="sm" />
- // </div>
- // <div style={{ marginRight: 50 }} onClick={() => DocUtils.MakeLink({ doc: this.props.Document.sourceDoc as Doc }, { doc: doc }, "User Selected Link", "Generated from Recommender", undefined)}>
- // <FontAwesomeIcon className="documentdecorations-icon" icon={"link"} size="sm" />
- // </div>
- // </div>
- // );
- // });
- // }
-
- componentDidMount() { //TODO: invoking a computedFn from outside an reactive context won't be memoized, unless keepAlive is set
- runInAction(() => {
- if (this._docViews.length === 0) {
- this._docViews = DocListCast(this.props.Document.data).map(doc => {
- return (
- <div className="content">
- <span style={{ height: NumCast(this.props.Document.documentIconHeight) }} className="image-background">
- {this.DocumentIcon(doc)}
- </span>
- <span className="score">{NumCast(doc.score).toFixed(4)}</span>
- <div style={{ marginRight: 50 }} onClick={() => DocumentManager.Instance.jumpToDocument(doc, false)}>
- <FontAwesomeIcon className="documentdecorations-icon" icon={"bullseye"} size="sm" />
- </div>
- <div style={{ marginRight: 50 }} onClick={() => DocUtils.MakeLink({ doc: this.props.Document.sourceDoc as Doc }, { doc: doc }, "Recommender", "", undefined)}>
- <FontAwesomeIcon className="documentdecorations-icon" icon={"link"} size="sm" />
- </div>
- </div>
- );
- });
- }
- });
- }
-
- render() { //TODO: Invariant violation: max depth exceeded error. Occurs when images are rendered.
- // if (!this._display) {
- // return null;
- // }
- // let style = { left: this.pageX, top: this.pageY };
- //const transform = "translate(" + (NumCast(this.props.node.x) + 350) + "px, " + NumCast(this.props.node.y) + "px"
- let title = StrCast((this.props.Document.sourceDoc as Doc).title);
- if (title.length > 15) {
- title = title.substring(0, 15) + "...";
- }
- return (
- <div className="rec-scroll">
- <p>Recommendations for "{title}"</p>
- {this._docViews}
- </div>
- );
- }
- //
- //
-} \ No newline at end of file
diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx
index 9fb8a227e..eb20fc257 100644
--- a/src/client/views/TemplateMenu.tsx
+++ b/src/client/views/TemplateMenu.tsx
@@ -63,14 +63,6 @@ export class TemplateMenu extends React.Component<TemplateMenuProps> {
this.props.docViews.map(dv => dv.switchViews(false, "layout"));
}
- toggleFloat = (e: React.ChangeEvent<HTMLInputElement>): void => {
- SelectionManager.DeselectAll();
- const topDocView = this.props.docViews[0];
- const ex = e.target.getBoundingClientRect().left;
- const ey = e.target.getBoundingClientRect().top;
- DocumentView.FloatDoc(topDocView, ex, ey);
- }
-
toggleAudio = (e: React.ChangeEvent<HTMLInputElement>): void => {
this.props.docViews.map(dv => dv.props.Document._showAudio = e.target.checked);
}
@@ -127,7 +119,6 @@ export class TemplateMenu extends React.Component<TemplateMenuProps> {
this.props.templates.forEach((checked, template) =>
templateMenu.push(<TemplateToggle key={template.Name} template={template} checked={checked} toggle={this.toggleTemplate} />));
templateMenu.push(<OtherToggle key={"audio"} name={"Audio"} checked={firstDoc._showAudio ? true : false} toggle={this.toggleAudio} />);
- templateMenu.push(<OtherToggle key={"float"} name={"Float"} checked={firstDoc.z ? true : false} toggle={this.toggleFloat} />);
templateMenu.push(<OtherToggle key={"chrome"} name={"Chrome"} checked={layout._chromeStatus !== "disabled"} toggle={this.toggleChrome} />);
templateMenu.push(<OtherToggle key={"default"} name={"Default"} checked={templateName === "layout"} toggle={this.toggleDefault} />);
addedTypes.concat(noteTypes).map(template => template.treeViewChecked = this.templateIsUsed(firstDoc, template));
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index b82a33bd8..f658e9816 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -597,7 +597,6 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp
stackCreated = (stack: any) => {
//stack.header.controlsContainer.find('.lm_popout').hide();
- stack.header.element[0].style.backgroundColor = DocServer.Control.isReadOnly() ? "#228540" : undefined;
stack.header.element.on('mousedown', (e: any) => {
if (e.target === stack.header.element[0] && e.button === 1) {
this.AddTab(stack, Docs.Create.FreeformDocument([], { _width: this.props.PanelWidth(), _height: this.props.PanelHeight(), title: "Untitled Collection" }));
diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index d6cb79e9c..0ca86172f 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -27,6 +27,7 @@ import { ColorState } from "react-color";
import { ObjectField } from "../../../fields/ObjectField";
import { ScriptField } from "../../../fields/ScriptField";
import { IconProp } from '@fortawesome/fontawesome-svg-core';
+import { DocUtils } from "../../documents/Documents";
@observer
export default class CollectionMenu extends AntimodeMenu {
@@ -313,12 +314,19 @@ export class CollectionViewBaseChrome extends React.Component<CollectionMenuProp
<div className="collectionMenu">
<div className="collectionViewBaseChrome">
{this.props.type === CollectionViewType.Invalid || this.props.type === CollectionViewType.Docking ? (null) : this.viewModes}
- {this.props.type === CollectionViewType.Invalid || this.props.type === CollectionViewType.Docking ? (null) : this.templateChrome}
+ {this.props.type === CollectionViewType.Docking ? (null) : this.templateChrome}
<div className="collectionViewBaseChrome-viewSpecs" title="filter documents to show" style={{ display: "grid" }}>
<button className={"antimodeMenu-button"} onClick={this.toggleViewSpecs} >
<FontAwesomeIcon icon="filter" size="lg" />
</button>
</div>
+
+ {this.props.docView.props.ContainingCollectionDoc?._viewType !== CollectionViewType.Freeform ? (null) : <button className={"antimodeMenu-button"} key="float"
+ style={{ backgroundColor: !this.props.docView.layoutDoc.isAnnotating ? "121212" : undefined, borderRight: "1px solid gray" }}
+ title="Toggle Overlay Layer"
+ onClick={() => DocumentView.FloatDoc(this.props.docView)}>
+ <FontAwesomeIcon icon={["fab", "buffer"]} size={"lg"} />
+ </button>}
</div>
{this.subChrome}
</div>
@@ -540,7 +548,7 @@ export class CollectionFreeFormViewChrome extends React.Component<CollectionMenu
<FontAwesomeIcon icon={"caret-right"} size={"lg"} />
</div>
- {!this.props.isOverlay ? (null) :
+ {!this.props.isOverlay || this.document.type !== DocumentType.WEB ? (null) :
<button className={"antimodeMenu-button"} key="hypothesis"
style={{ backgroundColor: !this.props.docView.layoutDoc.isAnnotating ? "121212" : undefined, borderRight: "1px solid gray" }}
title="Use Hypothesis"
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index a89fcc703..9f78c15eb 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -127,7 +127,7 @@ export function CollectionSubView<T, X>(schemaCtor: (doc: Doc) => T, moreProps?:
const docs = rawdocs.filter(d => !(d instanceof Promise)).map(d => d as Doc);
const docFilters = this.docFilters();
- const viewSpecScript = Cast(this.props.Document.viewSpecScript, ScriptField);
+ const viewSpecScript = ScriptCast(this.props.Document.viewSpecScript);
const docRangeFilters = this.props.ignoreFields?.includes("_docRangeFilters") ? [] : Cast(this.props.Document._docRangeFilters, listSpec("string"), []);
return this.props.Document.dontRegisterView ? docs : DocUtils.FilterDocs(docs, docFilters, docRangeFilters, viewSpecScript);
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index dd823f5d5..b8996c178 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -100,8 +100,8 @@ class TreeView extends React.Component<TreeViewProps> {
childDocList(field: string) {
const layout = Doc.LayoutField(this.doc) instanceof Doc ? Doc.LayoutField(this.doc) as Doc : undefined;
return ((this.props.dataDoc ? DocListCast(this.props.dataDoc[field]) : undefined) || // if there's a data doc for an expanded template, use it's data field
- (layout ? Cast(layout[field], listSpec(Doc)) : undefined) || // else if there's a layout doc, display it's fields
- Cast(this.doc[field], listSpec(Doc))) as Doc[]; // otherwise use the document's data field
+ (layout ? DocListCast(layout[field]) : undefined) || // else if there's a layout doc, display it's fields
+ DocListCast(this.doc[field])) as Doc[]; // otherwise use the document's data field
}
@computed get childDocs() { return this.childDocList(this.fieldKey); }
@computed get childLinks() { return this.childDocList("links"); }
diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx
index 42d320308..7e7ea6786 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, getPlaygroundMode, distributeAcls, SharingPermissions } from '../../../fields/util';
+import { TraceMobx, GetEffectiveAcl, SharingPermissions } 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';
@@ -142,20 +142,20 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
const effectiveAcl = GetEffectiveAcl(this.props.Document);
if (added.length) {
- if (effectiveAcl === AclPrivate || (effectiveAcl === AclReadonly && !getPlaygroundMode())) {
+ if (effectiveAcl === AclPrivate || effectiveAcl === AclReadonly) {
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])) {
- distributeAcls(key, this.AclMap.get(value) as SharingPermissions, d, true);
- }
- // dataDoc[AclSym] = d[AclSym] = this.props.Document[AclSym];
- });
- }
+ // 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 (effectiveAcl === AclAddonly) {
added.map(doc => Doc.AddDocToList(targetDataDoc, this.props.fieldKey, doc));
@@ -179,7 +179,8 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
doc.context = this.props.Document;
});
added.map(add => Doc.AddDocToList(Cast(Doc.UserDoc().myCatalog, Doc, null), "data", add));
- targetDataDoc[this.props.fieldKey] = new List<Doc>([...docList, ...added]);
+ // targetDataDoc[this.props.fieldKey] = new List<Doc>([...docList, ...added]);
+ (targetDataDoc[this.props.fieldKey] as List<Doc>).push(...added);
targetDataDoc[this.props.fieldKey + "-lastModified"] = new DateField(new Date(Date.now()));
}
}
@@ -189,14 +190,16 @@ export class CollectionView extends Touchable<FieldViewProps & CollectionViewCus
@action.bound
removeDocument = (doc: any): boolean => {
- const effectiveAcl = GetEffectiveAcl(this.props.Document);
- if (effectiveAcl === AclEdit || effectiveAcl === AclAdmin || getPlaygroundMode()) {
+ const collectionEffectiveAcl = GetEffectiveAcl(this.props.Document);
+ const docEffectiveAcl = GetEffectiveAcl(doc);
+ // you can remove the document if you either have Admin/Edit access to the collection or to the specific document
+ if (collectionEffectiveAcl === AclEdit || collectionEffectiveAcl === AclAdmin || docEffectiveAcl === AclAdmin || docEffectiveAcl === AclEdit) {
const docs = doc instanceof Doc ? [doc] : doc as Doc[];
const targetDataDoc = this.props.Document[DataSym];
const value = DocListCast(targetDataDoc[this.props.fieldKey]);
- const result = value.filter(v => !docs.includes(v));
- if (result.length !== value.length) {
- targetDataDoc[this.props.fieldKey] = new List<Doc>(result);
+ const toRemove = value.filter(v => docs.includes(v));
+ if (toRemove.length !== 0) {
+ toRemove.forEach(doc => Doc.RemoveDocFromList(targetDataDoc, this.props.fieldKey, doc));
return true;
}
}
diff --git a/src/client/views/collections/collectionFreeForm/FormatShapePane.scss b/src/client/views/collections/collectionFreeForm/FormatShapePane.scss
index 010beb836..d49ab27fb 100644
--- a/src/client/views/collections/collectionFreeForm/FormatShapePane.scss
+++ b/src/client/views/collections/collectionFreeForm/FormatShapePane.scss
@@ -27,13 +27,15 @@
position: absolute;
}
-.sketch-picker {
- background: #323232;
- width: 160px !important;
- height: 80% !important;
-
- .flexbox-fit {
+.btn-group-palette {
+ .sketch-picker {
background: #323232;
+ width: 160px !important;
+ height: 80% !important;
+
+ .flexbox-fit {
+ background: #323232;
+ }
}
}
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index 764758eee..a32c8b363 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -1,7 +1,7 @@
import { action, computed, observable } from "mobx";
import { observer } from "mobx-react";
import { Doc, Opt, DocListCast, DataSym, AclEdit, AclAddonly, AclAdmin } from "../../../../fields/Doc";
-import { GetEffectiveAcl, getPlaygroundMode } from "../../../../fields/util";
+import { GetEffectiveAcl } from "../../../../fields/util";
import { InkData, InkField, InkTool } from "../../../../fields/InkField";
import { List } from "../../../../fields/List";
import { RichTextField } from "../../../../fields/RichTextField";
@@ -281,7 +281,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
this._downX = x;
this._downY = y;
const effectiveAcl = GetEffectiveAcl(this.props.Document);
- if ([AclAdmin, AclEdit, AclAddonly].includes(effectiveAcl) || getPlaygroundMode()) PreviewCursor.Show(x, y, this.onKeyPress, this.props.addLiveTextDocument, this.props.getTransform, this.props.addDocument, this.props.nudge);
+ if ([AclAdmin, AclEdit, AclAddonly].includes(effectiveAcl)) PreviewCursor.Show(x, y, this.onKeyPress, this.props.addLiveTextDocument, this.props.getTransform, this.props.addDocument, this.props.nudge);
this.clearSelection();
}
});
diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx
index 47dc0a773..e8173d103 100644
--- a/src/client/views/nodes/DocumentContentsView.tsx
+++ b/src/client/views/nodes/DocumentContentsView.tsx
@@ -35,7 +35,6 @@ import { VideoBox } from "./VideoBox";
import { WebBox } from "./WebBox";
import { InkingStroke } from "../InkingStroke";
import React = require("react");
-import { RecommendationsBox } from "../RecommendationsBox";
import { TraceMobx, GetEffectiveAcl } from "../../../fields/util";
import { ScriptField } from "../../../fields/ScriptField";
import XRegExp = require("xregexp");
@@ -194,7 +193,7 @@ export class DocumentContentsView extends React.Component<DocumentViewProps & {
CollectionFreeFormView, CollectionDockingView, CollectionSchemaView, CollectionView, WebBox, KeyValueBox,
PDFBox, VideoBox, AudioBox, PresBox, YoutubeBox, PresElementBox, QueryBox,
ColorBox, DashWebRTCVideo, LinkAnchorBox, InkingStroke, DocHolderBox, LinkBox, ScriptingBox,
- RecommendationsBox, ScreenshotBox, HTMLtag, ComparisonBox
+ ScreenshotBox, HTMLtag, ComparisonBox
}}
bindings={bindings}
jsx={layoutFrame}
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 37d561954..b3bfadf4f 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -238,20 +238,28 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
}
}
- public static FloatDoc(topDocView: DocumentView, x: number, y: number) {
+ @undoBatch @action
+ public static FloatDoc(topDocView: DocumentView, x?: number, y?: number) {
const topDoc = topDocView.props.Document;
- const de = new DragManager.DocumentDragData([topDoc]);
- de.dragDivName = topDocView.props.dragDivName;
- de.moveDocument = topDocView.props.moveDocument;
- setTimeout(() => {
- const newDocView = DocumentManager.Instance.getDocumentView(topDoc);
- if (newDocView) {
- const contentDiv = newDocView.ContentDiv!;
- const xf = contentDiv.getBoundingClientRect();
- DragManager.StartDocumentDrag([contentDiv], de, x, y, { offsetX: x - xf.left, offsetY: y - xf.top, hideSource: true });
+ const container = topDocView.props.ContainingCollectionView;
+ if (container) {
+ SelectionManager.DeselectAll();
+ if (topDoc.z && (x === undefined && y === undefined)) {
+ const spt = container.screenToLocalTransform().inverse().transformPoint(NumCast(topDoc.x), NumCast(topDoc.y));
+ topDoc.z = 0;
+ topDoc.x = spt[0];
+ topDoc.y = spt[1];
+ topDocView.props.removeDocument?.(topDoc);
+ topDocView.props.addDocTab(topDoc, "inParent");
+ } else {
+ const spt = topDocView.props.ScreenToLocalTransform().inverse().transformPoint(0, 0);
+ const fpt = container.screenToLocalTransform().transformPoint(x !== undefined ? x : spt[0], y !== undefined ? y : spt[1]);
+ topDoc.z = 1;
+ topDoc.x = fpt[0];
+ topDoc.y = fpt[1];
}
- }, 0);
- UndoManager.RunInBatch(action(() => topDoc.z = topDoc.z ? 0 : 1), "float");
+ setTimeout(() => SelectionManager.SelectDoc(DocumentManager.Instance.getDocumentView(topDoc, container)!, false), 0);
+ }
}
onKeyDown = (e: React.KeyboardEvent) => {
@@ -849,6 +857,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
if (this.props.LayoutTemplateString?.includes("LinkAnchorBox")) return null;
return (this.props.treeViewDoc && this.props.LayoutTemplateString) || // render nothing for: tree view anchor dots
this.layoutDoc.presBox || // presentationbox nodes
+ this.rootDoc.type === DocumentType.LINK ||
this.props.dontRegisterView ? (null) : // view that are not registered
DocUtils.FilterDocs(this.directLinks, this.props.docFilters(), []).filter(d => !d.hidden && this.isNonTemporalLink).map((d, i) =>
<DocumentView {...this.props} key={i + 1}
diff --git a/src/client/views/nodes/LinkAnchorBox.tsx b/src/client/views/nodes/LinkAnchorBox.tsx
index d4ab70200..be6292bb6 100644
--- a/src/client/views/nodes/LinkAnchorBox.tsx
+++ b/src/client/views/nodes/LinkAnchorBox.tsx
@@ -49,14 +49,13 @@ export class LinkAnchorBox extends ViewBoxBaseComponent<FieldViewProps, LinkAnch
const bounds = cdiv.getBoundingClientRect();
const pt = Utils.getNearestPointInPerimeter(bounds.left, bounds.top, bounds.width, bounds.height, e.clientX, e.clientY);
const separation = Math.sqrt((pt[0] - e.clientX) * (pt[0] - e.clientX) + (pt[1] - e.clientY) * (pt[1] - e.clientY));
- const dragdist = Math.sqrt((pt[0] - down[0]) * (pt[0] - down[0]) + (pt[1] - down[1]) * (pt[1] - down[1]));
if (separation > 100) {
const dragData = new DragManager.DocumentDragData([this.rootDoc]);
dragData.dropAction = "alias";
dragData.removeDropProperties = ["anchor1_x", "anchor1_y", "anchor2_x", "anchor2_y", "isLinkButton"];
- DragManager.StartDocumentDrag([this._ref.current!], dragData, down[0], down[1]);
+ DragManager.StartDocumentDrag([this._ref.current!], dragData, pt[0], pt[1]);
return true;
- } else if (dragdist > separation) {
+ } else {
this.rootDoc[this.fieldKey + "_x"] = (pt[0] - bounds.left) / bounds.width * 100;
this.rootDoc[this.fieldKey + "_y"] = (pt[1] - bounds.top) / bounds.height * 100;
}
diff --git a/src/client/views/nodes/TaskCompletedBox.tsx b/src/client/views/nodes/TaskCompletedBox.tsx
index 89602f219..2a3dd8d2d 100644
--- a/src/client/views/nodes/TaskCompletedBox.tsx
+++ b/src/client/views/nodes/TaskCompletedBox.tsx
@@ -1,7 +1,5 @@
import React = require("react");
import { observer } from "mobx-react";
-import { documentSchema } from "../../../fields/documentSchemas";
-import { makeInterface } from "../../../fields/Schema";
import "./TaskCompletedBox.scss";
import { observable, action } from "mobx";
import { Fade } from "@material-ui/core";
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index d30f1499e..646a94aa7 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -4,7 +4,7 @@ import { action, computed, IReactionDisposer, observable, reaction, runInAction
import { observer } from "mobx-react";
import { Dictionary } from "typescript-collections";
import * as WebRequest from 'web-request';
-import { Doc, DocListCast, Opt } from "../../../fields/Doc";
+import { Doc, DocListCast, Opt, AclAddonly, AclEdit, AclAdmin } from "../../../fields/Doc";
import { documentSchema } from "../../../fields/documentSchemas";
import { Id } from "../../../fields/FieldSymbols";
import { HtmlField } from "../../../fields/HtmlField";
@@ -13,7 +13,7 @@ import { List } from "../../../fields/List";
import { listSpec, makeInterface } from "../../../fields/Schema";
import { Cast, NumCast, StrCast } from "../../../fields/Types";
import { WebField } from "../../../fields/URLField";
-import { TraceMobx } from "../../../fields/util";
+import { TraceMobx, GetEffectiveAcl } from "../../../fields/util";
import { addStyleSheet, clearStyleSheetRules, emptyFunction, returnOne, returnZero, Utils, returnTrue } from "../../../Utils";
import { Docs, DocUtils } from "../../documents/Documents";
import { DragManager } from "../../util/DragManager";
@@ -535,9 +535,10 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps, WebDocum
@action
highlight = (color: string) => {
// creates annotation documents for current highlights
- const annotationDoc = this.makeAnnotationDocument(color);
- annotationDoc && Doc.AddDocToList(this.props.Document, this.annotationKey, annotationDoc);
- return annotationDoc;
+ const effectiveAcl = GetEffectiveAcl(this.props.Document);
+ const annotationDoc = [AclAddonly, AclEdit, AclAdmin].includes(effectiveAcl) && this.makeAnnotationDocument(color);
+ annotationDoc && this.addDocument?.(annotationDoc);
+ return annotationDoc ?? undefined;
}
/**
* This is temporary for creating annotations from highlights. It will
diff --git a/src/client/views/nodes/formattedText/RichTextMenu.tsx b/src/client/views/nodes/formattedText/RichTextMenu.tsx
index 47a4911b8..7ccbfa051 100644
--- a/src/client/views/nodes/formattedText/RichTextMenu.tsx
+++ b/src/client/views/nodes/formattedText/RichTextMenu.tsx
@@ -223,7 +223,7 @@ export default class RichTextMenu extends AntimodeMenu {
if (this.view && this.TextView.props.isSelected(true)) {
const path = (this.view.state.selection.$from as any).path;
for (let i = path.length - 3; i < path.length && i >= 0; i -= 3) {
- if (path[i]?.type === this.view.state.schema.nodes.paragraph) {
+ if (path[i]?.type === this.view.state.schema.nodes.paragraph || path[i]?.type === this.view.state.schema.nodes.heading) {
return path[i].attrs.align || "left";
}
}
@@ -490,7 +490,7 @@ export default class RichTextMenu extends AntimodeMenu {
alignParagraphs(state: EditorState<any>, align: "left" | "right" | "center", dispatch: any) {
var tr = state.tr;
state.doc.nodesBetween(state.selection.from, state.selection.to, (node, pos, parent, index) => {
- if (node.type === schema.nodes.paragraph) {
+ if (node.type === schema.nodes.paragraph || node.type === schema.nodes.heading) {
tr = tr.setNodeMarkup(pos, node.type, { ...node.attrs, align }, node.marks);
return false;
}
@@ -503,7 +503,7 @@ export default class RichTextMenu extends AntimodeMenu {
insetParagraph(state: EditorState<any>, dispatch: any) {
var tr = state.tr;
state.doc.nodesBetween(state.selection.from, state.selection.to, (node, pos, parent, index) => {
- if (node.type === schema.nodes.paragraph) {
+ if (node.type === schema.nodes.paragraph || node.type === schema.nodes.heading) {
const inset = (node.attrs.inset ? Number(node.attrs.inset) : 0) + 10;
tr = tr.setNodeMarkup(pos, node.type, { ...node.attrs, inset }, node.marks);
return false;
@@ -516,7 +516,7 @@ export default class RichTextMenu extends AntimodeMenu {
outsetParagraph(state: EditorState<any>, dispatch: any) {
var tr = state.tr;
state.doc.nodesBetween(state.selection.from, state.selection.to, (node, pos, parent, index) => {
- if (node.type === schema.nodes.paragraph) {
+ if (node.type === schema.nodes.paragraph || node.type === schema.nodes.heading) {
const inset = Math.max(0, (node.attrs.inset ? Number(node.attrs.inset) : 0) - 10);
tr = tr.setNodeMarkup(pos, node.type, { ...node.attrs, inset }, node.marks);
return false;
@@ -529,8 +529,9 @@ export default class RichTextMenu extends AntimodeMenu {
indentParagraph(state: EditorState<any>, dispatch: any) {
var tr = state.tr;
+ let headin = false;
state.doc.nodesBetween(state.selection.from, state.selection.to, (node, pos, parent, index) => {
- if (node.type === schema.nodes.paragraph) {
+ if (node.type === schema.nodes.paragraph || node.type === schema.nodes.heading) {
const nodeval = node.attrs.indent ? Number(node.attrs.indent) : undefined;
const indent = !nodeval ? 25 : nodeval < 0 ? 0 : nodeval + 25;
tr = tr.setNodeMarkup(pos, node.type, { ...node.attrs, indent }, node.marks);
@@ -538,14 +539,14 @@ export default class RichTextMenu extends AntimodeMenu {
}
return true;
});
- dispatch?.(tr);
+ !headin && dispatch?.(tr);
return true;
}
hangingIndentParagraph(state: EditorState<any>, dispatch: any) {
var tr = state.tr;
state.doc.nodesBetween(state.selection.from, state.selection.to, (node, pos, parent, index) => {
- if (node.type === schema.nodes.paragraph) {
+ if (node.type === schema.nodes.paragraph || node.type === schema.nodes.heading) {
const nodeval = node.attrs.indent ? Number(node.attrs.indent) : undefined;
const indent = !nodeval ? -25 : nodeval > 0 ? 0 : nodeval - 10;
tr = tr.setNodeMarkup(pos, node.type, { ...node.attrs, indent }, node.marks);
@@ -827,6 +828,7 @@ export default class RichTextMenu extends AntimodeMenu {
}
// TODO: should check for valid URL
+ @undoBatch
makeLinkToURL = (target: string, lcoation: string) => {
((this.view as any)?.TextView as FormattedTextBox).makeLinkToSelection("", target, "onRight", "", target);
}
diff --git a/src/client/views/nodes/formattedText/nodes_rts.ts b/src/client/views/nodes/formattedText/nodes_rts.ts
index 1af821738..0eca6d753 100644
--- a/src/client/views/nodes/formattedText/nodes_rts.ts
+++ b/src/client/views/nodes/formattedText/nodes_rts.ts
@@ -66,9 +66,11 @@ export const nodes: { [index: string]: NodeSpec } = {
// should hold the number 1 to 6. Parsed and serialized as `<h1>` to
// `<h6>` elements.
heading: {
- attrs: { level: { default: 1 } },
- content: "inline*",
- group: "block",
+ ...ParagraphNodeSpec,
+ attrs: {
+ ...ParagraphNodeSpec.attrs,
+ level: { default: 1 },
+ },
defining: true,
parseDOM: [{ tag: "h1", attrs: { level: 1 } },
{ tag: "h2", attrs: { level: 2 } },
@@ -76,7 +78,18 @@ export const nodes: { [index: string]: NodeSpec } = {
{ tag: "h4", attrs: { level: 4 } },
{ tag: "h5", attrs: { level: 5 } },
{ tag: "h6", attrs: { level: 6 } }],
- toDOM(node: any) { return ["h" + node.attrs.level, 0]; }
+ toDOM(node) {
+ var dom = toParagraphDOM(node) as any;
+ var level = node.attrs.level || 1;
+ dom[0] = 'h' + level;
+ return dom;
+ },
+ getAttrs(dom: any) {
+ var attrs = getParagraphNodeAttrs(dom) as any;
+ var level = Number(dom.nodeName.substring(1)) || 1;
+ attrs.level = level;
+ return attrs;
+ }
},
// :: NodeSpec A code listing. Disallows marks or non-text inline
diff --git a/src/client/views/pdf/PDFMenu.tsx b/src/client/views/pdf/PDFMenu.tsx
index c3e1ae22f..7bea8d01b 100644
--- a/src/client/views/pdf/PDFMenu.tsx
+++ b/src/client/views/pdf/PDFMenu.tsx
@@ -93,7 +93,7 @@ export default class PDFMenu extends AntimodeMenu {
@computed get highlighter() {
const button =
- <button className="antimodeMenu-button color-preview-button" title="" key="highilghter-button" onPointerDown={this.highlightClicked}>
+ <button className="antimodeMenu-button color-preview-button" title="" key="highlighter-button" onPointerDown={this.highlightClicked}>
<FontAwesomeIcon icon="highlighter" size="lg" style={{ transition: "transform 0.1s", transform: this.Highlighting ? "" : "rotate(-45deg)" }} />
<div className="color-preview" style={{ backgroundColor: this.highlightColor }}></div>
</button>;
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index d1010de48..192a6300a 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -4,7 +4,7 @@ const pdfjs = require('pdfjs-dist/es5/build/pdf.js');
import * as Pdfjs from "pdfjs-dist";
import "pdfjs-dist/web/pdf_viewer.css";
import { Dictionary } from "typescript-collections";
-import { Doc, DocListCast, FieldResult, HeightSym, Opt, WidthSym } from "../../../fields/Doc";
+import { Doc, DocListCast, FieldResult, HeightSym, Opt, WidthSym, AclAddonly, AclEdit, AclAdmin } from "../../../fields/Doc";
import { documentSchema } from "../../../fields/documentSchemas";
import { Id } from "../../../fields/FieldSymbols";
import { InkTool } from "../../../fields/InkField";
@@ -13,7 +13,7 @@ import { createSchema, makeInterface, listSpec } from "../../../fields/Schema";
import { ScriptField, ComputedField } from "../../../fields/ScriptField";
import { Cast, NumCast } from "../../../fields/Types";
import { PdfField } from "../../../fields/URLField";
-import { TraceMobx } from "../../../fields/util";
+import { TraceMobx, GetEffectiveAcl } from "../../../fields/util";
import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, emptyFunction, emptyPath, intersectRect, returnZero, smoothScroll, Utils } from "../../../Utils";
import { Docs, DocUtils } from "../../documents/Documents";
import { DocumentType } from "../../documents/DocumentTypes";
@@ -570,9 +570,10 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
@action
highlight = (color: string) => {
// creates annotation documents for current highlights
- const annotationDoc = this.makeAnnotationDocument(color);
- annotationDoc && this.props.addDocument?.(annotationDoc);
- return annotationDoc;
+ const effectiveAcl = GetEffectiveAcl(this.props.Document);
+ const annotationDoc = [AclAddonly, AclEdit, AclAdmin].includes(effectiveAcl) && this.makeAnnotationDocument(color);
+ annotationDoc && this.addDocument?.(annotationDoc);
+ return annotationDoc as Doc ?? undefined;
}
/**