aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/client/util/DropConverter.ts2
-rw-r--r--src/client/views/DocumentButtonBar.tsx4
-rw-r--r--src/client/views/DocumentDecorations.scss3
-rw-r--r--src/client/views/DocumentDecorations.tsx6
-rw-r--r--src/client/views/TemplateMenu.tsx94
-rw-r--r--src/client/views/collections/CollectionDockingView.tsx27
-rw-r--r--src/client/views/collections/CollectionLinearView.tsx20
-rw-r--r--src/client/views/collections/CollectionTreeView.scss1
-rw-r--r--src/client/views/collections/CollectionTreeView.tsx7
-rw-r--r--src/client/views/collections/ParentDocumentSelector.tsx22
-rw-r--r--src/client/views/collections/collectionFreeForm/MarqueeView.tsx12
-rw-r--r--src/client/views/nodes/DocumentView.tsx15
-rw-r--r--src/client/views/nodes/FormattedTextBox.tsx25
-rw-r--r--src/client/views/search/SearchItem.tsx2
-rw-r--r--src/new_fields/Doc.ts2
-rw-r--r--src/new_fields/ScriptField.ts4
-rw-r--r--src/new_fields/util.ts1
-rw-r--r--src/server/authentication/models/current_user_utils.ts16
18 files changed, 189 insertions, 74 deletions
diff --git a/src/client/util/DropConverter.ts b/src/client/util/DropConverter.ts
index 861cde5de..a6a43d06a 100644
--- a/src/client/util/DropConverter.ts
+++ b/src/client/util/DropConverter.ts
@@ -49,7 +49,7 @@ export function convertDropDataToButtons(data: DragManager.DocumentDragData) {
(layoutDoc.layout instanceof Doc) && !data.userDropAction;
}
layoutDoc.isTemplateDoc = true;
- dbox = Docs.Create.FontIconDocument({ _nativeWidth: 100, _nativeHeight: 100, _width: 100, _height: 100, backgroundColor: StrCast(doc.backgroundColor), title: "Custom", icon: layoutDoc.isTemplateDoc ? "font" : "bolt" });
+ dbox = Docs.Create.FontIconDocument({ _nativeWidth: 100, _nativeHeight: 100, _width: 100, _height: 100, backgroundColor: StrCast(doc.backgroundColor), title: StrCast(layoutDoc.title), icon: layoutDoc.isTemplateDoc ? "font" : "bolt" });
dbox.dragFactory = layoutDoc;
dbox.removeDropProperties = doc.removeDropProperties instanceof ObjectField ? ObjectField.MakeCopy(doc.removeDropProperties) : undefined;
dbox.onDragStart = ScriptField.MakeFunction('getCopy(this.dragFactory, true)');
diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx
index 23875fa33..8a33232b4 100644
--- a/src/client/views/DocumentButtonBar.tsx
+++ b/src/client/views/DocumentButtonBar.tsx
@@ -108,7 +108,7 @@ export class DocumentButtonBar extends React.Component<{ views: (DocumentView |
this._pullColorAnimating = false;
});
- get view0() { return this.props.views && this.props.views.length ? this.props.views[0] : undefined; }
+ get view0() { return this.props.views?.[0]; }
@action
onLinkButtonMoved = (e: PointerEvent): void => {
@@ -250,7 +250,7 @@ export class DocumentButtonBar extends React.Component<{ views: (DocumentView |
@computed
get contextButton() {
- return !this.view0 ? (null) : <ParentDocSelector Views={this.props.views.filter(v => v).map(v => v as DocumentView)} Document={this.view0.props.Document} addDocTab={(doc, where) => {
+ return !this.view0 ? (null) : <ParentDocSelector Document={this.view0.props.Document} addDocTab={(doc, where) => {
where === "onRight" ? CollectionDockingView.AddRightSplit(doc) :
this.props.stack ? CollectionDockingView.Instance.AddTab(this.props.stack, doc) :
this.view0?.props.addDocTab(doc, "onRight");
diff --git a/src/client/views/DocumentDecorations.scss b/src/client/views/DocumentDecorations.scss
index 8d6002f8f..353520026 100644
--- a/src/client/views/DocumentDecorations.scss
+++ b/src/client/views/DocumentDecorations.scss
@@ -80,6 +80,7 @@ $linkGap : 3px;
#documentDecorations-topLeftResizer,
#documentDecorations-bottomRightResizer {
cursor: nwse-resize;
+ background: dimGray;
}
#documentDecorations-bottomRightResizer {
@@ -89,6 +90,7 @@ $linkGap : 3px;
#documentDecorations-topRightResizer,
#documentDecorations-bottomLeftResizer {
cursor: nesw-resize;
+ background: dimGray;
}
#documentDecorations-topResizer,
@@ -158,6 +160,7 @@ $linkGap : 3px;
padding-top: 5px;
width: $MINIMIZED_ICON_SIZE;
height: $MINIMIZED_ICON_SIZE;
+ max-height: 20px;
}
.documentDecorations-background {
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index c4abc935f..ff72592d8 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -266,7 +266,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
let dist = Math.sqrt((e.clientX - down[0]) * (e.clientX - down[0]) + (e.clientY - down[1]) * (e.clientY - down[1]));
dist = dist < 3 ? 0 : dist;
SelectionManager.SelectedDocuments().map(dv => dv.props.Document).map(doc => doc.layout instanceof Doc ? doc.layout : doc.isTemplateForField ? doc : Doc.GetProto(doc)).
- map(d => d.borderRounding = `${Math.max(0, dist)}px`);
+ map(d => d.borderRounding = `${Math.max(0, dist)}%`);
return false;
}
@@ -330,6 +330,10 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
const width = (layoutDoc._width || 0);
const height = (layoutDoc._height || (nheight / nwidth * width));
const scale = element.props.ScreenToLocalTransform().Scale * element.props.ContentScaling();
+ if (nwidth && nheight) {
+ if (Math.abs(dW) > Math.abs(dH)) dH = dW * nheight / nwidth;
+ else dW = dH * nwidth / nheight;
+ }
const actualdW = Math.max(width + (dW * scale), 20);
const actualdH = Math.max(height + (dH * scale), 20);
doc.x = (doc.x || 0) + dX * (actualdW - width);
diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx
index 5029b4074..cf6ce2c6f 100644
--- a/src/client/views/TemplateMenu.tsx
+++ b/src/client/views/TemplateMenu.tsx
@@ -1,4 +1,4 @@
-import { action, observable, runInAction, ObservableSet } from "mobx";
+import { action, observable, runInAction, ObservableSet, trace, computed } from "mobx";
import { observer } from "mobx-react";
import { SelectionManager } from "../util/SelectionManager";
import { undoBatch } from "../util/UndoManager";
@@ -7,8 +7,13 @@ import { DocumentView } from "./nodes/DocumentView";
import { Template } from "./Templates";
import React = require("react");
import { Doc, DocListCast } from "../../new_fields/Doc";
+import { Docs, } from "../documents/Documents";
import { StrCast, Cast } from "../../new_fields/Types";
-import { CurrentUserUtils } from "../../server/authentication/models/current_user_utils";
+import { CollectionTreeView } from "./collections/CollectionTreeView";
+import { returnTrue, emptyFunction, returnFalse, returnOne, emptyPath } from "../../Utils";
+import { Transform } from "../util/Transform";
+import { ScriptField, ComputedField } from "../../new_fields/ScriptField";
+import { Scripting } from "../util/Scripting";
@observer
class TemplateToggle extends React.Component<{ template: Template, checked: boolean, toggle: (event: React.ChangeEvent<HTMLInputElement>, template: Template) => void }> {
@@ -50,7 +55,10 @@ export class TemplateMenu extends React.Component<TemplateMenuProps> {
@observable private _hidden: boolean = true;
toggleLayout = (e: React.ChangeEvent<HTMLInputElement>, layout: string): void => {
- this.props.docViews.map(dv => dv.switchViews(e.target.checked, layout));//.setCustomView(e.target.checked, layout));
+ this.props.docViews.map(dv => dv.switchViews(e.target.checked, layout));
+ }
+ toggleDefault = (e: React.ChangeEvent<HTMLInputElement>): void => {
+ this.props.docViews.map(dv => dv.switchViews(false, "layout"));
}
toggleFloat = (e: React.ChangeEvent<HTMLInputElement>): void => {
@@ -94,27 +102,81 @@ export class TemplateMenu extends React.Component<TemplateMenuProps> {
Array.from(Object.keys(Doc.GetProto(this.props.docViews[0].props.Document))).
filter(key => key.startsWith("layout_")).
map(key => runInAction(() => this._addedKeys.add(key.replace("layout_", ""))));
- DocListCast(Cast(CurrentUserUtils.UserDocument.expandingButtons, Doc, null)?.data)?.map(btnDoc => {
- if (StrCast(Cast(btnDoc?.dragFactory, Doc, null)?.title)) {
- runInAction(() => this._addedKeys.add(StrCast(Cast(btnDoc?.dragFactory, Doc, null)?.title)));
- }
- });
}
+ return100 = () => 100;
+ @computed get scriptField() {
+ return ScriptField.MakeScript("switchView(firstDoc, this)", { this: Doc.name, heading: "string", checked: "string", containingTreeView: Doc.name, firstDoc: Doc.name },
+ { firstDoc: this.props.docViews[0].props.Document });
+ }
render() {
- const layout = Doc.Layout(this.props.docViews[0].Document);
+ const firstDoc = this.props.docViews[0].props.Document;
+ const templateName = StrCast(firstDoc.layoutKey, "layout").replace("layout_", "");
+ const noteTypesDoc = Cast(Doc.UserDoc().noteTypes, Doc, null);
+ const noteTypes = DocListCast(noteTypesDoc?.data);
+ const addedTypes = DocListCast(Cast(Doc.UserDoc().templateButtons, Doc, null)?.data)
+ const layout = Doc.Layout(firstDoc);
const templateMenu: Array<JSX.Element> = [];
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={this.props.docViews[0].Document._showAudio ? true : false} toggle={this.toggleAudio} />);
- templateMenu.push(<OtherToggle key={"float"} name={"Float"} checked={this.props.docViews[0].Document.z ? true : false} toggle={this.toggleFloat} />);
+ 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} />);
- this._addedKeys && Array.from(this._addedKeys).map(layout =>
- templateMenu.push(<OtherToggle key={layout} name={layout} checked={StrCast(this.props.docViews[0].Document.layoutKey, "layout") === "layout_" + layout} toggle={e => this.toggleLayout(e, layout)} />)
- );
+ templateMenu.push(<OtherToggle key={"default"} name={"Default"} checked={templateName === "layout"} toggle={this.toggleDefault} />);
+ if (noteTypesDoc) {
+ addedTypes.concat(noteTypes).map(template => template.treeViewChecked = ComputedField.MakeFunction("templateIsUsed(this, firstDoc)", { firstDoc: "string" }, { firstDoc: StrCast(firstDoc.title) }));
+ this._addedKeys && Array.from(this._addedKeys).filter(key => !noteTypes.some(nt => nt.title === key)).forEach(template => templateMenu.push(
+ <OtherToggle key={template} name={template} checked={templateName === template} toggle={e => this.toggleLayout(e, template)} />));
+ templateMenu.push(
+ <CollectionTreeView
+ Document={Doc.UserDoc().templateDocs as Doc}
+ CollectionView={undefined}
+ ContainingCollectionDoc={undefined}
+ ContainingCollectionView={undefined}
+ onCheckedClick={this.scriptField!}
+ onChildClick={this.scriptField!}
+ LibraryPath={emptyPath}
+ dropAction={undefined}
+ active={returnTrue}
+ ContentScaling={returnOne}
+ bringToFront={emptyFunction}
+ focus={emptyFunction}
+ whenActiveChanged={emptyFunction}
+ ScreenToLocalTransform={Transform.Identity}
+ isSelected={returnFalse}
+ pinToPres={emptyFunction}
+ select={emptyFunction}
+ renderDepth={1}
+ addDocTab={returnFalse}
+ PanelWidth={this.return100}
+ PanelHeight={this.return100}
+ treeViewHideHeaderFields={true}
+ annotationsKey={""}
+ dontRegisterView={true}
+ fieldKey={"data"}
+ moveDocument={(doc: Doc) => false}
+ removeDocument={(doc: Doc) => false}
+ addDocument={(doc: Doc) => false} />
+ );
+ }
return <ul className="template-list" style={{ display: "block" }}>
- {templateMenu}
<input placeholder="+ layout" ref={this._customRef} onKeyPress={this.onCustomKeypress}></input>
+ {templateMenu}
</ul>;
}
-} \ No newline at end of file
+}
+
+Scripting.addGlobal(function switchView(doc: Doc, template: Doc) {
+ if (template.dragFactory) {
+ template = Cast(template.dragFactory, Doc, null);
+ }
+ let templateTitle = StrCast(template?.title);
+ return templateTitle && DocumentView.makeCustomViewClicked(doc, undefined, Docs.Create.FreeformDocument, templateTitle, template)
+});
+
+Scripting.addGlobal(function templateIsUsed(templateDoc: Doc, firstDocTitlte: string) {
+ const firstDoc = SelectionManager.SelectedDocuments()[0].props.Document;
+ const template = StrCast(templateDoc.dragFactory ? Cast(templateDoc.dragFactory, Doc, null)?.title : templateDoc.title);
+ return StrCast(firstDoc.layoutKey) === "layout_" + template ? 'check' : 'unchecked';
+ // return SelectionManager.SelectedDocuments().some(view => StrCast(view.props.Document.layoutKey) === "layout_" + template) ? 'check' : 'unchecked'
+}) \ No newline at end of file
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index 00e22d6fb..1fb78f625 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -2,7 +2,7 @@ import { library } from '@fortawesome/fontawesome-svg-core';
import { faFile } from '@fortawesome/free-solid-svg-icons';
import 'golden-layout/src/css/goldenlayout-base.css';
import 'golden-layout/src/css/goldenlayout-dark-theme.css';
-import { action, computed, Lambda, observable, reaction, runInAction } from "mobx";
+import { action, computed, Lambda, observable, reaction, runInAction, trace } from "mobx";
import { observer } from "mobx-react";
import * as ReactDOM from 'react-dom';
import Measure from "react-measure";
@@ -20,7 +20,7 @@ import { DocServer } from "../../DocServer";
import { Docs } from '../../documents/Documents';
import { DocumentType } from '../../documents/DocumentTypes';
import { DocumentManager } from '../../util/DocumentManager';
-import { DragManager } from "../../util/DragManager";
+import { DragManager, dropActionType } from "../../util/DragManager";
import { Scripting } from '../../util/Scripting';
import { SelectionManager } from '../../util/SelectionManager';
import { Transform } from '../../util/Transform';
@@ -504,15 +504,25 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp
}
tab.setActive(true);
};
- ReactDOM.render(<span title="Drag as document"
- className="collectionDockingView-dragAsDocument"
- onPointerDown={e => {
+ const onDown = (e: React.PointerEvent) => {
+ if (!(e.nativeEvent as any).defaultPrevented) {
e.preventDefault();
e.stopPropagation();
const dragData = new DragManager.DocumentDragData([doc]);
- dragData.dropAction = doc.dropAction === "alias" ? "alias" : doc.dropAction === "copy" ? "copy" : undefined;
+ dragData.dropAction = doc.dropAction as dropActionType;
DragManager.StartDocumentDrag([gearSpan], dragData, e.clientX, e.clientY);
- }}><DockingViewButtonSelector Document={doc} Stack={stack} /></span>, gearSpan);
+ }
+ }
+ let rendered = false;
+ tab.buttonDisposer = reaction(() => ((view: Opt<DocumentView>) => view ? [view] : [])(DocumentManager.Instance.getDocumentView(doc)),
+ (views) => {
+ !rendered && ReactDOM.render(<span title="Drag as document" className="collectionDockingView-dragAsDocument" onPointerDown={onDown} >
+ <DockingViewButtonSelector views={views} Stack={stack} />
+ </span>,
+ gearSpan);
+ rendered = true;
+ });
+
tab.reactComponents = [gearSpan];
tab.element.append(gearSpan);
tab.reactionDisposer = reaction(() => ({ title: doc.title, degree: Doc.IsBrushedDegree(doc) }), ({ title, degree }) => {
@@ -526,7 +536,8 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp
}
tab.closeElement.off('click') //unbind the current click handler
.click(async function () {
- tab.reactionDisposer && tab.reactionDisposer();
+ tab.reactionDisposer?.();
+ tab.buttonDisposer?.();
const doc = await DocServer.GetRefField(tab.contentItem.config.props.documentId);
if (doc instanceof Doc) {
const theDoc = doc;
diff --git a/src/client/views/collections/CollectionLinearView.tsx b/src/client/views/collections/CollectionLinearView.tsx
index 79ec6d518..344605412 100644
--- a/src/client/views/collections/CollectionLinearView.tsx
+++ b/src/client/views/collections/CollectionLinearView.tsx
@@ -31,7 +31,7 @@ export class CollectionLinearView extends CollectionSubView(LinearDocument) {
this._dropDisposer && this._dropDisposer();
this._widthDisposer && this._widthDisposer();
this._selectedDisposer && this._selectedDisposer();
- this.childLayoutPairs.filter((pair) => this.isCurrent(pair.layout)).map((pair, ind) => {
+ this.childLayoutPairs.map((pair, ind) => {
Cast(pair.layout.proto?.onPointerUp, ScriptField)?.script.run({ this: pair.layout.proto }, console.log);
});
}
@@ -48,7 +48,7 @@ export class CollectionLinearView extends CollectionSubView(LinearDocument) {
(i) => runInAction(() => {
this._selectedIndex = i;
let selected: any = undefined;
- this.childLayoutPairs.filter((pair) => this.isCurrent(pair.layout)).map(async (pair, ind) => {
+ this.childLayoutPairs.map(async (pair, ind) => {
const isSelected = this._selectedIndex === ind;
if (isSelected) {
selected = pair;
@@ -71,8 +71,6 @@ export class CollectionLinearView extends CollectionSubView(LinearDocument) {
}
}
- public isCurrent(doc: Doc) { return (Math.abs(NumCast(doc.displayTimecode, -1) - NumCast(this.Document.currentTimecode, -1)) < 1.5 || NumCast(doc.displayTimecode, -1) === -1); }
-
dimension = () => NumCast(this.props.Document._height); // 2 * the padding
getTransform = (ele: React.RefObject<HTMLDivElement>) => () => {
if (!ele.current) return Transform.Identity();
@@ -87,17 +85,21 @@ export class CollectionLinearView extends CollectionSubView(LinearDocument) {
<div className="collectionLinearView" ref={this.createDashEventsTarget} >
<input id={`${guid}`} type="checkbox" checked={BoolCast(this.props.Document.linearViewIsExpanded)} ref={this.addMenuToggle}
onChange={action((e: any) => this.props.Document.linearViewIsExpanded = this.addMenuToggle.current!.checked)} />
- <label htmlFor={`${guid}`} style={{ marginTop: "auto", marginBottom: "auto", background: StrCast(this.props.Document.backgroundColor, "black") === StrCast(this.props.Document.color, "white") ? "black" : StrCast(this.props.Document.backgroundColor, "black") }} title="Close Menu"><p>+</p></label>
+ <label htmlFor={`${guid}`} title="Close Menu" style={{ marginTop: "auto", marginBottom: "auto",
+ background: StrCast(this.props.Document.backgroundColor, "black") === StrCast(this.props.Document.color, "white") ? "black" : StrCast(this.props.Document.backgroundColor, "black") }} >
+ <p>+</p>
+ </label>
- <div className="collectionLinearView-content" style={{ height: this.dimension(), width: NumCast(this.props.Document._width, 25), flexDirection: flexDir }}>
- {this.childLayoutPairs.filter((pair) => this.isCurrent(pair.layout)).map((pair, ind) => {
+ <div className="collectionLinearView-content" style={{ height: this.dimension(), flexDirection: flexDir }}>
+ {this.childLayoutPairs.map((pair, ind) => {
const nested = pair.layout._viewType === CollectionViewType.Linear;
const dref = React.createRef<HTMLDivElement>();
const nativeWidth = NumCast(pair.layout._nativeWidth, this.dimension());
const deltaSize = nativeWidth * .15 / 2;
- return <div className={`collectionLinearView-docBtn` + (pair.layout.onClick || pair.layout.onDragStart ? "-scalable" : "")} key={pair.layout[Id]} ref={dref}
+ const scalable = pair.layout.onClick || pair.layout.onDragStart;
+ return <div className={`collectionLinearView-docBtn` + (scalable ? "-scalable" : "")} key={pair.layout[Id]} ref={dref}
style={{
- width: nested ? pair.layout[WidthSym]() : this.dimension() - deltaSize,
+ width: scalable ? (nested ? pair.layout[WidthSym]() : this.dimension() - deltaSize) : undefined,
height: nested && pair.layout.linearViewIsExpanded ? pair.layout[HeightSym]() : this.dimension() - deltaSize,
}} >
<DocumentView
diff --git a/src/client/views/collections/CollectionTreeView.scss b/src/client/views/collections/CollectionTreeView.scss
index fd4a963c3..5efd97a6b 100644
--- a/src/client/views/collections/CollectionTreeView.scss
+++ b/src/client/views/collections/CollectionTreeView.scss
@@ -22,6 +22,7 @@
ul {
list-style: none;
padding-left: 20px;
+ margin-bottom: 1px;// otherwise vertical scrollbars may pop up for no apparent reason....
}
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 8af4b6dfd..53df7f041 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -778,7 +778,12 @@ export class CollectionTreeView extends CollectionSubView(Document, undefined as
const childDocs = this.props.overrideDocuments ? this.props.overrideDocuments : this.childDocs;
return !childDocs ? (null) : (
<div className="collectionTreeView-dropTarget" id="body"
- style={{ background: this.props.backgroundColor?.(this.props.Document), paddingTop: `${NumCast(this.props.Document._yMargin, 20)}px` }}
+ style={{
+ background: this.props.backgroundColor?.(this.props.Document),
+ paddingLeft: `${NumCast(this.props.Document._xPadding, 10)}px`,
+ paddingRight: `${NumCast(this.props.Document._xPadding, 10)}px`,
+ paddingTop: `${NumCast(this.props.Document._yPadding, 20)}px`
+ }}
onContextMenu={this.onContextMenu}
onWheel={(e: React.WheelEvent) => this._mainEle && this._mainEle.scrollHeight > this._mainEle.clientHeight && e.stopPropagation()}
onDrop={this.onTreeDrop}
diff --git a/src/client/views/collections/ParentDocumentSelector.tsx b/src/client/views/collections/ParentDocumentSelector.tsx
index 43ba5c614..35e3a8958 100644
--- a/src/client/views/collections/ParentDocumentSelector.tsx
+++ b/src/client/views/collections/ParentDocumentSelector.tsx
@@ -2,7 +2,7 @@ import * as React from "react";
import './ParentDocumentSelector.scss';
import { Doc } from "../../../new_fields/Doc";
import { observer } from "mobx-react";
-import { observable, action, runInAction } from "mobx";
+import { observable, action, runInAction, trace, computed } from "mobx";
import { Id } from "../../../new_fields/FieldSymbols";
import { SearchUtil } from "../../util/SearchUtil";
import { CollectionDockingView } from "./CollectionDockingView";
@@ -14,6 +14,7 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faCog, faChevronCircleUp } from "@fortawesome/free-solid-svg-icons";
import { library } from "@fortawesome/fontawesome-svg-core";
import { DocumentView } from "../nodes/DocumentView";
+import { SelectionManager } from "../../util/SelectionManager";
const higflyout = require("@hig/flyout");
export const { anchorPoints } = higflyout;
export const Flyout = higflyout.default;
@@ -22,7 +23,6 @@ library.add(faCog);
type SelectorProps = {
Document: Doc,
- Views: DocumentView[],
Stack?: any,
addDocTab(doc: Doc, location: string): void
};
@@ -93,7 +93,7 @@ export class ParentDocSelector extends React.Component<SelectorProps> {
}
@observer
-export class DockingViewButtonSelector extends React.Component<{ Document: Doc, Stack: any }> {
+export class DockingViewButtonSelector extends React.Component<{ views: DocumentView[], Stack: any }> {
@observable hover = false;
customStylesheet(styles: any) {
@@ -106,15 +106,19 @@ export class DockingViewButtonSelector extends React.Component<{ Document: Doc,
};
}
- render() {
- const view = DocumentManager.Instance.getDocumentView(this.props.Document);
- const flyout = (
+ @computed get flyout() {
+ trace();
+ return (
<div className="ParentDocumentSelector-flyout" title=" ">
- <DocumentButtonBar views={[view]} stack={this.props.Stack} />
+ <DocumentButtonBar views={this.props.views} stack={this.props.Stack} />
</div>
);
- return <span title="Tap for menu, drag tab as document" onPointerDown={e => !this.props.Stack && e.stopPropagation()} className="buttonSelector">
- <Flyout anchorPoint={anchorPoints.LEFT_TOP} content={flyout} stylesheet={this.customStylesheet}>
+ }
+
+ render() {
+ trace();
+ return <span title="Tap for menu, drag tab as document" onPointerDown={e => { this.props.views[0].select(false); e.stopPropagation(); }} className="buttonSelector">
+ <Flyout anchorPoint={anchorPoints.LEFT_TOP} content={this.flyout} stylesheet={this.customStylesheet}>
<FontAwesomeIcon icon={"cog"} size={"sm"} />
</Flyout>
</span>;
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index 4bf3329eb..17bba9568 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -107,8 +107,14 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
});
} else if (!e.ctrlKey) {
FormattedTextBox.SelectOnLoadChar = FormattedTextBox.DefaultLayout ? e.key : "";
- this.props.addLiveTextDocument(
- Docs.Create.TextDocument("", { _width: NumCast((FormattedTextBox.DefaultLayout as Doc)?._width) || 200, _height: 100, layout: FormattedTextBox.DefaultLayout, x: x, y: y, _autoHeight: true, title: "-typed text-" }));
+ let tbox = Docs.Create.TextDocument("", { _width: 200, _height: 100, x: x, y: y, _autoHeight: true, title: "-typed text-" });
+ const template = FormattedTextBox.DefaultLayout;
+ if (template instanceof Doc) {
+ tbox._width = NumCast(template._width);
+ tbox.layoutKey = "layout_"+StrCast(template.title);
+ tbox[StrCast(tbox.layoutKey)] = template;
+ }
+ this.props.addLiveTextDocument(tbox);
}
e.stopPropagation();
}
@@ -334,7 +340,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
this.props.removeDocument(d);
d.x = NumCast(d.x) - bounds.left - bounds.width / 2;
d.y = NumCast(d.y) - bounds.top - bounds.height / 2;
- d.displayTimecode = undefined;
+ d.displayTimecode = undefined; // bcz: this should be automatic somehow.. along with any other properties that were logically associated with the original collection
return d;
});
}
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 874d075e6..9a7568518 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -516,7 +516,6 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
static makeCustomViewClicked = (doc: Doc, dataDoc: Opt<Doc>, creator: (documents: Array<Doc>, options: DocumentOptions, id?: string) => Doc, name: string = "custom", docLayoutTemplate?: Doc) => {
const batch = UndoManager.StartBatch("CustomViewClicked");
const customName = "layout_" + name;
- if (!StrCast(doc.title).endsWith(name)) doc.title = doc.title + "_" + name;
if (doc[customName] === undefined) {
const _width = NumCast(doc._width);
const _height = NumCast(doc._height);
@@ -634,13 +633,15 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
// } else
if (custom) {
DocumentView.makeNativeViewClicked(this.props.Document);
+ const userDoc = Doc.UserDoc();
- const imgView = Cast(Doc.UserDoc().iconView, Doc, null);
- const iconImgView = Cast(Doc.UserDoc().iconImageView, Doc, null);
- const iconColView = Cast(Doc.UserDoc().iconColView, Doc, null);
+ const imgView = Cast(userDoc.iconView, Doc, null);
+ const iconImgView = Cast(userDoc.iconImageView, Doc, null);
+ const iconColView = Cast(userDoc.iconColView, Doc, null);
const iconViews = [imgView, iconImgView, iconColView];
- const expandingButtons = DocListCast(Cast(Doc.UserDoc().expandingButtons, Doc, null)?.data);
- const allTemplates = iconViews.concat(expandingButtons);
+ const templateButtons = DocListCast(Cast(userDoc.templateButtons, Doc, null)?.data);
+ const noteTypes = DocListCast(Cast(userDoc.noteTypes, Doc, null)?.data);
+ const allTemplates = iconViews.concat(templateButtons).concat(noteTypes);
let foundLayout: Opt<Doc>;
allTemplates.map(btnDoc => (btnDoc.dragFactory as Doc) || btnDoc).filter(doc => doc.isTemplateDoc).forEach(tempDoc => {
if (StrCast(tempDoc.title) === this.props.Document.type + "_" + layout) {
@@ -1028,7 +1029,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
</div>);
const captionView = (!showCaption ? (null) :
<div className="documentView-captionWrapper">
- <FormattedTextBox {...this.props} onClick={this.onClickHandler}
+ <FormattedTextBox {...this.props} onClick={this.onClickHandler} dropAction="alias"
DataDoc={this._dataDoc} active={returnTrue} Document={this._layoutDoc || this.props.Document}
isSelected={this.isSelected} focus={emptyFunction} select={this.select}
hideOnLeave={true} fieldKey={showCaption}
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 1fa603cbd..e7c9e5e6b 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -47,6 +47,7 @@ import "./FormattedTextBox.scss";
import { FormattedTextBoxComment, formattedTextBoxCommentPlugin } from './FormattedTextBoxComment';
import React = require("react");
import { PrefetchProxy } from '../../../new_fields/Proxy';
+import { makeTemplate } from '../../util/DropConverter';
library.add(faEdit);
library.add(faSmile, faTextHeight, faUpload);
@@ -249,7 +250,7 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
}
protected createDropTarget = (ele: HTMLDivElement) => {
this.ProseRef = ele;
- this.dropDisposer && this.dropDisposer();
+ this.dropDisposer?.();
ele && (this.dropDisposer = DragManager.MakeDropTarget(ele, this.drop.bind(this)));
}
@@ -386,9 +387,14 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
}
specificContextMenu = (e: React.MouseEvent): void => {
const funcs: ContextMenuProps[] = [];
- this.props.Document.isTemplateDoc && funcs.push({ description: "Make Default Layout", event: async () => Doc.UserDoc().defaultTextLayout = new PrefetchProxy(this.props.Document.proto as Doc), icon: "eye" });
+ this.props.Document.isTemplateDoc && funcs.push({ description: "Make Default Layout", event: async () => Doc.UserDoc().defaultTextLayout = new PrefetchProxy(this.props.Document), icon: "eye" });
funcs.push({ description: "Reset Default Layout", event: () => Doc.UserDoc().defaultTextLayout = undefined, icon: "eye" });
- !this.props.Document.expandedTemplate && funcs.push({ description: "Make Template", event: () => { this.props.Document.isTemplateDoc = true; Doc.AddDocToList(Cast(Doc.UserDoc().noteTypes, Doc, null), "data", this.props.Document); }, icon: "eye" });
+ !this.props.Document.expandedTemplate && funcs.push({
+ description: "Make Template", event: () => {
+ this.props.Document.isTemplateDoc = makeTemplate(this.props.Document, true);
+ Doc.AddDocToList(Cast(Doc.UserDoc().noteTypes, Doc, null), "data", this.props.Document);
+ }, icon: "eye"
+ });
funcs.push({ description: "Toggle Single Line", event: () => this.props.Document._singleLine = !this.props.Document._singleLine, icon: "expand-arrows-alt" });
funcs.push({ description: "Toggle Sidebar", event: () => this.props.Document._showSidebar = !this.props.Document._showSidebar, icon: "expand-arrows-alt" });
funcs.push({ description: "Toggle Audio", event: () => this.props.Document._showAudio = !this.props.Document._showAudio, icon: "expand-arrows-alt" });
@@ -901,6 +907,7 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
if (e.buttons === 1 && this.props.isSelected(true) && !e.altKey) {
e.stopPropagation();
}
+ this._downX = this._downY = Number.NaN;
}
@action
@@ -914,12 +921,16 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
prosediv && (prosediv.keeplocation = undefined);
const pos = this._editorView?.state.selection.$from.pos || 1;
keeplocation && setTimeout(() => this._editorView?.dispatch(this._editorView?.state.tr.setSelection(TextSelection.create(this._editorView.state.doc, pos))));
+ const coords = !Number.isNaN(this._downX) ? { left: this._downX, top: this._downY, bottom: this._downY, right: this._downX } : this._editorView?.coordsAtPos(pos);
// jump rich text menu to this textbox
- const { current } = this._ref;
- if (current && this.props.Document._chromeStatus !== "disabled") {
- const x = Math.min(Math.max(current.getBoundingClientRect().left, 0), window.innerWidth - RichTextMenu.Instance.width);
- const y = this._ref.current!.getBoundingClientRect().top - RichTextMenu.Instance.height - 50;
+ const bounds = this._ref.current?.getBoundingClientRect();
+ if (bounds && this.props.Document._chromeStatus !== "disabled") {
+ const x = Math.min(Math.max(bounds.left, 0), window.innerWidth - RichTextMenu.Instance.width);
+ let y = Math.min(Math.max(0, bounds.top - RichTextMenu.Instance.height - 50), window.innerHeight - RichTextMenu.Instance.height);
+ if (coords && coords.left > x && coords.left < x + RichTextMenu.Instance.width && coords.top > y && coords.top < y + RichTextMenu.Instance.height + 50) {
+ y = Math.min(bounds.bottom, window.innerHeight - RichTextMenu.Instance.height);
+ }
RichTextMenu.Instance.jumpTo(x, y);
}
}
diff --git a/src/client/views/search/SearchItem.tsx b/src/client/views/search/SearchItem.tsx
index 2cbb24da7..63cef5101 100644
--- a/src/client/views/search/SearchItem.tsx
+++ b/src/client/views/search/SearchItem.tsx
@@ -272,7 +272,7 @@ export class SearchItem extends React.Component<SearchItemProps> {
@computed
get contextButton() {
- return <ParentDocSelector Views={DocumentManager.Instance.DocumentViews} Document={this.props.doc} addDocTab={(doc, where) => CollectionDockingView.AddRightSplit(doc)} />;
+ return <ParentDocSelector Document={this.props.doc} addDocTab={(doc, where) => CollectionDockingView.AddRightSplit(doc)} />;
}
render() {
diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts
index 50adf0392..322b57272 100644
--- a/src/new_fields/Doc.ts
+++ b/src/new_fields/Doc.ts
@@ -795,8 +795,6 @@ export namespace Doc {
const prevLayout = StrCast(doc.layoutKey).split("_")[1];
const deiconify = prevLayout === "icon" && StrCast(doc.deiconifyLayout) ? "layout_" + StrCast(doc.deiconifyLayout) : "";
prevLayout === "icon" && (doc.deiconifyLayout = undefined);
- if (StrCast(doc.title).endsWith("_" + prevLayout) && deiconify) doc.title = StrCast(doc.title).replace("_" + prevLayout, deiconify);
- else doc.title = undefined;
doc.layoutKey = deiconify || "layout";
}
export function setDocFilterRange(target: Doc, key: string, range?: number[]) {
diff --git a/src/new_fields/ScriptField.ts b/src/new_fields/ScriptField.ts
index 9288fea9e..606f55b7c 100644
--- a/src/new_fields/ScriptField.ts
+++ b/src/new_fields/ScriptField.ts
@@ -119,8 +119,8 @@ export class ScriptField extends ObjectField {
return compiled.compiled ? new ScriptField(compiled) : undefined;
}
- public static MakeScript(script: string, params: object = {}) {
- const compiled = ScriptField.CompileScript(script, params, false);
+ public static MakeScript(script: string, params: object = {}, capturedVariables?: { [name: string]: Field }) {
+ const compiled = ScriptField.CompileScript(script, params, false, capturedVariables);
return compiled.compiled ? new ScriptField(compiled) : undefined;
}
}
diff --git a/src/new_fields/util.ts b/src/new_fields/util.ts
index 6d7f6b56e..3ab1b299b 100644
--- a/src/new_fields/util.ts
+++ b/src/new_fields/util.ts
@@ -7,7 +7,6 @@ import { ObjectField } from "./ObjectField";
import { action, trace } from "mobx";
import { Parent, OnUpdate, Update, Id, SelfProxy, Self } from "./FieldSymbols";
import { DocServer } from "../client/DocServer";
-import { props } from "bluebird";
function _readOnlySetter(): never {
throw new Error("Documents can't be modified in read-only mode");
diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts
index 31588bf82..9c39ce7de 100644
--- a/src/server/authentication/models/current_user_utils.ts
+++ b/src/server/authentication/models/current_user_utils.ts
@@ -53,7 +53,7 @@ export class CurrentUserUtils {
];
doc.fieldTypes = Docs.Create.TreeDocument([], { title: "field enumerations" });
Doc.addFieldEnumerations(Doc.GetProto(noteTemplates[4]), "taskStatus", taskStatusValues);
- doc.noteTypes = new PrefetchProxy(Docs.Create.TreeDocument(noteTemplates.map(nt => makeTemplate(nt, true, StrCast(nt.style)) ? nt : nt), { title: "Note Types", _height: 75 }));
+ doc.noteTypes = new PrefetchProxy(Docs.Create.TreeDocument(noteTemplates.map(nt => makeTemplate(nt, true, StrCast(nt.style)) ? nt : nt), { title: "Note Layouts", _height: 75 }));
}
// setup the "creator" buttons for the sidebar-- eg. the default set of draggable document creation tools
@@ -292,12 +292,20 @@ export class CurrentUserUtils {
{ _nativeWidth: 100, _nativeHeight: 100, _width: 100, _height: 100, dropAction: "alias", onDragStart: ScriptField.MakeFunction('getCopy(this.dragFactory, true)'), dragFactory: slideTemplate, removeDropProperties: new List<string>(["dropAction"]), title: "presentation slide", icon: "sticky-note" });
doc.descriptionBtn = Docs.Create.FontIconDocument(
{ _nativeWidth: 100, _nativeHeight: 100, _width: 100, _height: 100, dropAction: "alias", onDragStart: ScriptField.MakeFunction('getCopy(this.dragFactory, true)'), dragFactory: descriptionTemplate, removeDropProperties: new List<string>(["dropAction"]), title: "description view", icon: "sticky-note" });
- doc.expandingButtons = Docs.Create.LinearDocument([doc.undoBtn as Doc, doc.redoBtn as Doc, doc.slidesBtn as Doc, doc.descriptionBtn as Doc,
- ...DocListCast(Cast(doc.noteTypes, Doc, null))], {
+ doc.templateButtons = Docs.Create.LinearDocument([doc.slidesBtn as Doc, doc.descriptionBtn as Doc], {
+ title: "template buttons", _gridGap: 5, _xMargin: 5, _yMargin: 5, _height: 42, _width: 100, boxShadow: "0 0", dontSelect: true,
+ backgroundColor: "black", treeViewPreventOpen: true, forceActive: true, lockedPosition: true, _chromeStatus: "disabled", linearViewIsExpanded: true,
+ dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name })
+ });
+ doc.expandingButtons = Docs.Create.LinearDocument([doc.undoBtn as Doc, doc.redoBtn as Doc, doc.templateButtons as Doc], {
title: "expanding buttons", _gridGap: 5, _xMargin: 5, _yMargin: 5, _height: 42, _width: 100, boxShadow: "0 0",
- backgroundColor: "black", treeViewPreventOpen: true, forceActive: true, lockedPosition: true,
+ backgroundColor: "black", treeViewPreventOpen: true, forceActive: true, lockedPosition: true, linearViewIsExpanded: true,
dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name })
});
+ doc.templateDocs = new PrefetchProxy(Docs.Create.TreeDocument([doc.noteTypes as Doc, doc.templateButtons as Doc], {
+ title: "template layouts", _xPadding: 0, dropConverter: ScriptField.MakeScript("convertToButtons(dragData)",
+ { dragData: DragManager.DocumentDragData.name })
+ }));
}
// sets up the default set of documents to be shown in the Overlay layer