aboutsummaryrefslogtreecommitdiff
path: root/src/client/views
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/views')
-rw-r--r--src/client/views/ContextMenu.tsx2
-rw-r--r--src/client/views/ContextMenuItem.tsx2
-rw-r--r--src/client/views/MainOverlayTextBox.tsx1
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx55
-rw-r--r--src/client/views/nodes/CollectionFreeFormDocumentView.tsx4
-rw-r--r--src/client/views/nodes/FormattedTextBox.tsx18
-rw-r--r--src/client/views/nodes/WebBox.scss1
7 files changed, 67 insertions, 16 deletions
diff --git a/src/client/views/ContextMenu.tsx b/src/client/views/ContextMenu.tsx
index e27318429..890bfdfb7 100644
--- a/src/client/views/ContextMenu.tsx
+++ b/src/client/views/ContextMenu.tsx
@@ -248,7 +248,7 @@ export class ContextMenu extends React.Component {
e.preventDefault();
} else if (e.key === "Enter" || e.key === "Tab") {
const item = this.flatItems[this.selectedIndex];
- item.event();
+ item && item.event();
this.closeMenu();
}
}
diff --git a/src/client/views/ContextMenuItem.tsx b/src/client/views/ContextMenuItem.tsx
index 90f7be33f..1a0839060 100644
--- a/src/client/views/ContextMenuItem.tsx
+++ b/src/client/views/ContextMenuItem.tsx
@@ -89,7 +89,7 @@ export class ContextMenuItem extends React.Component<ContextMenuProps & { select
);
} else if ("subitems" in this.props) {
let submenu = !this.overItem ? (null) :
- <div className="contextMenu-subMenu-cont" style={{ marginLeft: "100.5%", left: "0px" }}>
+ <div className="contextMenu-subMenu-cont" style={{ marginLeft: "10.5%", left: "0px" }}>
{this._items.map(prop => <ContextMenuItem {...prop} key={prop.description} closeMenu={this.props.closeMenu} />)}
</div>;
return (
diff --git a/src/client/views/MainOverlayTextBox.tsx b/src/client/views/MainOverlayTextBox.tsx
index 27e0d181f..c3a2cb214 100644
--- a/src/client/views/MainOverlayTextBox.tsx
+++ b/src/client/views/MainOverlayTextBox.tsx
@@ -25,7 +25,6 @@ export class MainOverlayTextBox extends React.Component<MainOverlayTextBoxProps>
private _textTargetDiv: HTMLDivElement | undefined;
private _textProxyDiv: React.RefObject<HTMLDivElement>;
private _textBottom: boolean | undefined;
- private _textAutoHeight: boolean | undefined;
private _setouterdiv = (outerdiv: HTMLElement | null) => { this._outerdiv = outerdiv; this.updateTooltip(); };
private _outerdiv: HTMLElement | null = null;
private _textBox: FormattedTextBox | undefined;
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index fac4d4970..2df2a3464 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -152,6 +152,7 @@ export namespace PivotView {
y={pos.y}
width={pos.width}
height={pos.height}
+ jitterRotation={NumCast(target.props.Document.jitterRotation)}
{...target.getChildDocumentViewProps(doc)}
/>,
bounds: {
@@ -256,7 +257,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
private addDocument = (newBox: Doc, allowDuplicates: boolean) => {
this.props.addDocument(newBox, false);
this.bringToFront(newBox);
- this.updateClusters();
+ this.updateCluster(newBox);
return true;
}
private selectDocuments = (docs: Doc[]) => {
@@ -324,7 +325,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
this.bringToFront(d);
});
- this.updateClusters();
+ de.data.droppedDocuments.length == 1 && this.updateCluster(de.data.droppedDocuments[0]);
}
}
else if (de.data instanceof DragManager.AnnotationDragData) {
@@ -384,6 +385,8 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
return false;
}
@observable sets: (Doc[])[] = [];
+
+ @undoBatch
@action
updateClusters() {
this.sets.length = 0;
@@ -412,12 +415,42 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
this.sets.map((set, i) => set.map(member => member.cluster = i));
}
+ @undoBatch
+ @action
+ updateCluster(doc: Doc) {
+ if (this.props.Document.useClusters) {
+ this.sets.map(set => Doc.IndexOf(doc, set) !== -1 && set.splice(Doc.IndexOf(doc, set), 1));
+ let preferredInd = NumCast(doc.cluster);
+ doc.cluster = -1;
+ this.sets.map((set, i) => set.map(member => {
+ if (doc.cluster === -1 && Doc.IndexOf(member, this.childDocs) !== -1 && this.boundsOverlap(doc, member)) {
+ doc.cluster = i;
+ }
+ }));
+ if (doc.cluster === -1 && preferredInd !== -1 && (!this.sets[preferredInd] || !this.sets[preferredInd].filter(member => Doc.IndexOf(member, this.childDocs) !== -1).length)) {
+ doc.cluster = preferredInd;
+ }
+ this.sets.map((set, i) => {
+ if (doc.cluster === -1 && !set.filter(member => Doc.IndexOf(member, this.childDocs) !== -1).length) {
+ doc.cluster = i;
+ }
+ });
+ if (doc.cluster === -1) {
+ doc.cluster = this.sets.length;
+ this.sets.push([doc]);
+ } else {
+ for (let i = this.sets.length; i <= doc.cluster; i++) !this.sets[i] && this.sets.push([]);
+ this.sets[doc.cluster].push(doc);
+ }
+ }
+ }
+
getClusterColor = (doc: Doc) => {
if (this.props.Document.useClusters) {
let cluster = NumCast(doc.cluster);
if (this.sets.length <= cluster) {
- setTimeout(() => this.updateClusters(), 0);
- return;
+ setTimeout(() => this.updateCluster(doc), 0);// this.updateClusters(), 0);
+ return "";
}
let set = this.sets.length > cluster ? this.sets[cluster] : undefined;
let colors = ["#da42429e", "#31ea318c", "#8c4000", "#4a7ae2c4", "#d809ff", "#ff7601", "#1dffff", "yellow", "#1b8231f2", "#000000ad"];
@@ -765,6 +798,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
if (pair.layout && !(pair.data instanceof Promise)) {
prev.push({
ele: <CollectionFreeFormDocumentView key={doc[Id]}
+ jitterRotation={NumCast(this.props.Document.jitterRotation)}
x={script ? pos.x : undefined} y={script ? pos.y : undefined}
width={script ? pos.width : undefined} height={script ? pos.height : undefined} {...this.getChildDocumentViewProps(pair.layout, pair.data)} />,
bounds: { x: pos.x || 0, y: pos.y || 0, z: pos.z, width: NumCast(pos.width), height: NumCast(pos.height) }
@@ -869,6 +903,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
Docs.Prototypes.get(DocumentType.TEXT).defaultBackgroundColor = "#f1efeb"; // backward compatibility with databases that didn't have a default background color on prototypes
Docs.Prototypes.get(DocumentType.COL).defaultBackgroundColor = "white";
this.props.Document.useClusters = !this.props.Document.useClusters;
+ this.updateClusters();
},
icon: !this.props.Document.useClusters ? "braille" : "braille"
});
@@ -879,10 +914,14 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
});
layoutItems.push({ description: "Arrange contents in grid", event: this.arrangeContents, icon: "table" });
layoutItems.push({ description: "Analyze Strokes", event: this.analyzeStrokes, icon: "paint-brush" });
- layoutItems.push({ description: "1: Note", event: () => this.createText("Note", "yellow"), icon: "eye" });
- layoutItems.push({ description: "2: Idea", event: () => this.createText("Idea", "pink"), icon: "eye" });
- layoutItems.push({ description: "3: Topic", event: () => this.createText("Topic", "lightBlue"), icon: "eye" });
- layoutItems.push({ description: "4: Person", event: () => this.createText("Person", "lightGreen"), icon: "eye" });
+ layoutItems.push({ description: "Jitter Rotation", event: action(() => this.props.Document.jitterRotation = 10), icon: "paint-brush" });
+
+ let noteItems: ContextMenuProps[] = [];
+ noteItems.push({ description: "1: Note", event: () => this.createText("Note", "yellow"), icon: "eye" });
+ noteItems.push({ description: "2: Idea", event: () => this.createText("Idea", "pink"), icon: "eye" });
+ noteItems.push({ description: "3: Topic", event: () => this.createText("Topic", "lightBlue"), icon: "eye" });
+ noteItems.push({ description: "4: Person", event: () => this.createText("Person", "lightGreen"), icon: "eye" });
+ layoutItems.push({ description: "Add Note ...", subitems: noteItems, icon: "eye" })
ContextMenu.Instance.addItem({ description: "Freeform Options ...", subitems: layoutItems, icon: "eye" });
}
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index c9c394960..f07584b4f 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -8,12 +8,14 @@ import { DocumentView, DocumentViewProps, positionSchema } from "./DocumentView"
import "./DocumentView.scss";
import React = require("react");
import { Doc } from "../../../new_fields/Doc";
+import { random } from "animejs";
export interface CollectionFreeFormDocumentViewProps extends DocumentViewProps {
x?: number;
y?: number;
width?: number;
height?: number;
+ jitterRotation: number;
}
const schema = createSchema({
@@ -27,7 +29,7 @@ const FreeformDocument = makeInterface(schema, positionSchema);
@observer
export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeFormDocumentViewProps, FreeformDocument>(FreeformDocument) {
- @computed get transform() { return `scale(${this.props.ContentScaling()}) translate(${this.X}px, ${this.Y}px) scale(${this.zoom}) `; }
+ @computed get transform() { return `scale(${this.props.ContentScaling()}) translate(${this.X}px, ${this.Y}px) rotate(${random(-1, 1) * this.props.jitterRotation}deg) scale(${this.zoom}) `; }
@computed get X() { return this.props.x !== undefined ? this.props.x : this.Document.x || 0; }
@computed get Y() { return this.props.y !== undefined ? this.props.y : this.Document.y || 0; }
@computed get width(): number { return BoolCast(this.props.Document.willMaximize) ? 0 : this.props.width !== undefined ? this.props.width : this.Document.width || 0; }
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 5f185d8ae..ae1393fc4 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -261,7 +261,12 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
// }
}
}
-
+ setAnnotation = (start: number, end: number, mark: Mark, opened: boolean, keep: boolean = false) => {
+ let view = this._editorView!;
+ let mid = view.state.doc.resolve(Math.round((start + end) / 2));
+ let nmark = view.state.schema.marks.user_mark.create({ ...mark.attrs, userid: keep ? Doc.CurrentUserEmail : mark.attrs.userid, opened: opened });
+ view.dispatch(view.state.tr.removeMark(start, end, nmark).addMark(start, end, nmark).setSelection(new TextSelection(mid)));
+ }
protected createDropTarget = (ele: HTMLDivElement) => {
this._proseRef = ele;
this.dropDisposer && this.dropDisposer();
@@ -273,10 +278,13 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
drop = async (e: Event, de: DragManager.DropEvent) => {
// We're dealing with a link to a document
if (de.data instanceof DragManager.EmbedDragData && de.data.urlField) {
+ let target = de.data.embeddableSourceDoc;
// We're dealing with an internal document drop
let url = de.data.urlField.url.href;
let model: NodeType = (url.includes(".mov") || url.includes(".mp4")) ? schema.nodes.video : schema.nodes.image;
- this._editorView!.dispatch(this._editorView!.state.tr.insert(0, model.create({ src: url })));
+ let pos = this._editorView!.posAtCoords({ left: de.x, top: de.y });
+ this._editorView!.dispatch(this._editorView!.state.tr.insert(pos!.pos, model.create({ src: url, docid: target[Id] })));
+ DocUtils.MakeLink(this.dataDoc, target, undefined, "ImgRef:" + target.title, undefined, undefined, target[Id]);
e.stopPropagation();
} else if (de.data instanceof DragManager.DocumentDragData) {
const draggedDoc = de.data.draggedDocuments.length && de.data.draggedDocuments[0];
@@ -629,12 +637,13 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
}
}
if (this._proseRef) {
+ let self = this;
this._editorView && this._editorView.destroy();
this._editorView = new EditorView(this._proseRef, {
state: field && field.Data ? EditorState.fromJSON(config, JSON.parse(field.Data)) : EditorState.create(config),
dispatchTransaction: this.dispatchTransaction,
nodeViews: {
- image(node, view, getPos) { return new ImageResizeView(node, view, getPos); },
+ image(node, view, getPos) { return new ImageResizeView(node, view, getPos, self.props.addDocTab); },
star(node, view, getPos) { return new SummarizedView(node, view, getPos); },
ordered_list(node, view, getPos) { return new OrderedListView(); },
footnote(node, view, getPos) { return new FootnoteView(node, view, getPos); }
@@ -689,7 +698,8 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
for (let parent = (e.target as any).parentNode; !href && parent; parent = parent.parentNode) {
href = parent.childNodes[0].href ? parent.childNodes[0].href : parent.href;
}
- let node = this._editorView!.state.doc.nodeAt(this._editorView!.posAtCoords({ left: e.clientX, top: e.clientY })!.pos);
+ let pcords = this._editorView!.posAtCoords({ left: e.clientX, top: e.clientY });
+ let node = pcords && this._editorView!.state.doc.nodeAt(pcords.pos);
if (node) {
let link = node.marks.find(m => m.type === this._editorView!.state.schema.marks.link);
href = link && link.attrs.href;
diff --git a/src/client/views/nodes/WebBox.scss b/src/client/views/nodes/WebBox.scss
index 43220df71..fbe9bf063 100644
--- a/src/client/views/nodes/WebBox.scss
+++ b/src/client/views/nodes/WebBox.scss
@@ -30,6 +30,7 @@
width: 100%;
height: 100%;
position: absolute;
+ pointer-events: all;
}
.webBox-button {