aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/client/util/RichTextSchema.tsx91
-rw-r--r--src/client/util/TooltipTextMenu.tsx68
-rw-r--r--src/client/views/ContextMenu.tsx50
-rw-r--r--src/client/views/DocumentDecorations.scss17
-rw-r--r--src/client/views/DocumentDecorations.tsx23
-rw-r--r--src/client/views/GlobalKeyHandler.ts1
-rw-r--r--src/client/views/Main.scss2
-rw-r--r--src/client/views/MainView.tsx22
-rw-r--r--src/client/views/SearchItem.tsx67
-rw-r--r--src/client/views/collections/CollectionBaseView.tsx2
-rw-r--r--src/client/views/collections/CollectionDockingView.tsx2
-rw-r--r--src/client/views/collections/CollectionStackingView.tsx4
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx73
-rw-r--r--src/client/views/nodes/DocumentView.tsx20
-rw-r--r--src/client/views/nodes/FormattedTextBox.scss8
-rw-r--r--src/client/views/nodes/FormattedTextBox.tsx2
-rw-r--r--src/client/views/nodes/ImageBox.scss27
-rw-r--r--src/client/views/nodes/ImageBox.tsx4
-rw-r--r--src/client/views/nodes/LinkMenu.tsx1
-rw-r--r--src/client/views/nodes/LinkMenuGroup.tsx10
-rw-r--r--src/client/views/nodes/LinkMenuItem.tsx155
-rw-r--r--src/client/views/nodes/WebBox.scss75
-rw-r--r--src/client/views/nodes/WebBox.tsx6
-rw-r--r--src/client/views/search/SearchBox.scss5
-rw-r--r--src/client/views/search/SearchBox.tsx21
-rw-r--r--src/new_fields/Doc.ts67
-rw-r--r--src/server/authentication/models/current_user_utils.ts2
-rw-r--r--views/stylesheets/authentication.css6
28 files changed, 425 insertions, 406 deletions
diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx
index 733c50d20..6d2abfaa2 100644
--- a/src/client/util/RichTextSchema.tsx
+++ b/src/client/util/RichTextSchema.tsx
@@ -1,12 +1,6 @@
-import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { Schema, NodeSpec, MarkSpec, DOMOutputSpecArray, NodeType, Slice, Mark, Node } from "prosemirror-model";
-import { joinUp, lift, setBlockType, toggleMark, wrapIn, selectNodeForward, deleteSelection } from 'prosemirror-commands';
-import { redo, undo } from 'prosemirror-history';
-import { orderedList, bulletList, listItem, } from 'prosemirror-schema-list';
-import { EditorState, Transaction, NodeSelection, TextSelection, Selection, } from "prosemirror-state";
-import { EditorView, } from "prosemirror-view";
-import { View } from '@react-pdf/renderer';
-import { TooltipTextMenu } from './TooltipTextMenu';
+import { DOMOutputSpecArray, MarkSpec, Node, NodeSpec, Schema, Slice } from "prosemirror-model";
+import { bulletList, listItem, orderedList } from 'prosemirror-schema-list';
+import { TextSelection } from "prosemirror-state";
const pDOM: DOMOutputSpecArray = ["p", 0], blockquoteDOM: DOMOutputSpecArray = ["blockquote", 0], hrDOM: DOMOutputSpecArray = ["hr"],
preDOM: DOMOutputSpecArray = ["pre", ["code", 0]], brDOM: DOMOutputSpecArray = ["br"], ulDOM: DOMOutputSpecArray = ["ul", 0];
@@ -112,18 +106,6 @@ export const nodes: { [index: string]: NodeSpec } = {
// }]
},
- checkbox: {
- inline: true,
- attrs: {
- visibility: { default: false }
- },
- group: "inline",
- toDOM(node) {
- const attrs = { style: `width: 40px` };
- return ["span", { ...node.attrs, ...attrs }];
- },
- },
-
// :: NodeSpec An inline image (`<img>`) node. Supports `src`,
// `alt`, and `href` attributes. The latter two default to the empty
// string.
@@ -203,19 +185,6 @@ export const nodes: { [index: string]: NodeSpec } = {
// toDOM() { return ulDOM }
},
- checkbox_list: {
- content: 'checklist_item+',
- marks: '_',
- group: 'block',
- // inline: true,
- parseDOM: [
- { tag: "ul" }
- ],
- toDOM() {
- return ["ul", { style: 'list-style: none' }, 0];
- },
- },
-
//bullet_list: {
// content: 'list_item+',
// group: 'block',
@@ -229,17 +198,6 @@ export const nodes: { [index: string]: NodeSpec } = {
content: 'paragraph block*'
},
- checklist_item: {
- content: 'paragraph block*',
- parseDOM: [{ tag: "li" }],
- // toDOM() {
- // return ["li", { style: 'content: checkbox' }, 0];
- // },
- toDOM() {
- return ["li", 0];
- },
- defining: true
- }
};
const emDOM: DOMOutputSpecArray = ["em", 0];
@@ -562,49 +520,6 @@ export class ImageResizeView {
}
}
-export class CheckboxView {
- _view: any;
- _collapsed: HTMLElement;
-
- constructor(node: any, view: any, getPos: any) {
- this._collapsed = document.createElement("span");
- this._collapsed.textContent = node.attrs.visibility ? "⬛" : "⬜";
- this._collapsed.style.position = "relative";
- // this._collapsed.style.width = "80px";
- this._collapsed.style.height = "20px";
- let self = this;
- this._view = view;
- const js = node.toJSON;
- node.toJSON = function () {
-
- return js.apply(this, arguments);
- };
- this._collapsed.onpointerdown = function (e: any) {
- console.log(node.attrs.visibility)
- if (node.attrs.visibility) {
- let y = getPos();
- const attrs = { ...node.attrs };
- attrs.visibility = !attrs.visibility;
- view.dispatch(view.state.tr.setNodeMarkup(y, undefined, attrs));
- self._collapsed.textContent = "⬜";
- } else {
- let y = getPos();
- const attrs = { ...node.attrs };
- attrs.visibility = !attrs.visibility;
- console.log(attrs.visibility)
- view.dispatch(view.state.tr.setNodeMarkup(y, undefined, attrs));
- self._collapsed.textContent = "⬛";
- }
- e.preventDefault();
- e.stopPropagation();
- console.log(node.attrs.visibility)
-
- };
- (this as any).dom = this._collapsed;
- }
-
-}
-
export class SummarizedView {
// TODO: highlight text that is summarized. to find end of region, walk along mark
_collapsed: HTMLElement;
diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx
index 46961e416..4672dd246 100644
--- a/src/client/util/TooltipTextMenu.tsx
+++ b/src/client/util/TooltipTextMenu.tsx
@@ -1,32 +1,25 @@
-import { action, observable, observe } from "mobx";
-import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { faTag, faPlus, faCloudUploadAlt } from '@fortawesome/free-solid-svg-icons';
-import { Dropdown, MenuItem, icons, } from "prosemirror-menu"; //no import css
-import { EditorState, NodeSelection, TextSelection, Transaction } from "prosemirror-state";
-import { EditorView } from "prosemirror-view";
-import { schema } from "./RichTextSchema";
-import { Schema, NodeType, MarkType, Mark, ResolvedPos } from "prosemirror-model";
-import { Node as ProsNode } from "prosemirror-model";
-import "./TooltipTextMenu.scss";
-const { toggleMark, setBlockType } = require("prosemirror-commands");
import { library } from '@fortawesome/fontawesome-svg-core';
-import { wrapInList, liftListItem, bulletList, } from 'prosemirror-schema-list';
import { faListUl } from '@fortawesome/free-solid-svg-icons';
-import { FieldViewProps } from "../views/nodes/FieldView";
-const { openPrompt, TextField } = require("./ProsemirrorCopy/prompt.js");
-import { DragManager } from "./DragManager";
-import { Doc, Opt, Field } from "../../new_fields/Doc";
+import { action, observable } from "mobx";
+import { Dropdown, icons, MenuItem } from "prosemirror-menu"; //no import css
+import { Mark, MarkType, Node as ProsNode, NodeType, ResolvedPos, Schema } from "prosemirror-model";
+import { liftListItem, wrapInList } from 'prosemirror-schema-list';
+import { EditorState, NodeSelection, TextSelection } from "prosemirror-state";
+import { EditorView } from "prosemirror-view";
+import { Doc, Field, Opt } from "../../new_fields/Doc";
+import { Id } from "../../new_fields/FieldSymbols";
+import { Utils } from "../../Utils";
import { DocServer } from "../DocServer";
import { CollectionDockingView } from "../views/collections/CollectionDockingView";
+import { FieldViewProps } from "../views/nodes/FieldView";
+import { FormattedTextBoxProps } from "../views/nodes/FormattedTextBox";
import { DocumentManager } from "./DocumentManager";
-import { Id } from "../../new_fields/FieldSymbols";
-import { FormattedTextBoxProps, FormattedTextBox } from "../views/nodes/FormattedTextBox";
-import { typeAlias } from "babel-types";
-import React, { Children } from "react";
-import ReactDOM from "react-dom";
-import { Utils } from "../../Utils";
+import { DragManager } from "./DragManager";
import { LinkManager } from "./LinkManager";
-import { bool } from "prop-types";
+import { schema } from "./RichTextSchema";
+import "./TooltipTextMenu.scss";
+const { toggleMark, setBlockType } = require("prosemirror-commands");
+const { openPrompt, TextField } = require("./ProsemirrorCopy/prompt.js");
//appears above a selection of text in a RichTextBox to give user options such as Bold, Italics, etc.
export class TooltipTextMenu {
@@ -189,7 +182,6 @@ export class TooltipTextMenu {
this.tooltip.appendChild(this._brushdom);
this.tooltip.appendChild(this.createLink().render(this.view).dom);
this.tooltip.appendChild(this.createStar().render(this.view).dom);
- this.tooltip.appendChild(this.createCheckbox().render(this.view).dom);
this.updateListItemDropdown(":", this.listTypeBtnDom);
@@ -441,14 +433,6 @@ export class TooltipTextMenu {
return true;
}
- public static insertCheckbox(state: EditorState<any>, dispatch: any) {
- let newNode = schema.nodes.checkbox.create({ visibility: false });
- if (dispatch) {
- dispatch(state.tr.replaceSelectionWith(newNode));
- }
- return true;
- }
-
//will display a remove-list-type button if selection is in list, otherwise will show list type dropdown
updateListItemDropdown(label: string, listTypeBtn: any) {
//remove old btn
@@ -461,7 +445,6 @@ export class TooltipTextMenu {
});
//option to remove the list formatting
toAdd.push(this.dropdownNodeBtn("X", "color: black; width: 40px;", undefined, this.view, this.listTypes, this.changeToNodeType));
- toAdd.push(this.dropdownNodeBtn("⬜", "color:black; width:40px;", schema.nodes.checkbox_list, this.view, this.listTypes, this.changeToNodeType))
listTypeBtn = (new Dropdown(toAdd, {
label: label,
@@ -525,11 +508,6 @@ export class TooltipTextMenu {
liftListItem(schema.nodes.list_item)(view.state, view.dispatch);
if (nodeType) { //add new
wrapInList(nodeType)(view.state, view.dispatch);
- // console.log(nodeType === schema.nodes.checkbox_list)
- // if (nodeType === schema.nodes.checkbox_list) {
- // TooltipTextMenu.insertCheckbox(view.state, view.dispatch)
- // }
-
}
}
@@ -564,20 +542,6 @@ export class TooltipTextMenu {
});
}
- createCheckbox() {
- return new MenuItem({
- title: "Checkbox",
- label: "Checkbox",
- icon: icons.code,
- css: "color:white",
- class: "checkbox",
- execEvent: "",
- run: (state, dispatch) => {
- TooltipTextMenu.insertCheckbox(state, dispatch);
- }
- })
- }
-
deleteLinkItem() {
const icon = {
height: 16, width: 16,
diff --git a/src/client/views/ContextMenu.tsx b/src/client/views/ContextMenu.tsx
index 1bf6e383d..760736501 100644
--- a/src/client/views/ContextMenu.tsx
+++ b/src/client/views/ContextMenu.tsx
@@ -1,6 +1,6 @@
import React = require("react");
import { ContextMenuItem, ContextMenuProps, OriginalMenuProps } from "./ContextMenuItem";
-import { observable, action, computed } from "mobx";
+import { observable, action, computed, runInAction, IReactionDisposer, reaction } from "mobx";
import { observer } from "mobx-react";
import "./ContextMenu.scss";
import { library } from '@fortawesome/fontawesome-svg-core';
@@ -27,6 +27,13 @@ export class ContextMenu extends React.Component {
@observable private _width: number = 0;
@observable private _height: number = 0;
+ @observable private _mouseX: number = -1;
+ @observable private _mouseY: number = -1;
+ @observable private _shouldDisplay: boolean = false;
+ @observable private _mouseDown: boolean = false;
+
+ private _reactionDisposer?: IReactionDisposer;
+
constructor(props: Readonly<{}>) {
super(props);
@@ -34,6 +41,40 @@ export class ContextMenu extends React.Component {
}
@action
+ onPointerDown = (e: PointerEvent) => {
+ this._mouseDown = true;
+ this._mouseX = e.clientX;
+ this._mouseY = e.clientY;
+ }
+ @action
+ onPointerUp = (e: PointerEvent) => {
+ this._mouseDown = false;
+ let curX = e.clientX;
+ let curY = e.clientY;
+ if (this._mouseX !== curX || this._mouseY !== curY) {
+ this._shouldDisplay = false;
+ }
+
+ this._shouldDisplay && (this._display = true);
+ }
+ componentWillUnmount() {
+ document.removeEventListener("pointerdown", this.onPointerDown);
+ document.removeEventListener("pointerup", this.onPointerUp);
+ this._reactionDisposer && this._reactionDisposer();
+ }
+
+ @action
+ componentDidMount = () => {
+ document.addEventListener("pointerdown", this.onPointerDown);
+ document.addEventListener("pointerup", this.onPointerUp);
+
+ this._reactionDisposer = reaction(
+ () => this._shouldDisplay,
+ () => this._shouldDisplay && !this._mouseDown && runInAction(() => this._display = true)
+ );
+ }
+
+ @action
clearItems() {
this._items = [];
}
@@ -83,22 +124,21 @@ export class ContextMenu extends React.Component {
}
@action
- displayMenu(x: number, y: number) {
+ displayMenu = (x: number, y: number) => {
//maxX and maxY will change if the UI/font size changes, but will work for any amount
//of items added to the menu
this._pageX = x;
this._pageY = y;
-
this._searchString = "";
-
- this._display = true;
+ this._shouldDisplay = true;
}
@action
closeMenu = () => {
this.clearItems();
this._display = false;
+ this._shouldDisplay = false;
}
@computed get filteredItems(): (OriginalMenuProps | string[])[] {
diff --git a/src/client/views/DocumentDecorations.scss b/src/client/views/DocumentDecorations.scss
index 0b7411fca..3627edaae 100644
--- a/src/client/views/DocumentDecorations.scss
+++ b/src/client/views/DocumentDecorations.scss
@@ -24,13 +24,13 @@ $linkGap : 3px;
.documentDecorations-resizer {
pointer-events: auto;
background: $alt-accent;
- opacity: 0.8;
+ opacity: 1;
}
.documentDecorations-radius {
pointer-events: auto;
background: black;
- opacity: 0.8;
+ opacity: 1;
transform: translate(10px, 10px);
grid-row: 4;
}
@@ -92,27 +92,30 @@ $linkGap : 3px;
.title {
background: $alt-accent;
+ opacity: 1;
grid-column-start: 3;
grid-column-end: 4;
pointer-events: auto;
overflow: hidden;
+ text-align: center;
}
}
.documentDecorations-closeButton {
background: $alt-accent;
- opacity: 0.8;
+ opacity: 1;
grid-column-start: 4;
grid-column-end: 6;
pointer-events: all;
text-align: center;
cursor: pointer;
+ padding-right: 10px;
}
.documentDecorations-minimizeButton {
background: $alt-accent;
- opacity: 0.8;
+ opacity: 1;
grid-column-start: 1;
grid-column-end: 3;
pointer-events: all;
@@ -121,6 +124,7 @@ $linkGap : 3px;
position: absolute;
left: 0px;
top: 0px;
+ padding-top: 5px;
width: $MINIMIZED_ICON_SIZE;
height: $MINIMIZED_ICON_SIZE;
}
@@ -219,6 +223,11 @@ $linkGap : 3px;
margin-top: 3px;
}
+.documentdecorations-times {
+ margin-top: 3px;
+ padding-right: 3px;
+}
+
.templating-button,
.docDecs-tagButton {
width: 20px;
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index df526e01c..3fdda00cf 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -1,5 +1,5 @@
import { library } from '@fortawesome/fontawesome-svg-core';
-import { faLink, faTag } from '@fortawesome/free-solid-svg-icons';
+import { faLink, faTag, faTimes } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { action, computed, observable, reaction, runInAction } from "mobx";
import { observer } from "mobx-react";
@@ -36,6 +36,7 @@ export const Flyout = higflyout.default;
library.add(faLink);
library.add(faTag);
+library.add(faTimes);
@observer
export class DocumentDecorations extends React.Component<{}, { value: string }> {
@@ -65,6 +66,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
@observable private _opacity = 1;
@observable private _removeIcon = false;
@observable public Interacting = false;
+ @observable private _isMoving = false;
constructor(props: Readonly<{}>) {
super(props);
@@ -213,10 +215,14 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
}
@undoBatch
@action
- onCloseUp = (e: PointerEvent): void => {
+ onCloseUp = async (e: PointerEvent) => {
e.stopPropagation();
if (e.button === 0) {
- SelectionManager.SelectedDocuments().map(dv => dv.props.removeDocument && dv.props.removeDocument(dv.props.Document));
+ const recent = await Cast(CurrentUserUtils.UserDocument.recentlyClosed, Doc);
+ SelectionManager.SelectedDocuments().map(dv => {
+ recent && Doc.AddDocToList(recent, "data", dv.props.Document, undefined, true, true);
+ dv.props.removeDocument && dv.props.removeDocument(dv.props.Document);
+ });
SelectionManager.DeselectAll();
document.removeEventListener("pointermove", this.onCloseMove);
document.removeEventListener("pointerup", this.onCloseUp);
@@ -346,9 +352,14 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
document.addEventListener("pointermove", this.onRadiusMove);
document.addEventListener("pointerup", this.onRadiusUp);
}
+ if (!this._isMoving) {
+ SelectionManager.SelectedDocuments().map(dv => dv.props.Document.layout instanceof Doc ? dv.props.Document.layout : dv.props.Document.isTemplate ? dv.props.Document : Doc.GetProto(dv.props.Document)).
+ map(d => d.borderRounding = "0%");
+ }
}
onRadiusMove = (e: PointerEvent): void => {
+ this._isMoving = true;
let dist = Math.sqrt((e.clientX - this._radiusDown[0]) * (e.clientX - this._radiusDown[0]) + (e.clientY - this._radiusDown[1]) * (e.clientY - this._radiusDown[1]));
SelectionManager.SelectedDocuments().map(dv => dv.props.Document.layout instanceof Doc ? dv.props.Document.layout : dv.props.Document.isTemplate ? dv.props.Document : Doc.GetProto(dv.props.Document)).
map(d => d.borderRounding = `${Math.min(100, dist)}%`);
@@ -361,6 +372,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
e.preventDefault();
this._isPointerDown = false;
this._resizeUndo && this._resizeUndo.end();
+ this._isMoving = false;
document.removeEventListener("pointermove", this.onRadiusMove);
document.removeEventListener("pointerup", this.onRadiusUp);
}
@@ -673,6 +685,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
let linkButton = null;
if (SelectionManager.SelectedDocuments().length > 0) {
let selFirst = SelectionManager.SelectedDocuments()[0];
+
let linkCount = LinkManager.Instance.getAllRelatedLinks(selFirst.props.Document).length;
linkButton = (<Flyout
anchorPoint={anchorPoints.RIGHT_TOP}
@@ -743,7 +756,9 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
{this._edtingTitle ?
<input ref={this.keyinput} className="title" type="text" name="dynbox" value={this._title} onBlur={this.titleBlur} onChange={this.titleChanged} onKeyPress={this.titleEntered} /> :
<div className="title" onPointerDown={this.onTitleDown} ><span>{`${this.selectionTitle}`}</span></div>}
- <div className="documentDecorations-closeButton" title="Close Document" onPointerDown={this.onCloseDown}>X</div>
+ <div className="documentDecorations-closeButton" title="Close Document" onPointerDown={this.onCloseDown}>
+ <FontAwesomeIcon className="documentdecorations-times" icon={faTimes} size="lg" />
+ </div>
<div id="documentDecorations-topLeftResizer" className="documentDecorations-resizer" onPointerDown={this.onPointerDown} onContextMenu={(e) => e.preventDefault()}></div>
<div id="documentDecorations-topResizer" className="documentDecorations-resizer" onPointerDown={this.onPointerDown} onContextMenu={(e) => e.preventDefault()}></div>
<div id="documentDecorations-topRightResizer" className="documentDecorations-resizer" onPointerDown={this.onPointerDown} onContextMenu={(e) => e.preventDefault()}></div>
diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts
index df907b950..6238eb7b6 100644
--- a/src/client/views/GlobalKeyHandler.ts
+++ b/src/client/views/GlobalKeyHandler.ts
@@ -181,7 +181,6 @@ export default class KeyManager {
break;
case "a":
case "v":
- // this.printClipboard();
stopPropagation = false;
preventDefault = false;
break;
diff --git a/src/client/views/Main.scss b/src/client/views/Main.scss
index d84decdfe..bc0975c86 100644
--- a/src/client/views/Main.scss
+++ b/src/client/views/Main.scss
@@ -140,6 +140,8 @@ button:hover {
// font-size: 8px;
// user-select: none;
// }
+ margin-top: -2.55px;
+ margin-left: -2.55px;
}
// add nodes menu. Note that the + button is actually an input label, not an actual button.
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 7b4f1fc52..84fdf13a1 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -1,29 +1,33 @@
import { IconName, library } from '@fortawesome/fontawesome-svg-core';
-import { faArrowDown, faCloudUploadAlt, faArrowUp, faClone, faCheck, faPlay, faPause, faCaretUp, faLongArrowAltRight, faCommentAlt, faCut, faExclamation, faFilePdf, faFilm, faFont, faGlobeAsia, faPortrait, faMusic, faObjectGroup, faPenNib, faRedoAlt, faTable, faThumbtack, faTree, faUndoAlt, faCat, faBolt } from '@fortawesome/free-solid-svg-icons';
+import { faArrowDown, faArrowUp, faBolt, faCaretUp, faCat, faCheck, faClone, faCloudUploadAlt, faCommentAlt, faCut, faExclamation, faFilePdf, faFilm, faFont, faGlobeAsia, faLongArrowAltRight, faMusic, faObjectGroup, faPause, faPenNib, faPlay, faPortrait, faRedoAlt, faTable, faThumbtack, faTree, faUndoAlt } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { action, computed, configure, observable, runInAction, reaction, trace, autorun } from 'mobx';
+import { action, computed, configure, observable, reaction, runInAction } from 'mobx';
import { observer } from 'mobx-react';
import "normalize.css";
import * as React from 'react';
import { SketchPicker } from 'react-color';
import Measure from 'react-measure';
-import { Doc, DocListCast, Opt, HeightSym } from '../../new_fields/Doc';
+import { Doc, DocListCast, HeightSym, Opt } from '../../new_fields/Doc';
import { Id } from '../../new_fields/FieldSymbols';
import { InkTool } from '../../new_fields/InkField';
import { List } from '../../new_fields/List';
import { listSpec } from '../../new_fields/Schema';
-import { Cast, FieldValue, NumCast, BoolCast, StrCast } from '../../new_fields/Types';
+import { SchemaHeaderField } from '../../new_fields/SchemaHeaderField';
+import { BoolCast, Cast, FieldValue, StrCast } from '../../new_fields/Types';
import { CurrentUserUtils } from '../../server/authentication/models/current_user_utils';
import { RouteStore } from '../../server/RouteStore';
-import { emptyFunction, returnOne, returnTrue, Utils, returnEmptyString } from '../../Utils';
+import { emptyFunction, returnEmptyString, returnOne, returnTrue, Utils } from '../../Utils';
import { DocServer } from '../DocServer';
import { Docs } from '../documents/Documents';
+import { ClientUtils } from '../util/ClientUtils';
+import { DictationManager } from '../util/DictationManager';
import { SetupDrag } from '../util/DragManager';
import { HistoryUtil } from '../util/History';
import { Transform } from '../util/Transform';
import { UndoManager } from '../util/UndoManager';
import { CollectionBaseView } from './collections/CollectionBaseView';
import { CollectionDockingView } from './collections/CollectionDockingView';
+import { CollectionTreeView } from './collections/CollectionTreeView';
import { ContextMenu } from './ContextMenu';
import { DocumentDecorations } from './DocumentDecorations';
import KeyManager from './GlobalKeyHandler';
@@ -36,12 +40,6 @@ import PDFMenu from './pdf/PDFMenu';
import { PresentationView } from './presentationview/PresentationView';
import { PreviewCursor } from './PreviewCursor';
import { FilterBox } from './search/FilterBox';
-import { CollectionTreeView } from './collections/CollectionTreeView';
-import { ClientUtils } from '../util/ClientUtils';
-import { SchemaHeaderField, RandomPastel } from '../../new_fields/SchemaHeaderField';
-import { DictationManager } from '../util/DictationManager';
-import * as $ from 'jquery';
-import { KeyValueBox } from './nodes/KeyValueBox';
@observer
export class MainView extends React.Component {
@@ -542,7 +540,7 @@ export class MainView extends React.Component {
}
@observable isSearchVisible = false;
- @action
+ @action.bound
toggleSearch = () => {
// console.log("search toggling")
this.isSearchVisible = !this.isSearchVisible;
diff --git a/src/client/views/SearchItem.tsx b/src/client/views/SearchItem.tsx
deleted file mode 100644
index fd4b2420d..000000000
--- a/src/client/views/SearchItem.tsx
+++ /dev/null
@@ -1,67 +0,0 @@
-import React = require("react");
-import { library } from '@fortawesome/fontawesome-svg-core';
-import { faCaretUp, faFilePdf, faFilm, faImage, faObjectGroup, faStickyNote } from '@fortawesome/free-solid-svg-icons';
-import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { Doc } from "../../new_fields/Doc";
-import { DocumentManager } from "../util/DocumentManager";
-import { SetupDrag } from "../util/DragManager";
-
-
-export interface SearchProps {
- doc: Doc;
-}
-
-library.add(faCaretUp);
-library.add(faObjectGroup);
-library.add(faStickyNote);
-library.add(faFilePdf);
-library.add(faFilm);
-
-export class SearchItem extends React.Component<SearchProps> {
-
- onClick = () => {
- DocumentManager.Instance.jumpToDocument(this.props.doc, false);
- }
-
- //needs help
- // @computed get layout(): string { const field = Cast(this.props.doc[fieldKey], IconField); return field ? field.icon : "<p>Error loading icon data</p>"; }
-
-
- public static DocumentIcon(layout: string) {
- let button = layout.indexOf("PDFBox") !== -1 ? faFilePdf :
- layout.indexOf("ImageBox") !== -1 ? faImage :
- layout.indexOf("Formatted") !== -1 ? faStickyNote :
- layout.indexOf("Video") !== -1 ? faFilm :
- layout.indexOf("Collection") !== -1 ? faObjectGroup :
- faCaretUp;
- return <FontAwesomeIcon icon={button} className="documentView-minimizedIcon" />;
- }
- onPointerEnter = (e: React.PointerEvent) => {
- Doc.BrushDoc(this.props.doc);
- }
- onPointerLeave = (e: React.PointerEvent) => {
- Doc.UnBrushDoc(this.props.doc);
- }
-
- collectionRef = React.createRef<HTMLDivElement>();
- startDocDrag = () => {
- let doc = this.props.doc;
- const isProto = Doc.GetT(doc, "isPrototype", "boolean", true);
- if (isProto) {
- return Doc.MakeDelegate(doc);
- } else {
- return Doc.MakeAlias(doc);
- }
- }
- render() {
- return (
- <div className="search-item" ref={this.collectionRef} id="result"
- onPointerEnter={this.onPointerEnter} onPointerLeave={this.onPointerLeave}
- onClick={this.onClick} onPointerDown={SetupDrag(this.collectionRef, this.startDocDrag)} >
- <div className="search-title" id="result" >title: {this.props.doc.title}</div>
- {/* <div className="search-type" id="result" >Type: {this.props.doc.layout}</div> */}
- {/* <div className="search-type" >{SearchItem.DocumentIcon(this.layout)}</div> */}
- </div>
- );
- }
-} \ No newline at end of file
diff --git a/src/client/views/collections/CollectionBaseView.tsx b/src/client/views/collections/CollectionBaseView.tsx
index 4a296493a..b6ed6aaa0 100644
--- a/src/client/views/collections/CollectionBaseView.tsx
+++ b/src/client/views/collections/CollectionBaseView.tsx
@@ -11,6 +11,7 @@ import { SelectionManager } from '../../util/SelectionManager';
import { ContextMenu } from '../ContextMenu';
import { FieldViewProps } from '../nodes/FieldView';
import './CollectionBaseView.scss';
+import { DateField } from '../../../new_fields/DateField';
export enum CollectionViewType {
Invalid,
@@ -113,6 +114,7 @@ export class CollectionBaseView extends React.Component<CollectionViewProps> {
} else {
Doc.GetProto(targetDataDoc)[targetField] = new List([doc]);
}
+ Doc.GetProto(doc).lastOpened = new DateField;
return true;
}
diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx
index 7332a490a..a8e723379 100644
--- a/src/client/views/collections/CollectionDockingView.tsx
+++ b/src/client/views/collections/CollectionDockingView.tsx
@@ -28,6 +28,7 @@ import { library } from '@fortawesome/fontawesome-svg-core';
import { faFile, faUnlockAlt } from '@fortawesome/free-solid-svg-icons';
import { CurrentUserUtils } from '../../../server/authentication/models/current_user_utils';
import { Docs } from '../../documents/Documents';
+import { DateField } from '../../../new_fields/DateField';
library.add(faFile);
@observer
@@ -204,6 +205,7 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp
}
@action
public AddTab = (stack: any, document: Doc, dataDocument: Doc | undefined) => {
+ Doc.GetProto(document).lastOpened = new DateField;
let docs = Cast(this.props.Document.data, listSpec(Doc));
if (docs) {
docs.push(document);
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 4add7774e..2e4f6aff5 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -63,7 +63,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
setTimeout(() => this.props.Document.sectionHeaders = new List<SchemaHeaderField>(), 0);
return new Map<SchemaHeaderField, Doc[]>();
}
- const sectionHeaders = this.sectionHeaders!;
+ const sectionHeaders = this.sectionHeaders;
let fields = new Map<SchemaHeaderField, Doc[]>(sectionHeaders.map(sh => [sh, []] as [SchemaHeaderField, []]));
this.filteredChildren.map(d => {
let sectionValue = (d[this.sectionFilter] ? d[this.sectionFilter] : `NO ${this.sectionFilter.toUpperCase()} VALUE`) as object;
@@ -95,7 +95,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) {
if (this.isStackingView && BoolCast(this.props.Document.autoHeight)) {
let sectionsList = Array.from(this.Sections.size ? this.Sections.values() : [this.filteredChildren]);
return this.props.ContentScaling() * sectionsList.reduce((maxHght, s) => Math.max(maxHght,
- 50 + s.reduce((height, d, i) => height + this.childDocHeight(d) + (i === s.length - 1 ? this.yMargin : this.gridGap), this.yMargin)
+ (this.Sections.size ? 50 : 0) + s.reduce((height, d, i) => height + this.childDocHeight(d) + (i === s.length - 1 ? this.yMargin : this.gridGap), this.yMargin)
), 0);
}
return -1;
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 9db716f19..903fd72f7 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -78,7 +78,6 @@ export namespace PivotView {
let collection = target.Document;
const field = StrCast(collection.pivotField) || "title";
const width = NumCast(collection.pivotWidth) || 200;
-
const groups = new Map<FieldResult<Field>, Doc[]>();
for (const doc of target.childDocs) {
@@ -91,14 +90,11 @@ export namespace PivotView {
} else {
groups.set(val, [doc]);
}
-
}
let minSize = Infinity;
- groups.forEach((val, key) => {
- minSize = Math.min(minSize, val.length);
- });
+ groups.forEach((val, key) => minSize = Math.min(minSize, val.length));
const numCols = NumCast(collection.pivotNumColumns) || Math.ceil(Math.sqrt(minSize));
const fontSize = NumCast(collection.pivotFontSize);
@@ -135,42 +131,36 @@ export namespace PivotView {
});
let elements = target.viewDefsToJSX(groupNames);
- let curPage = FieldValue(target.Document.curPage, -1);
-
- let docViews = target.childDocs.filter(doc => doc instanceof Doc).reduce((prev, doc) => {
- var page = NumCast(doc.page, -1);
- if ((Math.abs(Math.round(page) - Math.round(curPage)) < 3) || page === -1) {
- let minim = BoolCast(doc.isMinimized);
- if (minim === undefined || !minim) {
- let defaultPosition = (): ViewDefBounds => {
- return {
- x: NumCast(doc.x),
- y: NumCast(doc.y),
- z: NumCast(doc.z),
- width: NumCast(doc.width),
- height: NumCast(doc.height)
- };
+ let docViews = target.childDocs.reduce((prev, doc) => {
+ let minim = BoolCast(doc.isMinimized);
+ if (minim === undefined || !minim) {
+ let defaultPosition = (): ViewDefBounds => {
+ return {
+ x: NumCast(doc.x),
+ y: NumCast(doc.y),
+ z: NumCast(doc.z),
+ width: NumCast(doc.width),
+ height: NumCast(doc.height)
};
- const pos = docMap.get(doc) || defaultPosition();
- prev.push({
- ele: (
- <CollectionFreeFormDocumentView
- key={doc[Id]}
- x={pos.x}
- y={pos.y}
- width={pos.width}
- height={pos.height}
- {...target.getChildDocumentViewProps(doc)}
- />),
- bounds: {
- x: pos.x,
- y: pos.y,
- z: pos.z,
- width: NumCast(pos.width),
- height: NumCast(pos.height)
- }
- });
- }
+ };
+ const pos = docMap.get(doc) || defaultPosition();
+ prev.push({
+ ele: <CollectionFreeFormDocumentView
+ key={doc[Id]}
+ x={pos.x}
+ y={pos.y}
+ width={pos.width}
+ height={pos.height}
+ {...target.getChildDocumentViewProps(doc)}
+ />,
+ bounds: {
+ x: pos.x,
+ y: pos.y,
+ z: pos.z,
+ width: NumCast(pos.width),
+ height: NumCast(pos.height)
+ }
+ });
}
return prev;
}, elements);
@@ -729,6 +719,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
@computed.struct
get elements() {
+ if (this.Document.usePivotLayout) return PivotView.elements(this);
let curPage = FieldValue(this.Document.curPage, -1);
const initScript = this.Document.arrangeInit;
const script = this.Document.arrangeScript;
@@ -772,7 +763,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
@computed.struct
get views() {
- let source = this.Document.usePivotLayout === true ? PivotView.elements(this) : this.elements;
+ let source = this.elements;
return source.filter(ele => ele.bounds && !ele.bounds.z).map(ele => ele.ele);
}
@computed.struct
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 188a306ec..900cd266e 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -699,7 +699,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
onPointerLeave = (e: React.PointerEvent): void => { Doc.UnBrushDoc(this.props.Document); };
isSelected = () => SelectionManager.IsSelected(this);
- @action select = (ctrlPressed: boolean) => { SelectionManager.SelectDoc(this, ctrlPressed); }
+ @action select = (ctrlPressed: boolean) => { SelectionManager.SelectDoc(this, ctrlPressed); };
@computed get nativeWidth() { return this.Document.nativeWidth || 0; }
@computed get nativeHeight() { return this.Document.nativeHeight || 0; }
@computed get onClickHandler() { return this.props.onClick ? this.props.onClick : this.Document.onClick; }
@@ -747,22 +747,20 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
}
let showTextTitle = showTitle && StrCast(this.layoutDoc.layout).startsWith("<FormattedTextBox") ? showTitle : undefined;
let brushDegree = Doc.IsBrushedDegree(this.props.Document);
+ let fullDegree = Doc.isBrushedHighlightedDegree(this.props.Document);
+ // console.log(fullDegree)
+ let borderRounding = StrCast(Doc.GetProto(this.props.Document).borderRounding);
+ let localScale = this.props.ScreenToLocalTransform().Scale * fullDegree;
return (
<div className={`documentView-node${this.topMost ? "-topmost" : ""}`}
ref={this._mainCont}
style={{
pointerEvents: this.layoutDoc.isBackground && !this.isSelected() ? "none" : "all",
color: foregroundColor,
- outlineColor: ["transparent", "maroon", "maroon"][brushDegree],
- outlineStyle: ["none", "dashed", "solid"][brushDegree],
- outlineWidth: brushDegree && !StrCast(Doc.GetProto(this.props.Document).borderRounding) ?
- `${brushDegree * this.props.ScreenToLocalTransform().Scale}px` : "0px",
- marginLeft: brushDegree && StrCast(Doc.GetProto(this.props.Document).borderRounding) ?
- `${-brushDegree * this.props.ScreenToLocalTransform().Scale}px` : undefined,
- marginTop: brushDegree && StrCast(Doc.GetProto(this.props.Document).borderRounding) ?
- `${-brushDegree * this.props.ScreenToLocalTransform().Scale}px` : undefined,
- border: brushDegree && StrCast(Doc.GetProto(this.props.Document).borderRounding) ?
- `${["none", "dashed", "solid"][brushDegree]} ${["transparent", "maroon", "maroon"][brushDegree]} ${this.props.ScreenToLocalTransform().Scale}px` : undefined,
+ outlineColor: ["transparent", "maroon", "maroon", "yellow"][fullDegree],
+ outlineStyle: ["none", "dashed", "solid", "solid"][fullDegree],
+ outlineWidth: fullDegree && !borderRounding ? `${localScale}px` : "0px",
+ border: fullDegree && borderRounding ? `${["none", "dashed", "solid", "solid"][fullDegree]} ${["transparent", "maroon", "maroon", "yellow"][fullDegree]} ${localScale}px` : undefined,
borderRadius: "inherit",
background: backgroundColor,
width: nativeWidth,
diff --git a/src/client/views/nodes/FormattedTextBox.scss b/src/client/views/nodes/FormattedTextBox.scss
index 247f7d1ea..1b537cc52 100644
--- a/src/client/views/nodes/FormattedTextBox.scss
+++ b/src/client/views/nodes/FormattedTextBox.scss
@@ -33,12 +33,12 @@
}
.formattedTextBox-inner-rounded {
- height: calc(100% - 25px);
- width: calc(100% - 40px);
+ height: 70%;
+ width: 85%;
position: absolute;
overflow: auto;
- top: 15;
- left: 20;
+ top: 15%;
+ left: 10%;
}
.formattedTextBox-inner-rounded div,
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 25f611f19..c2015a147 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -619,7 +619,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
let dh = NumCast(this.props.Document.height, 0);
let sh = scrBounds.height;
const ChromeHeight = MainOverlayTextBox.Instance.ChromeHeight;
- this.props.Document.height = (nh ? dh / nh * sh : sh) + (ChromeHeight ? ChromeHeight() : 0);
+ this.props.Document.height = Math.max(10, (nh ? dh / nh * sh : sh) + (ChromeHeight ? ChromeHeight() : 0));
this.dataDoc.nativeHeight = nh ? sh : undefined;
}
}
diff --git a/src/client/views/nodes/ImageBox.scss b/src/client/views/nodes/ImageBox.scss
index 497ce96c9..b1afa3f7d 100644
--- a/src/client/views/nodes/ImageBox.scss
+++ b/src/client/views/nodes/ImageBox.scss
@@ -62,17 +62,40 @@
position:relative;
width:100%;
margin:0 auto;
+ display:flex;
+ align-items: center;
+ height:100%;
+ .imageBox-fadeBlocker {
+ width:100%;
+ height:100%;
+ background: black;
+ display:flex;
+ flex-direction: row;
+ align-items: center;
+ z-index: 1;
+ .imageBox-fadeaway {
+ object-fit: contain;
+ width:100%;
+ height:100%;
+ }
+ }
}
#cf img {
position:absolute;
left:0;
+ }
+
+ .imageBox-fadeBlocker {
-webkit-transition: opacity 1s ease-in-out;
-moz-transition: opacity 1s ease-in-out;
-o-transition: opacity 1s ease-in-out;
transition: opacity 1s ease-in-out;
}
-
- #cf img.fadeaway:hover {
+ .imageBox-fadeBlocker:hover {
+ -webkit-transition: opacity 1s ease-in-out;
+ -moz-transition: opacity 1s ease-in-out;
+ -o-transition: opacity 1s ease-in-out;
+ transition: opacity 1s ease-in-out;
opacity:0;
} \ No newline at end of file
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index 582a50637..708e00576 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -420,13 +420,13 @@ export class ImageBox extends DocComponent<FieldViewProps, ImageDocument>(ImageD
width={nativeWidth}
ref={this._imgRef}
onError={this.onError} />
- {fadepath === srcpath ? (null) : <img id="fadeaway" className="fadeaway"
+ {fadepath === srcpath ? (null) : <div className="imageBox-fadeBlocker"> <img className="imageBox-fadeaway"
key={"fadeaway" + this._smallRetryCount + (this._mediumRetryCount << 4) + (this._largeRetryCount << 8)} // force cache to update on retrys
src={fadepath}
style={{ transform: `translate(0px, ${shift}px) rotate(${rotation}deg) scale(${aspect})` }}
width={nativeWidth}
ref={this._imgRef}
- onError={this.onError} />}
+ onError={this.onError} /></div>}
</div>
{paths.length > 1 ? this.dots(paths) : (null)}
<div className="imageBox-audioBackground"
diff --git a/src/client/views/nodes/LinkMenu.tsx b/src/client/views/nodes/LinkMenu.tsx
index 1a4af04f8..fe7d88457 100644
--- a/src/client/views/nodes/LinkMenu.tsx
+++ b/src/client/views/nodes/LinkMenu.tsx
@@ -42,6 +42,7 @@ export class LinkMenu extends React.Component<Props> {
linkItems.push(
<LinkMenuGroup
key={groupType}
+ docView={this.props.docView}
sourceDoc={this.props.docView.props.Document}
group={group}
groupType={groupType}
diff --git a/src/client/views/nodes/LinkMenuGroup.tsx b/src/client/views/nodes/LinkMenuGroup.tsx
index e04044266..aa23d80a1 100644
--- a/src/client/views/nodes/LinkMenuGroup.tsx
+++ b/src/client/views/nodes/LinkMenuGroup.tsx
@@ -22,6 +22,8 @@ interface LinkMenuGroupProps {
groupType: string;
showEditor: (linkDoc: Doc) => void;
addDocTab: (document: Doc, dataDoc: Doc | undefined, where: string) => void;
+ docView: DocumentView;
+
}
@observer
@@ -83,9 +85,13 @@ export class LinkMenuGroup extends React.Component<LinkMenuGroupProps> {
let groupItems = this.props.group.map(linkDoc => {
let destination = LinkManager.Instance.getOppositeAnchor(linkDoc, this.props.sourceDoc);
if (destination && this.props.sourceDoc) {
- return <LinkMenuItem key={destination[Id] + this.props.sourceDoc[Id]} groupType={this.props.groupType}
+ return <LinkMenuItem key={destination[Id] + this.props.sourceDoc[Id]}
+ groupType={this.props.groupType}
addDocTab={this.props.addDocTab}
- linkDoc={linkDoc} sourceDoc={this.props.sourceDoc} destinationDoc={destination} showEditor={this.props.showEditor} />;
+ linkDoc={linkDoc}
+ sourceDoc={this.props.sourceDoc}
+ destinationDoc={destination}
+ showEditor={this.props.showEditor} />;
}
});
diff --git a/src/client/views/nodes/LinkMenuItem.tsx b/src/client/views/nodes/LinkMenuItem.tsx
index a119eb39b..c3d9d033f 100644
--- a/src/client/views/nodes/LinkMenuItem.tsx
+++ b/src/client/views/nodes/LinkMenuItem.tsx
@@ -13,6 +13,8 @@ import { LinkManager } from '../../util/LinkManager';
import { DragLinkAsDocument } from '../../util/DragManager';
import { CollectionDockingView } from '../collections/CollectionDockingView';
import { SelectionManager } from '../../util/SelectionManager';
+import { CollectionViewType } from '../collections/CollectionBaseView';
+import { DocumentView } from './DocumentView';
library.add(faEye, faEdit, faTimes, faArrowRight, faChevronDown, faChevronUp);
@@ -30,11 +32,63 @@ export class LinkMenuItem extends React.Component<LinkMenuItemProps> {
private _drag = React.createRef<HTMLDivElement>();
@observable private _showMore: boolean = false;
@action toggleShowMore() { this._showMore = !this._showMore; }
+ @observable shouldUnhighlight: boolean = false;
+ componentDidMount = () => {
+ // document.addEventListener("pointerdown", this.unhighlight);
+ }
+
+ unhighlight = () => {
+ // if (this.shouldUnhighlight)
+ // Doc.UnhighlightAll();
+ Doc.UnHighlightDoc(this.props.destinationDoc);
+ }
+
+ @action
+ highlightDoc = () => {
+ // this.shouldUnhighlight = false;
+ document.removeEventListener("pointerdown", this.unhighlight);
+
+ Doc.HighlightDoc(this.props.destinationDoc);
+
+ window.setTimeout(() => {
+ // this.shouldUnhighlight = true;
+ document.addEventListener("pointerdown", this.unhighlight);
+
+ }, 3000);
+ }
+
+ // NOT DONE?
+ // col = collection the doc is in
+ // target = the document to center on
@undoBatch
- onFollowLink = async (e: React.PointerEvent): Promise<void> => {
- e.stopPropagation();
- e.persist();
+ openLinkColRight = ({ col, target }: { col: Doc, target: Doc }) => {
+ col = Doc.IsPrototype(col) ? Doc.MakeDelegate(col) : col;
+ if (NumCast(col.viewType, CollectionViewType.Invalid) === CollectionViewType.Freeform) {
+ const newPanX = NumCast(target.x) + NumCast(target.width) / NumCast(target.zoomBasis, 1) / 2;
+ const newPanY = NumCast(target.y) + NumCast(target.height) / NumCast(target.zoomBasis, 1) / 2;
+ col.panX = newPanX;
+ col.panY = newPanY;
+ }
+ CollectionDockingView.Instance.AddRightSplit(col, undefined);
+ }
+
+ // DONE
+ // this opens the linked doc in a right split, NOT in its collection
+ @undoBatch
+ openLinkRight = () => {
+ this.highlightDoc();
+ let alias = Doc.MakeAlias(this.props.destinationDoc);
+ CollectionDockingView.Instance.AddRightSplit(alias, undefined);
+ SelectionManager.DeselectAll();
+ }
+
+ // DONE
+ // this is the standard "follow link" (jump to document)
+ // taken from follow link
+ @undoBatch
+ jumpToLink = async (shouldZoom: boolean = false) => {
+ this.highlightDoc();
let jumpToDoc = this.props.destinationDoc;
let pdfDoc = FieldValue(Cast(this.props.destinationDoc, Doc));
if (pdfDoc) {
@@ -45,29 +99,61 @@ export class LinkMenuItem extends React.Component<LinkMenuItemProps> {
let sourceContext = await Cast(proto.sourceContext, Doc);
let self = this;
-
let dockingFunc = (document: Doc) => { this.props.addDocTab(document, undefined, "inTab"); SelectionManager.DeselectAll(); };
- if (e.ctrlKey) {
- dockingFunc = (document: Doc) => CollectionDockingView.Instance.AddRightSplit(document, undefined);
- }
if (this.props.destinationDoc === self.props.linkDoc.anchor2 && targetContext) {
- DocumentManager.Instance.jumpToDocument(jumpToDoc, e.altKey, false, async document => dockingFunc(document), undefined, targetContext!);
+ DocumentManager.Instance.jumpToDocument(jumpToDoc, shouldZoom, false, async document => dockingFunc(document), undefined, targetContext!);
}
else if (this.props.destinationDoc === self.props.linkDoc.anchor1 && sourceContext) {
- DocumentManager.Instance.jumpToDocument(jumpToDoc, e.altKey, false, document => dockingFunc(sourceContext!));
+ DocumentManager.Instance.jumpToDocument(jumpToDoc, shouldZoom, false, document => dockingFunc(sourceContext!));
}
else if (DocumentManager.Instance.getDocumentView(jumpToDoc)) {
- DocumentManager.Instance.jumpToDocument(jumpToDoc, e.altKey, undefined, undefined, NumCast((this.props.destinationDoc === self.props.linkDoc.anchor2 ? self.props.linkDoc.anchor2Page : self.props.linkDoc.anchor1Page)));
+ DocumentManager.Instance.jumpToDocument(jumpToDoc, shouldZoom, undefined, undefined, NumCast((this.props.destinationDoc === self.props.linkDoc.anchor2 ? self.props.linkDoc.anchor2Page : self.props.linkDoc.anchor1Page)));
+
}
else {
- DocumentManager.Instance.jumpToDocument(jumpToDoc, e.altKey, false, dockingFunc);
+ DocumentManager.Instance.jumpToDocument(jumpToDoc, shouldZoom, false, dockingFunc);
}
}
+ // DONE
+ // opens link in new tab (not in a collection)
+ // this opens it full screen, do we need a separate full screen option?
+ @undoBatch
+ openLinkTab = () => {
+ this.highlightDoc();
+ let fullScreenAlias = Doc.MakeAlias(this.props.destinationDoc);
+ this.props.addDocTab(fullScreenAlias, undefined, "inTab");
+ SelectionManager.DeselectAll();
+ }
+
+ //opens link in new tab in collection
+ // col = collection the doc is in
+ // target = the document to center on
+ @undoBatch
+ openLinkColTab = ({ col, target }: { col: Doc, target: Doc }) => {
+ this.highlightDoc();
+ }
+
+ // this will open a link next to the source doc
+ @undoBatch
+ openLinkInPlace = () => {
+ this.highlightDoc();
+
+ let alias = Doc.MakeAlias(this.props.destinationDoc);
+ let y = this.props.sourceDoc.y;
+ let x = this.props.sourceDoc.x;
+
+ console.log(x, y);
+ }
+
+ //set this to be the default link behavior, can be any of the above
+ private defaultLinkBehavior: any = this.openLinkRight;
+
onEdit = (e: React.PointerEvent): void => {
e.stopPropagation();
this.props.showEditor(this.props.linkDoc);
+ SelectionManager.DeselectAll();
}
renderMetadata = (): JSX.Element => {
@@ -127,7 +213,10 @@ export class LinkMenuItem extends React.Component<LinkMenuItemProps> {
{canExpand ? <div title="Show more" className="button" onPointerDown={() => this.toggleShowMore()}>
<FontAwesomeIcon className="fa-icon" icon={this._showMore ? "chevron-up" : "chevron-down"} size="sm" /></div> : <></>}
<div title="Edit link" className="button" onPointerDown={this.onEdit}><FontAwesomeIcon className="fa-icon" icon="edit" size="sm" /></div>
- <div title="Follow link" className="button" onPointerDown={this.onFollowLink}><FontAwesomeIcon className="fa-icon" icon="arrow-right" size="sm" /></div>
+ {/* Original */}
+ {/* <div title="Follow link" className="button" onPointerDown={this.onFollowLink}><FontAwesomeIcon className="fa-icon" icon="arrow-right" size="sm" /></div> */}
+ {/* New */}
+ <div title="Follow link" className="button" onPointerDown={this.defaultLinkBehavior}><FontAwesomeIcon className="fa-icon" icon="arrow-right" size="sm" /></div>
</div>
</div>
{this._showMore ? this.renderMetadata() : <></>}
@@ -136,4 +225,44 @@ export class LinkMenuItem extends React.Component<LinkMenuItemProps> {
</div >
);
}
-} \ No newline at end of file
+}
+
+ // @undoBatch
+ // onFollowLink = async (e: React.PointerEvent): Promise<void> => {
+ // e.stopPropagation();
+ // e.persist();
+ // let jumpToDoc = this.props.destinationDoc;
+ // let pdfDoc = FieldValue(Cast(this.props.destinationDoc, Doc));
+ // if (pdfDoc) {
+ // jumpToDoc = pdfDoc;
+ // }
+ // let proto = Doc.GetProto(this.props.linkDoc);
+ // let targetContext = await Cast(proto.targetContext, Doc);
+ // let sourceContext = await Cast(proto.sourceContext, Doc);
+ // let self = this;
+
+
+ // let dockingFunc = (document: Doc) => { this.props.addDocTab(document, undefined, "inTab"); SelectionManager.DeselectAll(); };
+ // if (e.ctrlKey) {
+ // dockingFunc = (document: Doc) => CollectionDockingView.Instance.AddRightSplit(document, undefined);
+ // }
+
+ // if (this.props.destinationDoc === self.props.linkDoc.anchor2 && targetContext) {
+ // DocumentManager.Instance.jumpToDocument(jumpToDoc, e.altKey, false, async document => dockingFunc(document), undefined, targetContext!);
+ // console.log("1")
+ // }
+ // else if (this.props.destinationDoc === self.props.linkDoc.anchor1 && sourceContext) {
+ // DocumentManager.Instance.jumpToDocument(jumpToDoc, e.altKey, false, document => dockingFunc(sourceContext!));
+ // console.log("2")
+ // }
+ // else if (DocumentManager.Instance.getDocumentView(jumpToDoc)) {
+ // DocumentManager.Instance.jumpToDocument(jumpToDoc, e.altKey, undefined, undefined, NumCast((this.props.destinationDoc === self.props.linkDoc.anchor2 ? self.props.linkDoc.anchor2Page : self.props.linkDoc.anchor1Page)));
+ // console.log("3")
+
+ // }
+ // else {
+ // DocumentManager.Instance.jumpToDocument(jumpToDoc, e.altKey, false, dockingFunc);
+ // console.log("4")
+
+ // }
+ // } \ No newline at end of file
diff --git a/src/client/views/nodes/WebBox.scss b/src/client/views/nodes/WebBox.scss
index c37f08eca..07774263c 100644
--- a/src/client/views/nodes/WebBox.scss
+++ b/src/client/views/nodes/WebBox.scss
@@ -52,91 +52,20 @@
padding-bottom: 10px;
overflow: hidden;
- .collectionViewBaseChrome {
+ .editorBase {
display: flex;
- .collectionViewBaseChrome-viewPicker {
- font-size: 75%;
- text-transform: uppercase;
- letter-spacing: 2px;
- background: rgb(238, 238, 238);
- color: grey;
- outline-color: black;
- border: none;
- padding: 12px 10px 11px 10px;
- margin-left: 50px;
- }
-
- .collectionViewBaseChrome-viewPicker:active {
- outline-color: black;
- }
-
- .collectionViewBaseChrome-collapse {
+ .editor-collapse {
transition: all .5s, opacity 0.3s;
position: absolute;
width: 40px;
transform-origin: top left;
- // margin-top: 10px;
- }
-
- .collectionViewBaseChrome-viewSpecs {
- margin-left: 10px;
- display: grid;
-
-
-
- .collectionViewBaseChrome-viewSpecsMenu {
- overflow: hidden;
- transition: height .5s, display .5s;
- position: absolute;
- top: 60px;
- z-index: 100;
- display: flex;
- flex-direction: column;
- background: rgb(238, 238, 238);
- box-shadow: grey 2px 2px 4px;
-
- .qs-datepicker {
- left: unset;
- right: 0;
- }
-
- .collectionViewBaseChrome-viewSpecsMenu-row {
- display: grid;
- grid-template-columns: 150px 200px 150px;
- margin-top: 10px;
- margin-right: 10px;
-
- .collectionViewBaseChrome-viewSpecsMenu-rowLeft,
- .collectionViewBaseChrome-viewSpecsMenu-rowMiddle,
- .collectionViewBaseChrome-viewSpecsMenu-rowRight {
- font-size: 75%;
- letter-spacing: 2px;
- color: grey;
- margin-left: 10px;
- padding: 5px;
- border: none;
- outline-color: black;
- }
- }
-
- .collectionViewBaseChrome-viewSpecsMenu-lastRow {
- display: grid;
- grid-template-columns: 1fr 1fr 1fr;
- grid-gap: 10px;
- margin: 10px;
- }
- }
}
}
button:hover {
transform: scale(1);
}
-
- .collectionStackingViewChrome-sectionFilter:hover {
- cursor: text;
- }
}
}
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index 6e23d6fb7..173de64de 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -63,7 +63,7 @@ export class WebBox extends React.Component<FieldViewProps> {
@action
setURL() {
- let urlField: FieldResult<WebField> = Cast(this.props.Document.data, WebField)
+ let urlField: FieldResult<WebField> = Cast(this.props.Document.data, WebField);
if (urlField) this.url = urlField.url.toString();
else this.url = "";
}
@@ -97,8 +97,8 @@ export class WebBox extends React.Component<FieldViewProps> {
return (
<div className="webView-urlEditor" style={{ top: this.collapsed ? -70 : 0 }}>
<div className="urlEditor">
- <div className="collectionViewBaseChrome">
- <button className="collectionViewBaseChrome-collapse"
+ <div className="editorBase">
+ <button className="editor-collapse"
style={{
top: this.collapsed ? 70 : 10,
transform: `rotate(${this.collapsed ? 180 : 0}deg) scale(${this.collapsed ? 0.5 : 1}) translate(${this.collapsed ? "-100%, -100%" : "0, 0"})`,
diff --git a/src/client/views/search/SearchBox.scss b/src/client/views/search/SearchBox.scss
index fcdc79220..5ed33a596 100644
--- a/src/client/views/search/SearchBox.scss
+++ b/src/client/views/search/SearchBox.scss
@@ -37,6 +37,11 @@
margin-left: 2px;
margin-right: 2px
}
+
+ &.searchBox-close {
+ color: $light-color;
+ max-height: 32px;
+ }
}
}
diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx
index 2214ac8af..4dc409e77 100644
--- a/src/client/views/search/SearchBox.tsx
+++ b/src/client/views/search/SearchBox.tsx
@@ -4,6 +4,8 @@ import { observable, action, runInAction, flow, computed } from 'mobx';
import "./SearchBox.scss";
import "./FilterBox.scss";
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { faTimes } from '@fortawesome/free-solid-svg-icons';
+import { library } from '@fortawesome/fontawesome-svg-core';
import { SetupDrag } from '../../util/DragManager';
import { Docs } from '../../documents/Documents';
import { NumCast, Cast } from '../../../new_fields/Types';
@@ -14,8 +16,12 @@ import { Id } from '../../../new_fields/FieldSymbols';
import { SearchUtil } from '../../util/SearchUtil';
import { RouteStore } from '../../../server/RouteStore';
import { FilterBox } from './FilterBox';
+import { ReadStream } from 'fs';
+import * as $ from 'jquery';
+import { MainView } from '../MainView';
import { Utils } from '../../../Utils';
+library.add(faTimes);
@observer
export class SearchBox extends React.Component {
@@ -29,6 +35,7 @@ export class SearchBox extends React.Component {
@observable private _visibleElements: JSX.Element[] = [];
private resultsRef = React.createRef<HTMLDivElement>();
+ public inputRef = React.createRef<HTMLInputElement>();
private _isSearch: ("search" | "placeholder" | undefined)[] = [];
private _numTotalResults = -1;
@@ -46,6 +53,15 @@ export class SearchBox extends React.Component {
this.resultsScrolled = this.resultsScrolled.bind(this);
}
+ componentDidMount = () => {
+ if (this.inputRef.current) {
+ this.inputRef.current.focus();
+ runInAction(() => {
+ this._searchbarOpen = true;
+ });
+ }
+ }
+
@action
getViews = async (doc: Doc) => {
const results = await SearchUtil.GetViewsOfDocument(doc);
@@ -229,6 +245,7 @@ export class SearchBox extends React.Component {
@action.bound
closeSearch = () => {
+ console.log("closing search")
FilterBox.Instance.closeFilter();
this.closeResults();
this._searchbarOpen = false;
@@ -321,11 +338,12 @@ export class SearchBox extends React.Component {
<span className="searchBox-barChild searchBox-collection" onPointerDown={SetupDrag(this.collectionRef, this.startDragCollection)} ref={this.collectionRef} title="Drag Results as Collection">
<FontAwesomeIcon icon="object-group" size="lg" />
</span>
- <input value={this._searchString} onChange={this.onChange} type="text" placeholder="Search..."
+ <input value={this._searchString} onChange={this.onChange} type="text" placeholder="Search..." id="search-input" ref={this.inputRef}
className="searchBox-barChild searchBox-input" onPointerDown={this.openSearch} onKeyPress={this.enter}
style={{ width: this._searchbarOpen ? "500px" : "100px" }} />
<button className="searchBox-barChild searchBox-submit" onClick={this.submitSearch} onPointerDown={FilterBox.Instance.stopProp}>Submit</button>
<button className="searchBox-barChild searchBox-filter" onClick={FilterBox.Instance.openFilter} onPointerDown={FilterBox.Instance.stopProp}>Filter</button>
+ <button className="searchBox-barChild searchBox-close" title={"Close Search Bar"} onPointerDown={MainView.Instance.toggleSearch}><FontAwesomeIcon icon={faTimes} size="lg" /></button>
</div>
<div className="searchBox-results" onScroll={this.resultsScrolled} style={{
display: this._resultsOpen ? "flex" : "none",
@@ -336,5 +354,4 @@ export class SearchBox extends React.Component {
</div>
);
}
-
} \ No newline at end of file
diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts
index d634cf57f..425d532c0 100644
--- a/src/new_fields/Doc.ts
+++ b/src/new_fields/Doc.ts
@@ -329,12 +329,12 @@ export namespace Doc {
export function AddDocToList(target: Doc, key: string, doc: Doc, relativeTo?: Doc, before?: boolean, first?: boolean, allowDuplicates?: boolean) {
if (target[key] === undefined) {
- console.log("target key undefined");
+ // console.log("target key undefined");
Doc.GetProto(target)[key] = new List<Doc>();
}
let list = Cast(target[key], listSpec(Doc));
if (list) {
- console.log("has list");
+ // console.log("has list");
if (allowDuplicates !== true) {
let pind = list.reduce((l, d, i) => d instanceof Doc && Doc.AreProtosEqual(d, doc) ? i : l, -1);
if (pind !== -1) {
@@ -342,15 +342,15 @@ export namespace Doc {
}
}
if (first) {
- console.log("is first");
+ // console.log("is first");
list.splice(0, 0, doc);
}
else {
- console.log("not first");
+ // console.log("not first");
let ind = relativeTo ? list.indexOf(relativeTo) : -1;
if (ind === -1) list.push(doc);
else list.splice(before ? ind : ind + 1, 0, doc);
- console.log("index", ind);
+ // console.log("index", ind);
}
}
return true;
@@ -595,23 +595,66 @@ export namespace Doc {
});
}
+ export function isBrushedHighlightedDegree(doc: Doc) {
+ if (Doc.IsHighlighted(doc)) {
+ return 3;
+ }
+ else {
+ return Doc.IsBrushedDegree(doc);
+ }
+ }
+
export class DocBrush {
@observable BrushedDoc: ObservableMap<Doc, boolean> = new ObservableMap();
}
- const manager = new DocBrush();
+ const brushManager = new DocBrush();
export function IsBrushed(doc: Doc) {
- return manager.BrushedDoc.has(doc) || manager.BrushedDoc.has(Doc.GetDataDoc(doc));
+ return brushManager.BrushedDoc.has(doc) || brushManager.BrushedDoc.has(Doc.GetDataDoc(doc));
}
export function IsBrushedDegree(doc: Doc) {
- return manager.BrushedDoc.has(Doc.GetDataDoc(doc)) ? 2 : manager.BrushedDoc.has(doc) ? 1 : 0;
+ return brushManager.BrushedDoc.has(Doc.GetDataDoc(doc)) ? 2 : brushManager.BrushedDoc.has(doc) ? 1 : 0;
}
export function BrushDoc(doc: Doc) {
- manager.BrushedDoc.set(doc, true);
- manager.BrushedDoc.set(Doc.GetDataDoc(doc), true);
+ brushManager.BrushedDoc.set(doc, true);
+ brushManager.BrushedDoc.set(Doc.GetDataDoc(doc), true);
}
export function UnBrushDoc(doc: Doc) {
- manager.BrushedDoc.delete(doc);
- manager.BrushedDoc.delete(Doc.GetDataDoc(doc));
+ brushManager.BrushedDoc.delete(doc);
+ brushManager.BrushedDoc.delete(Doc.GetDataDoc(doc));
+ }
+
+ export class HighlightBrush {
+ @observable HighlightedDoc: ObservableMap<Doc, boolean> = new ObservableMap();
+ }
+ const highlightManager = new HighlightBrush();
+ export function IsHighlighted(doc: Doc) {
+ // return highlightManager.HighlightedDoc.has(doc) || highlightManager.HighlightedDoc.has(Doc.GetDataDoc(doc));
+ return highlightManager.HighlightedDoc.get(doc) || highlightManager.HighlightedDoc.get(Doc.GetDataDoc(doc));
+ }
+ export function HighlightDoc(doc: Doc) {
+ console.log("is highlighting")
+ runInAction(() => {
+ highlightManager.HighlightedDoc.set(doc, true);
+ highlightManager.HighlightedDoc.set(Doc.GetDataDoc(doc), true);
+ });
+ }
+ export function UnHighlightDoc(doc: Doc) {
+ // highlightManager.HighlightedDoc.delete(doc);
+ // highlightManager.HighlightedDoc.delete(Doc.GetDataDoc(doc));
+ runInAction(() => {
+ highlightManager.HighlightedDoc.set(doc, false);
+ highlightManager.HighlightedDoc.set(Doc.GetDataDoc(doc), false);
+ })
+ }
+ export function UnhighlightAll() {
+ // highlightManager.HighlightedDoc.clear();
+ let docs = highlightManager.HighlightedDoc.keys();
+ let doc = docs.next();
+ while (docs.next !== null) {
+ Doc.UnHighlightDoc(doc.value);
+ doc = docs.next();
+ }
+
}
}
Scripting.addGlobal(function renameAlias(doc: any, n: any) { return StrCast(doc.title).replace(/\([0-9]*\)/, "") + `(${n})`; });
diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts
index 91d7ba87d..f36f5b73d 100644
--- a/src/server/authentication/models/current_user_utils.ts
+++ b/src/server/authentication/models/current_user_utils.ts
@@ -41,8 +41,6 @@ export class CurrentUserUtils {
doc.boxShadow = "0 0";
doc.excludeFromLibrary = true;
doc.optionalRightCollection = Docs.Create.StackingDocument([], { title: "New mobile uploads" });
- // doc.library = Docs.Create.TreeDocument([doc], { title: `Library: ${CurrentUserUtils.email}` });
- // (doc.library as Doc).excludeFromLibrary = true;
return doc;
}
diff --git a/views/stylesheets/authentication.css b/views/stylesheets/authentication.css
index dea0474e4..36bb880af 100644
--- a/views/stylesheets/authentication.css
+++ b/views/stylesheets/authentication.css
@@ -69,10 +69,10 @@ body {
.workspaceId {
list-style-type: none;
- font-family: Arial, Helvetica, sans-serif;
+ font-family: Arial, Helvetica, sans-serif;
margin-left: -20px;
cursor: grab;
- padding-bottom: 15px;
+ padding-bottom: 15px;
}
.workspaceId:hover {
@@ -106,7 +106,7 @@ body {
}
.overlay {
- border: 2px solid yellow;
+ border: 2px gray;
text-align: center;
position: absolute;
margin: auto;