aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/nodes
diff options
context:
space:
mode:
authorSam Wilkins <samwilkins333@gmail.com>2019-12-17 16:38:19 -0800
committerSam Wilkins <samwilkins333@gmail.com>2019-12-17 16:38:19 -0800
commit10843071eacf94b237d131a50df9c58352441814 (patch)
tree854ed4e91131d5f11c4526c0cd24056adf1de2e3 /src/client/views/nodes
parente553c4ac4785ee1d2c57ed5d5303d6dff26929f9 (diff)
parent96ada41d4c3c411be63bd656da65bba7894a4224 (diff)
Merge branch 'master' of https://github.com/browngraphicslab/Dash-Web
Diffstat (limited to 'src/client/views/nodes')
-rw-r--r--src/client/views/nodes/ContentFittingDocumentView.scss5
-rw-r--r--src/client/views/nodes/ContentFittingDocumentView.tsx26
-rw-r--r--src/client/views/nodes/DocumentBox.scss15
-rw-r--r--src/client/views/nodes/DocumentBox.tsx111
-rw-r--r--src/client/views/nodes/DocumentContentsView.tsx3
-rw-r--r--src/client/views/nodes/DocumentView.tsx63
-rw-r--r--src/client/views/nodes/FormattedTextBox.tsx3
-rw-r--r--src/client/views/nodes/ImageBox.tsx1
-rw-r--r--src/client/views/nodes/KeyValueBox.tsx2
-rw-r--r--src/client/views/nodes/KeyValuePair.tsx1
10 files changed, 197 insertions, 33 deletions
diff --git a/src/client/views/nodes/ContentFittingDocumentView.scss b/src/client/views/nodes/ContentFittingDocumentView.scss
index 796e67269..2801af441 100644
--- a/src/client/views/nodes/ContentFittingDocumentView.scss
+++ b/src/client/views/nodes/ContentFittingDocumentView.scss
@@ -2,10 +2,11 @@
.contentFittingDocumentView {
position: relative;
- height: auto !important;
+ display: flex;
+ align-items: center;
.contentFittingDocumentView-previewDoc {
- position: absolute;
+ position: relative;
display: inline;
}
diff --git a/src/client/views/nodes/ContentFittingDocumentView.tsx b/src/client/views/nodes/ContentFittingDocumentView.tsx
index 5e3306a11..2f8142a44 100644
--- a/src/client/views/nodes/ContentFittingDocumentView.tsx
+++ b/src/client/views/nodes/ContentFittingDocumentView.tsx
@@ -31,9 +31,9 @@ interface ContentFittingDocumentViewProps {
CollectionDoc?: Doc;
onClick?: ScriptField;
getTransform: () => Transform;
- addDocument: (document: Doc) => boolean;
- moveDocument: (document: Doc, target: Doc | undefined, addDoc: ((doc: Doc) => boolean)) => boolean;
- removeDocument: (document: Doc) => boolean;
+ addDocument?: (document: Doc) => boolean;
+ moveDocument?: (document: Doc, target: Doc | undefined, addDoc: ((doc: Doc) => boolean)) => boolean;
+ removeDocument?: (document: Doc) => boolean;
active: (outsideReaction: boolean) => boolean;
whenActiveChanged: (isActive: boolean) => void;
addDocTab: (document: Doc, dataDoc: Doc | undefined, where: string) => boolean;
@@ -47,8 +47,8 @@ interface ContentFittingDocumentViewProps {
export class ContentFittingDocumentView extends React.Component<ContentFittingDocumentViewProps>{
public get displayName() { return "DocumentView(" + this.props.Document?.title + ")"; } // this makes mobx trace() statements more descriptive
private get layoutDoc() { return this.props.Document && Doc.Layout(this.props.Document); }
- private get nativeWidth() { return NumCast(this.layoutDoc!.nativeWidth, this.props.PanelWidth()); }
- private get nativeHeight() { return NumCast(this.layoutDoc!.nativeHeight, this.props.PanelHeight()); }
+ private get nativeWidth() { return NumCast(this.layoutDoc?.nativeWidth, this.props.PanelWidth()); }
+ private get nativeHeight() { return NumCast(this.layoutDoc?.nativeHeight, this.props.PanelHeight()); }
private contentScaling = () => {
const wscale = this.props.PanelWidth() / (this.nativeWidth ? this.nativeWidth : this.props.PanelWidth());
if (wscale * this.nativeHeight > this.props.PanelHeight()) {
@@ -73,21 +73,25 @@ export class ContentFittingDocumentView extends React.Component<ContentFittingDo
}
private PanelWidth = () => this.nativeWidth && (!this.props.Document || !this.props.Document.fitWidth) ? this.nativeWidth * this.contentScaling() : this.props.PanelWidth();
private PanelHeight = () => this.nativeHeight && (!this.props.Document || !this.props.Document.fitWidth) ? this.nativeHeight * this.contentScaling() : this.props.PanelHeight();
- private getTransform = () => this.props.getTransform().translate(-this.centeringOffset, 0).scale(1 / this.contentScaling());
+ private getTransform = () => this.props.getTransform().translate(-this.centeringOffset, -this.centeringYOffset).scale(1 / this.contentScaling());
private get centeringOffset() { return this.nativeWidth && (!this.props.Document || !this.props.Document.fitWidth) ? (this.props.PanelWidth() - this.nativeWidth * this.contentScaling()) / 2 : 0; }
+ private get centeringYOffset() { return Math.abs(this.centeringOffset) < 0.001 ? (this.props.PanelHeight() - this.nativeHeight * this.contentScaling()) / 2 : 0; }
- @computed get borderRounding() { return StrCast(this.props.Document!.borderRounding); }
+ @computed get borderRounding() { return StrCast(this.props.Document?.borderRounding); }
render() {
TraceMobx();
- return (<div className="contentFittingDocumentView" style={{ width: this.props.PanelWidth(), height: this.props.PanelHeight() }}>
+ return (<div className="contentFittingDocumentView" style={{
+ width: Math.abs(this.centeringYOffset) > 0.001 ? "auto" : this.props.PanelWidth(),
+ height: Math.abs(this.centeringOffset) > 0.0001 ? "auto" : this.props.PanelHeight()
+ }}>
{!this.props.Document || !this.props.PanelWidth ? (null) : (
<div className="contentFittingDocumentView-previewDoc"
style={{
transform: `translate(${this.centeringOffset}px, 0px)`,
borderRadius: this.borderRounding,
- height: this.props.PanelHeight(),
- width: `${100 * (this.props.PanelWidth() - this.centeringOffset * 2) / this.props.PanelWidth()}%`
+ height: Math.abs(this.centeringYOffset) > 0.001 ? `${100 * this.nativeHeight / this.nativeWidth * this.props.PanelWidth() / this.props.PanelHeight()}%` : this.props.PanelHeight(),
+ width: Math.abs(this.centeringOffset) > 0.001 ? `${100 * (this.props.PanelWidth() - this.centeringOffset * 2) / this.props.PanelWidth()}%` : this.props.PanelWidth()
}}>
<DocumentView {...this.props}
Document={this.props.Document}
@@ -107,7 +111,7 @@ export class ContentFittingDocumentView extends React.Component<ContentFittingDo
pinToPres={this.props.pinToPres}
parentActive={this.props.active}
ScreenToLocalTransform={this.getTransform}
- renderDepth={this.props.renderDepth + 1}
+ renderDepth={this.props.renderDepth}
ContentScaling={this.contentScaling}
PanelWidth={this.PanelWidth}
PanelHeight={this.PanelHeight}
diff --git a/src/client/views/nodes/DocumentBox.scss b/src/client/views/nodes/DocumentBox.scss
new file mode 100644
index 000000000..b7d06b364
--- /dev/null
+++ b/src/client/views/nodes/DocumentBox.scss
@@ -0,0 +1,15 @@
+.documentBox-container {
+ width: 100%;
+ height: 100%;
+ pointer-events: all;
+ background: gray;
+ border: #00000021 solid 15px;
+ border-top: #0000005e inset 15px;
+ border-bottom: #0000005e outset 15px;
+ .documentBox-lock {
+ margin: auto;
+ color: white;
+ margin-top: -15px;
+ position: absolute;
+ }
+} \ No newline at end of file
diff --git a/src/client/views/nodes/DocumentBox.tsx b/src/client/views/nodes/DocumentBox.tsx
new file mode 100644
index 000000000..6be0289d7
--- /dev/null
+++ b/src/client/views/nodes/DocumentBox.tsx
@@ -0,0 +1,111 @@
+import { IReactionDisposer, reaction } from "mobx";
+import { observer } from "mobx-react";
+import { Doc, Field } from "../../../new_fields/Doc";
+import { documentSchema } from "../../../new_fields/documentSchemas";
+import { List } from "../../../new_fields/List";
+import { makeInterface } from "../../../new_fields/Schema";
+import { ComputedField } from "../../../new_fields/ScriptField";
+import { Cast, StrCast, BoolCast } from "../../../new_fields/Types";
+import { emptyFunction, emptyPath } from "../../../Utils";
+import { ContextMenu } from "../ContextMenu";
+import { ContextMenuProps } from "../ContextMenuItem";
+import { DocComponent } from "../DocComponent";
+import { ContentFittingDocumentView } from "./ContentFittingDocumentView";
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import "./DocumentBox.scss";
+import { FieldView, FieldViewProps } from "./FieldView";
+import React = require("react");
+
+type DocBoxSchema = makeInterface<[typeof documentSchema]>;
+const DocBoxDocument = makeInterface(documentSchema);
+
+@observer
+export class DocumentBox extends DocComponent<FieldViewProps, DocBoxSchema>(DocBoxDocument) {
+ public static LayoutString(fieldKey: string) { return FieldView.LayoutString(DocumentBox, fieldKey); }
+ _prevSelectionDisposer: IReactionDisposer | undefined;
+ _selections: Doc[] = [];
+ _curSelection = -1;
+ componentDidMount() {
+ this._prevSelectionDisposer = reaction(() => Cast(this.props.Document[this.props.fieldKey], Doc) as Doc, (data) => {
+ if (data && !this._selections.includes(data)) {
+ this._selections.length = ++this._curSelection;
+ this._selections.push(data);
+ }
+ });
+ }
+ specificContextMenu = (e: React.MouseEvent): void => {
+ const funcs: ContextMenuProps[] = [];
+ funcs.push({ description: (this.isSelectionLocked() ? "Show" : "Lock") + " Selection", event: () => this.toggleLockSelection, icon: "expand-arrows-alt" });
+ funcs.push({ description: `${this.props.Document.forceActive ? "Select" : "Force"} Contents Active`, event: () => this.props.Document.forceActive = !this.props.Document.forceActive, icon: "project-diagram" });
+
+ ContextMenu.Instance.addItem({ description: "DocumentBox Funcs...", subitems: funcs, icon: "asterisk" });
+ }
+ lockSelection = () => {
+ Doc.GetProto(this.props.Document)[this.props.fieldKey] = this.props.Document[this.props.fieldKey];
+ }
+ showSelection = () => {
+ Doc.GetProto(this.props.Document)[this.props.fieldKey] = ComputedField.MakeFunction("selectedDocs(this,true,[_last_])?.[0]");
+ }
+ isSelectionLocked = () => {
+ const kvpstring = Field.toKeyValueString(this.props.Document, this.props.fieldKey);
+ return !(kvpstring.startsWith("=") || kvpstring.startsWith(":="));
+ }
+ toggleLockSelection = () => {
+ !this.isSelectionLocked() ? this.lockSelection() : this.showSelection();
+ }
+ prevSelection = () => {
+ if (this._curSelection > 0) {
+ Doc.UserDoc().SelectedDocs = new List([this._selections[--this._curSelection]]);
+ }
+ }
+ nextSelection = () => {
+ if (this._curSelection < this._selections.length - 1 && this._selections.length) {
+ Doc.UserDoc().SelectedDocs = new List([this._selections[++this._curSelection]]);
+ }
+ }
+ onPointerDown = (e: React.PointerEvent) => {
+ }
+ onClick = (e: React.MouseEvent) => {
+ if (this._contRef.current!.getBoundingClientRect().top + 15 > e.clientY) this.toggleLockSelection();
+ else {
+ if (this._contRef.current!.getBoundingClientRect().left + 15 > e.clientX) this.prevSelection();
+ if (this._contRef.current!.getBoundingClientRect().right - 15 < e.clientX) this.nextSelection();
+ }
+ }
+ _contRef = React.createRef<HTMLDivElement>();
+ pwidth = () => this.props.PanelWidth() - 30;
+ pheight = () => this.props.PanelHeight() - 30;
+ getTransform = () => this.props.ScreenToLocalTransform().translate(-15, -15);
+ render() {
+ const containedDoc = this.props.Document[this.props.fieldKey] as Doc;
+ return <div className="documentBox-container" ref={this._contRef}
+ onContextMenu={this.specificContextMenu}
+ onPointerDown={this.onPointerDown} onClick={this.onClick}
+ style={{ background: StrCast(this.props.Document.backgroundColor) }}>
+ <div className="documentBox-lock">
+ <FontAwesomeIcon icon={this.isSelectionLocked() ? "lock" : "unlock"} size="sm" />
+ </div>
+ {!(containedDoc instanceof Doc) ? (null) : <ContentFittingDocumentView
+ Document={containedDoc}
+ DataDocument={undefined}
+ LibraryPath={emptyPath}
+ fitToBox={this.props.fitToBox}
+ addDocument={this.props.addDocument}
+ moveDocument={this.props.moveDocument}
+ removeDocument={this.props.removeDocument}
+ ruleProvider={this.props.ruleProvider}
+ addDocTab={this.props.addDocTab}
+ pinToPres={this.props.pinToPres}
+ getTransform={this.getTransform}
+ renderDepth={this.props.Document.forceActive ? 0 : this.props.renderDepth + 1} // bcz: really need to have an 'alwaysSelected' prop that's not conflated with renderDepth
+ PanelWidth={this.pwidth}
+ PanelHeight={this.pheight}
+ focus={this.props.focus}
+ active={this.props.active}
+ whenActiveChanged={this.props.whenActiveChanged}
+ setPreviewScript={emptyFunction}
+ previewScript={undefined}
+ />}
+ </div>;
+ }
+}
diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx
index 1bbc82119..8f6bfc8e1 100644
--- a/src/client/views/nodes/DocumentContentsView.tsx
+++ b/src/client/views/nodes/DocumentContentsView.tsx
@@ -14,6 +14,7 @@ import { LinkFollowBox } from "../linking/LinkFollowBox";
import { YoutubeBox } from "./../../apis/youtube/YoutubeBox";
import { AudioBox } from "./AudioBox";
import { ButtonBox } from "./ButtonBox";
+import { DocumentBox } from "./DocumentBox";
import { DocumentViewProps } from "./DocumentView";
import "./DocumentView.scss";
import { FontIconBox } from "./FontIconBox";
@@ -102,7 +103,7 @@ export class DocumentContentsView extends React.Component<DocumentViewProps & {
FormattedTextBox, ImageBox, IconBox, DirectoryImportBox, FontIconBox: FontIconBox, ButtonBox, FieldView,
CollectionFreeFormView, CollectionDockingView, CollectionSchemaView, CollectionView, WebBox, KeyValueBox,
PDFBox, VideoBox, AudioBox, HistogramBox, PresBox, YoutubeBox, LinkFollowBox, PresElementBox, QueryBox,
- ColorBox, DocuLinkBox, InkingStroke
+ ColorBox, DocuLinkBox, InkingStroke, DocumentBox
}}
bindings={this.CreateBindings()}
jsx={this.layout}
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index b096d68fc..8d3c3126d 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -43,6 +43,8 @@ import { InteractionUtils } from '../../util/InteractionUtils';
import { InkingControl } from '../InkingControl';
import { InkTool } from '../../../new_fields/InkField';
import { TraceMobx } from '../../../new_fields/util';
+import { List } from '../../../new_fields/List';
+import { FormattedTextBoxComment } from './FormattedTextBoxComment';
library.add(fa.faEdit, fa.faTrash, fa.faShare, fa.faDownload, fa.faExpandArrowsAlt, fa.faCompressArrowsAlt, fa.faLayerGroup, fa.faExternalLinkAlt, fa.faAlignCenter, fa.faCaretSquareRight,
fa.faSquare, fa.faConciergeBell, fa.faWindowRestore, fa.faFolder, fa.faMapPin, fa.faLink, fa.faFingerprint, fa.faCrosshairs, fa.faDesktop, fa.faUnlock, fa.faLock, fa.faLaptopCode, fa.faMale,
@@ -135,20 +137,42 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
}
}
+ 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;
+ undoBatch(action(() => topDoc.z = topDoc.z ? 0 : 1))();
+ 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 });
+ }
+ }, 0);
+ }
+
onKeyDown = (e: React.KeyboardEvent) => {
- if (e.altKey && (e.key === "†" || e.key === "t") && !(e.nativeEvent as any).StopPropagationForReal) {
+ if (e.altKey && !(e.nativeEvent as any).StopPropagationForReal) {
(e.nativeEvent as any).StopPropagationForReal = true; // e.stopPropagation() doesn't seem to work...
e.stopPropagation();
e.preventDefault();
- if (!StrCast(this.Document.showTitle)) this.Document.showTitle = "title";
- if (!this._titleRef.current) setTimeout(() => this._titleRef.current?.setIsFocused(true), 0);
- else if (!this._titleRef.current.setIsFocused(true)) { // if focus didn't change, focus on interior text...
- {
- this._titleRef.current?.setIsFocused(false);
- const any = (this._mainCont.current?.getElementsByClassName("ProseMirror")?.[0] as any);
- any.keeplocation = true;
- any?.focus();
+ if (e.key === "†" || e.key === "t") {
+ if (!StrCast(this.Document.showTitle)) this.Document.showTitle = "title";
+ if (!this._titleRef.current) setTimeout(() => this._titleRef.current?.setIsFocused(true), 0);
+ else if (!this._titleRef.current.setIsFocused(true)) { // if focus didn't change, focus on interior text...
+ {
+ this._titleRef.current?.setIsFocused(false);
+ const any = (this._mainCont.current?.getElementsByClassName("ProseMirror")?.[0] as any);
+ any.keeplocation = true;
+ any?.focus();
+ }
}
+ } else if (e.key === "f") {
+ const ex = (e.nativeEvent.target! as any).getBoundingClientRect().left;
+ const ey = (e.nativeEvent.target! as any).getBoundingClientRect().top;
+ DocumentView.FloatDoc(this, ex, ey);
}
}
}
@@ -170,6 +194,9 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
this.onClickHandler.script.run({ this: this.Document.isTemplateField && this.props.DataDoc ? this.props.DataDoc : this.props.Document }, console.log);
} else if (this.Document.type === DocumentType.BUTTON) {
ScriptBox.EditButtonScript("On Button Clicked ...", this.props.Document, "onClick", e.clientX, e.clientY);
+ } else if (this.props.Document.isButton === "Selector") { // this should be moved to an OnClick script
+ FormattedTextBoxComment.Hide();
+ this.Document.links?.[0] instanceof Doc && (Doc.UserDoc().SelectedDocs = new List([Doc.LinkOtherAnchor(this.Document.links[0]!, this.props.Document)]));
} else if (this.Document.isButton) {
SelectionManager.SelectDoc(this, e.ctrlKey); // don't think this should happen if a button action is actually triggered.
this.buttonClick(e.altKey, e.ctrlKey);
@@ -316,6 +343,17 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
}
@undoBatch
+ makeSelBtnClicked = (): void => {
+ if (this.Document.isButton || this.Document.onClick || this.Document.ignoreClick) {
+ this.Document.isButton = false;
+ this.Document.ignoreClick = false;
+ this.Document.onClick = undefined;
+ } else {
+ this.props.Document.isButton = "Selector";
+ }
+ }
+
+ @undoBatch
@action
drop = async (e: Event, de: DragManager.DropEvent) => {
if (de.complete.annoDragData) {
@@ -433,13 +471,8 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
onClicks.push({ description: "Toggle Detail", event: () => this.Document.onClick = ScriptField.MakeScript("toggleDetail(this)"), icon: "window-restore" });
onClicks.push({ description: this.Document.ignoreClick ? "Select" : "Do Nothing", event: () => this.Document.ignoreClick = !this.Document.ignoreClick, icon: this.Document.ignoreClick ? "unlock" : "lock" });
onClicks.push({ description: this.Document.isButton || this.Document.onClick ? "Remove Click Behavior" : "Follow Link", event: this.makeBtnClicked, icon: "concierge-bell" });
+ onClicks.push({ description: this.props.Document.isButton ? "Remove Select Link Behavior" : "Select Link", event: this.makeSelBtnClicked, icon: "concierge-bell" });
onClicks.push({ description: "Edit onClick Script", icon: "edit", event: (obj: any) => ScriptBox.EditButtonScript("On Button Clicked ...", this.props.Document, "onClick", obj.x, obj.y) });
- onClicks.push({
- description: "Edit onClick Foreach Doc Script", icon: "edit", event: (obj: any) => {
- this.props.Document.collectionContext = this.props.ContainingCollectionDoc;
- ScriptBox.EditButtonScript("Foreach Collection Doc (d) => ", this.props.Document, "onClick", obj.x, obj.y, "docList(this.collectionContext.data).map(d => {", "});\n");
- }
- });
!existingOnClick && cm.addItem({ description: "OnClick...", subitems: onClicks, icon: "hand-point-right" });
const funcs: ContextMenuProps[] = [];
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index a298fd6af..b19729811 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -822,6 +822,7 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
clipboardTextSerializer: this.clipboardTextSerializer,
handlePaste: this.handlePaste,
});
+ this._editorView.state.schema.Document = this.props.Document;
if (startup && this._editorView) {
Doc.GetProto(doc).documentText = undefined;
this._editorView.dispatch(this._editorView.state.tr.insertText(startup));
@@ -872,7 +873,7 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
if (this.props.onClick && e.button === 0) {
e.preventDefault();
}
- if (e.button === 0 && this.props.isSelected(true) && !e.altKey && !e.ctrlKey && !e.metaKey) {
+ if (e.button === 0 && this.active(true) && !e.altKey && !e.ctrlKey && !e.metaKey) {
e.stopPropagation();
}
if (e.button === 2 || (e.button === 0 && e.ctrlKey)) {
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index f6aa47f15..09e627078 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -18,7 +18,6 @@ import { undoBatch } from '../../util/UndoManager';
import { ContextMenu } from "../../views/ContextMenu";
import { ContextMenuProps } from '../ContextMenuItem';
import { DocAnnotatableComponent } from '../DocComponent';
-import { InkingControl } from '../InkingControl';
import FaceRectangles from './FaceRectangles';
import { FieldView, FieldViewProps } from './FieldView';
import "./ImageBox.scss";
diff --git a/src/client/views/nodes/KeyValueBox.tsx b/src/client/views/nodes/KeyValueBox.tsx
index 322d639dc..234a6a9d3 100644
--- a/src/client/views/nodes/KeyValueBox.tsx
+++ b/src/client/views/nodes/KeyValueBox.tsx
@@ -57,7 +57,7 @@ export class KeyValueBox extends React.Component<FieldViewProps> {
value = eq ? value.substr(1) : value;
const dubEq = value.startsWith(":=") ? "computed" : value.startsWith(";=") ? "script" : false;
value = dubEq ? value.substr(2) : value;
- const options: ScriptOptions = { addReturn: true, params: { this: "Doc" } };
+ const options: ScriptOptions = { addReturn: true, params: { this: "Doc", _last_: "any" }, editable: false };
if (dubEq) options.typecheck = false;
const script = CompileScript(value, options);
if (!script.compiled) {
diff --git a/src/client/views/nodes/KeyValuePair.tsx b/src/client/views/nodes/KeyValuePair.tsx
index 3e253b83a..91f8bb3b0 100644
--- a/src/client/views/nodes/KeyValuePair.tsx
+++ b/src/client/views/nodes/KeyValuePair.tsx
@@ -5,7 +5,6 @@ import { emptyFunction, returnFalse, returnOne, returnZero } from '../../../Util
import { Docs } from '../../documents/Documents';
import { Transform } from '../../util/Transform';
import { undoBatch } from '../../util/UndoManager';
-import { CollectionDockingView } from '../collections/CollectionDockingView';
import { ContextMenu } from '../ContextMenu';
import { EditableView } from "../EditableView";
import { FieldView, FieldViewProps } from './FieldView';