From d10a091db9b2dd2656fde172628d62c4dbf67970 Mon Sep 17 00:00:00 2001 From: laurawilsonri Date: Sun, 10 Mar 2019 20:23:56 -0400 Subject: changed the format of the text tooltip menu --- src/client/util/TooltipTextMenu.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/client/util/TooltipTextMenu.tsx') diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx index 3b87fe9de..8cc653bf2 100644 --- a/src/client/util/TooltipTextMenu.tsx +++ b/src/client/util/TooltipTextMenu.tsx @@ -117,7 +117,7 @@ export class TooltipTextMenu { let width = Math.abs(start.left - end.left) / 2; let mid = Math.min(start.left, end.left) + width; //THIS WIDTH IS 15 * NUMBER OF ICONS + 15 - this.tooltip.style.width = 120 + "px"; + this.tooltip.style.width = 122 + "px"; this.tooltip.style.bottom = (box.bottom - start.top) + "px"; } -- cgit v1.2.3-70-g09d2 From bff0093163bdc05fb661eb744c2333069544dc89 Mon Sep 17 00:00:00 2001 From: laurawilsonri Date: Mon, 11 Mar 2019 18:48:58 -0400 Subject: added a method to check if block has a syle ie bullets --- src/client/util/RichTextSchema.tsx | 44 +++++++++++++++++++++++++---- src/client/util/TooltipTextMenu.tsx | 3 +- src/client/views/nodes/FormattedTextBox.tsx | 2 ++ 3 files changed, 41 insertions(+), 8 deletions(-) (limited to 'src/client/util/TooltipTextMenu.tsx') diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx index abf448c9f..341d5a443 100644 --- a/src/client/util/RichTextSchema.tsx +++ b/src/client/util/RichTextSchema.tsx @@ -1,12 +1,31 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { Schema, NodeSpec, MarkSpec, DOMOutputSpecArray } from "prosemirror-model" +import { Schema, NodeSpec, MarkSpec, DOMOutputSpecArray, NodeType } from "prosemirror-model" import { joinUp, lift, setBlockType, toggleMark, wrapIn } from 'prosemirror-commands' import { redo, undo } from 'prosemirror-history' -import { orderedList, bulletList, listItem } from 'prosemirror-schema-list' +import { orderedList, bulletList, listItem, } from 'prosemirror-schema-list' +import { EditorState, Transaction, NodeSelection, } from "prosemirror-state"; +import { EditorView, } from "prosemirror-view"; const pDOM: DOMOutputSpecArray = ["p", 0], blockquoteDOM: DOMOutputSpecArray = ["blockquote", 0], hrDOM: DOMOutputSpecArray = ["hr"], preDOM: DOMOutputSpecArray = ["pre", ["code", 0]], brDOM: DOMOutputSpecArray = ["br"], ulDOM: DOMOutputSpecArray = ["ul", 0] +//adapted this method - use it to check if block has a tag (ie bulleting) +const blockActive = (type: NodeType>, attrs = {}) => (state: EditorState) => { + + if (state.selection instanceof NodeSelection) { + const sel: NodeSelection = state.selection; + let $from = sel.$from; + let to = sel.to; + let node = sel.node; + + if (node) { + return node.hasMarkup(type, attrs); + } + + return to <= $from.end() && $from.parent.hasMarkup(type, attrs); + } +}; + // :: Object // [Specs](#model.NodeSpec) for the nodes defined in this schema. export const nodes: { [index: string]: NodeSpec } = { @@ -113,11 +132,24 @@ export const nodes: { [index: string]: NodeSpec } = { content: 'list_item+', group: 'block' }, + //bullet_list: { + // ...bulletList, + // content: 'list_item+', + // group: 'block', + //parseDOM: [{ tag: "ul" }, { style: 'list-style-type=disc' }], + //toDOM() { return ulDOM } + //}, bullet_list: { - content: 'list_item+', - group: 'block', - parseDOM: [{ tag: "ul" }, { style: "list-style-type=disc;" }], - toDOM() { return ulDOM } + title: "Wrap in bullet list", + content: icons.bullet_list, + active: blockActive(state.config.schema.nodes.bullet_list), + enable: state => wrapInList(state.config.schema.nodes.bullet_list), + run: state => wrapInList(state.config.schema.nodes.bullet_list), + active: blockActive(schema.nodes.bullet_list), + enable: wrapInList(schema.nodes.bullet_list), + run: wrapInList(schema.nodes.bullet_list), + select: state => true, + menu: props => ,
@@ -310,7 +311,7 @@ export class Main extends React.Component {
,
- ] + ]; } render() { @@ -318,7 +319,7 @@ export class Main extends React.Component { let workspaces = this.userDocument.GetT>(KeyStore.Workspaces, ListField); if (workspaces && workspaces !== FieldWaiting) { workspaceMenu = + isShown={this.areWorkspacesShown} toggle={this.toggleWorkspaces} />; } return ( <> @@ -359,7 +360,7 @@ export class Main extends React.Component { schemaDocuments.push(field); } else { var atmod = new ColumnAttributeModel(attr); - let histoOp = new HistogramOperation(schema!.displayName!, + let histoOp = new HistogramOperation(schema.displayName!, new AttributeTransformationModel(atmod, AggregateFunction.None), new AttributeTransformationModel(atmod, AggregateFunction.Count), new AttributeTransformationModel(atmod, AggregateFunction.Count)); @@ -368,7 +369,7 @@ export class Main extends React.Component { })); }); return schemaDoc; - }) + }); } } async initializeNorthstar(): Promise { @@ -386,7 +387,7 @@ export class Main extends React.Component { } (async () => { - await Documents.initProtos() - await CurrentUserUtils.loadCurrentUser() + await Documents.initProtos(); + await CurrentUserUtils.loadCurrentUser(); ReactDOM.render(
, document.getElementById('root')); -})() +})(); diff --git a/src/client/views/collections/CollectionBaseView.tsx b/src/client/views/collections/CollectionBaseView.tsx index 7a5ab6e3c..32462a4c1 100644 --- a/src/client/views/collections/CollectionBaseView.tsx +++ b/src/client/views/collections/CollectionBaseView.tsx @@ -66,17 +66,20 @@ export class CollectionBaseView extends React.Component { createsCycle(documentToAdd: Document, containerDocument: Document): boolean { let data = documentToAdd.GetList(KeyStore.Data, []); for (const doc of data) { - if (this.createsCycle(doc, containerDocument)) + if (this.createsCycle(doc, containerDocument)) { return true; + } } let annots = documentToAdd.GetList(KeyStore.Annotations, []); for (const annot of annots) { - if (this.createsCycle(annot, containerDocument)) + if (this.createsCycle(annot, containerDocument)) { return true; + } } for (let containerProto: FieldValue = containerDocument; containerProto && containerProto !== FieldWaiting; containerProto = containerProto.GetPrototype()) { - if (containerProto.Id === documentToAdd.Id) + if (containerProto.Id === documentToAdd.Id) { return true; + } } return false; } @@ -91,20 +94,23 @@ export class CollectionBaseView extends React.Component { } if (props.Document.Get(props.fieldKey) instanceof Field) { //TODO This won't create the field if it doesn't already exist - const value = props.Document.GetData(props.fieldKey, ListField, new Array()) + const value = props.Document.GetData(props.fieldKey, ListField, new Array()); if (!this.createsCycle(doc, props.Document)) { - if (!value.some(v => v.Id === doc.Id) || allowDuplicates) + if (!value.some(v => v.Id === doc.Id) || allowDuplicates) { value.push(doc); + } } - else + else { return false; + } } else { let proto = props.Document.GetPrototype(); if (!proto || proto === FieldWaiting || !this.createsCycle(proto, doc)) { props.Document.SetOnPrototype(props.fieldKey, new ListField([doc])); } - else + else { return false; + } } return true; } @@ -113,7 +119,7 @@ export class CollectionBaseView extends React.Component { removeDocument(doc: Document): boolean { const props = this.props; //TODO This won't create the field if it doesn't already exist - const value = props.Document.GetData(props.fieldKey, ListField, new Array()) + const value = props.Document.GetData(props.fieldKey, ListField, new Array()); let index = -1; for (let i = 0; i < value.length; i++) { if (value[i].Id === doc.Id) { @@ -125,16 +131,16 @@ export class CollectionBaseView extends React.Component { if (annotationOn === props.Document) { doc.Set(KeyStore.AnnotationOn, undefined, true); } - }) + }); if (index !== -1) { - value.splice(index, 1) + value.splice(index, 1); // SelectionManager.DeselectAll() - ContextMenu.Instance.clearItems() + ContextMenu.Instance.clearItems(); return true; } - return false + return false; } @action.bound @@ -155,12 +161,12 @@ export class CollectionBaseView extends React.Component { moveDocument: this.moveDocument, active: this.active, onActiveChanged: this.onActiveChanged, - } + }; return (
{this.props.children(this.collectionViewType, props)}
- ) + ); } } \ No newline at end of file diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index c3757a377..ea6d3a247 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -32,7 +32,7 @@ export class CollectionDockingView extends React.Component) => { - if (f instanceof Document) - DragManager.StartDocumentDrag([tab], new DragManager.DocumentDragData([f as Document]), e.pageX, e.pageY, + if (f instanceof Document) { + DragManager.StartDocumentDrag([tab], new DragManager.DocumentDragData([f]), e.pageX, e.pageY, { handlers: { dragComplete: action(() => { }), }, hideSource: false - }) + }); + } })); } if (className === "lm_drag_handle" || className === "lm_close" || className === "lm_maximise" || className === "lm_minimise" || className === "lm_close_tab") { @@ -220,7 +222,7 @@ export class CollectionDockingView extends React.Component { var json = JSON.stringify(this._goldenLayout.toConfig()); - this.props.Document.SetText(KeyStore.Data, json) + this.props.Document.SetText(KeyStore.Data, json); } itemDropped = () => { @@ -236,7 +238,7 @@ export class CollectionDockingView extends React.Component { Server.GetField(this.props.documentId, action((f: Opt) => this._document = f as Document)); } - private _nativeWidth = () => this._document!.GetNumber(KeyStore.NativeWidth, this._panelWidth) - private _nativeHeight = () => this._document!.GetNumber(KeyStore.NativeHeight, this._panelHeight) - private _contentScaling = () => this._panelWidth / (this._nativeWidth() ? this._nativeWidth() : this._panelWidth) + private _nativeWidth = () => this._document!.GetNumber(KeyStore.NativeWidth, this._panelWidth); + private _nativeHeight = () => this._document!.GetNumber(KeyStore.NativeHeight, this._panelHeight); + private _contentScaling = () => this._panelWidth / (this._nativeWidth() ? this._nativeWidth() : this._panelWidth); ScreenToLocalTransform = () => { let { scale, translateX, translateY } = Utils.GetScreenTransform(this._mainCont.current!); - return CollectionDockingView.Instance.props.ScreenToLocalTransform().translate(-translateX, -translateY).scale(scale / this._contentScaling()) + return CollectionDockingView.Instance.props.ScreenToLocalTransform().translate(-translateX, -translateY).scale(scale / this._contentScaling()); } render() { - if (!this._document) + if (!this._document) { return (null); + } var content =
{ onActiveChanged={emptyFunction} focus={(doc: Document) => { }} ContainingCollectionView={undefined} /> -
+ ; return { this._panelWidth = r.entry.width; this._panelHeight = r.entry.height; })}> {({ measureRef }) =>
{content}
} -
+ ; } } \ No newline at end of file diff --git a/src/client/views/collections/CollectionPDFView.tsx b/src/client/views/collections/CollectionPDFView.tsx index 32f50afc0..97bac745c 100644 --- a/src/client/views/collections/CollectionPDFView.tsx +++ b/src/client/views/collections/CollectionPDFView.tsx @@ -2,7 +2,7 @@ import { action, computed, observable } from "mobx"; import { observer } from "mobx-react"; import { KeyStore } from "../../../fields/KeyStore"; import { ContextMenu } from "../ContextMenu"; -import "./CollectionPDFView.scss" +import "./CollectionPDFView.scss"; import React = require("react"); import { CollectionFreeFormView } from "./collectionFreeForm/CollectionFreeFormView"; import { FieldView, FieldViewProps } from "../nodes/FieldView"; @@ -44,7 +44,7 @@ export class CollectionPDFView extends React.Component { {this.props.isSelected() ? this.uIButtons : (null)} - ) + ); } render() { @@ -52,6 +52,6 @@ export class CollectionPDFView extends React.Component { {this.subView} - ) + ); } } \ No newline at end of file diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx index 9b780f29b..52933818f 100644 --- a/src/client/views/collections/CollectionSchemaView.tsx +++ b/src/client/views/collections/CollectionSchemaView.tsx @@ -1,4 +1,4 @@ -import React = require("react") +import React = require("react"); import { library } from '@fortawesome/fontawesome-svg-core'; import { faCog, faPlus } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; @@ -41,7 +41,7 @@ class KeyToggle extends React.Component<{ keyId: string, checked: boolean, toggl if (field instanceof Key) { this.key = field; } - })) + })); } render() { @@ -49,7 +49,7 @@ class KeyToggle extends React.Component<{ keyId: string, checked: boolean, toggl return (
this.key && this.props.toggle(this.key)} /> {this.key.Name} -
) + ); } return (null); } @@ -85,10 +85,10 @@ export class CollectionSchemaView extends CollectionSubView { focus: emptyFunction, active: returnFalse, onActiveChanged: emptyFunction, - } + }; let contents = ( - ) + ); let reference = React.createRef(); let onItemDown = setupDrag(reference, () => props.Document, this.props.moveDocument); let applyToDoc = (doc: Document, run: (args?: { [name: string]: any }) => any) => { @@ -106,7 +106,7 @@ export class CollectionSchemaView extends CollectionSubView { } } return false; - } + }; return (
applyToDoc(doc, run)); } - }) + }); }}>
- ) + ); } private getTrProps: ComponentPropsGetterR = (state, rowInfo) => { @@ -156,7 +156,7 @@ export class CollectionSchemaView extends CollectionSubView { that._selectedIndex = rowInfo.index; if (handleOriginal) { - handleOriginal() + handleOriginal(); } }), style: { @@ -182,7 +182,7 @@ export class CollectionSchemaView extends CollectionSubView { this.columns.splice(index, 1); } - }) + }); } //toggles preview side-panel of schema @@ -197,7 +197,7 @@ export class CollectionSchemaView extends CollectionSubView { @computed get findAllDocumentKeys(): { [id: string]: boolean } { const docs = this.props.Document.GetList(this.props.fieldKey, []); - let keys: { [id: string]: boolean } = {} + let keys: { [id: string]: boolean } = {}; if (this._optionsActivated > -1) { // bcz: ugh. this is untracked since otherwise a large collection of documents will blast the server for all their fields. // then as each document's fields come back, we update the documents _proxies. Each time we do this, the whole schema will be @@ -206,7 +206,7 @@ export class CollectionSchemaView extends CollectionSubView { // is displayed (unlikely) it won't show up until something else changes. untracked(() => docs.map(doc => doc.GetAllPrototypes().map(proto => proto._proxies.forEach((val: any, key: string) => keys[key] = false)))); } - this.columns.forEach(key => keys[key.Id] = true) + this.columns.forEach(key => keys[key.Id] = true); return keys; } @@ -248,10 +248,10 @@ export class CollectionSchemaView extends CollectionSubView { getContentScaling = (): number => this._contentScaling; getPanelWidth = (): number => this._panelWidth; getPanelHeight = (): number => this._panelHeight; - getTransform = (): Transform => this.props.ScreenToLocalTransform().translate(- COLLECTION_BORDER_WIDTH - this.DIVIDER_WIDTH - this._dividerX, - COLLECTION_BORDER_WIDTH).scale(1 / this._contentScaling) - getPreviewTransform = (): Transform => this.props.ScreenToLocalTransform().translate(- COLLECTION_BORDER_WIDTH - this.DIVIDER_WIDTH - this._dividerX - this._tableWidth, - COLLECTION_BORDER_WIDTH).scale(1 / this._contentScaling) + getTransform = (): Transform => this.props.ScreenToLocalTransform().translate(- COLLECTION_BORDER_WIDTH - this.DIVIDER_WIDTH - this._dividerX, - COLLECTION_BORDER_WIDTH).scale(1 / this._contentScaling); + getPreviewTransform = (): Transform => this.props.ScreenToLocalTransform().translate(- COLLECTION_BORDER_WIDTH - this.DIVIDER_WIDTH - this._dividerX - this._tableWidth, - COLLECTION_BORDER_WIDTH).scale(1 / this._contentScaling); - focusDocument = (doc: Document) => { } + focusDocument = (doc: Document) => { }; onPointerDown = (e: React.PointerEvent): void => { if (this.props.isSelected()) { @@ -273,8 +273,9 @@ export class CollectionSchemaView extends CollectionSubView { this.newKeyName = e.currentTarget.value; } onWheel = (e: React.WheelEvent): void => { - if (this.props.active()) + if (this.props.active()) { e.stopPropagation(); + } } @observable _optionsActivated: number = 0; @@ -322,9 +323,9 @@ export class CollectionSchemaView extends CollectionSubView { } - ) + ); let dividerDragger = this.splitPercentage === 0 ? (null) : -
+
; //options button and menu let optionsMenu = !this.props.active() ? (null) : (
- ) + ); } } \ No newline at end of file diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 59b89e119..bd385c27e 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -14,7 +14,7 @@ import { NumberField } from "../../../fields/NumberField"; import { ServerUtils } from "../../../server/ServerUtil"; import { Server } from "../../Server"; import { FieldViewProps } from "../nodes/FieldView"; -import * as rp from 'request-promise' +import * as rp from 'request-promise'; export interface CollectionViewProps extends FieldViewProps { addDocument: (document: Document, allowDuplicates?: boolean) => boolean; @@ -58,8 +58,8 @@ export class CollectionSubView extends React.Component { let entry = new TupleField<[string, string], [number, number]>([textInfo, position]); cursors.push(entry); } - })) - }) + })); + }); } } @@ -77,17 +77,17 @@ export class CollectionSubView extends React.Component { added = de.data.droppedDocuments.reduce((added: boolean, d) => added || this.props.addDocument(d), false); } else if (de.data.moveDocument) { const move = de.data.moveDocument; - added = de.data.droppedDocuments.reduce((added: boolean, d) => added || move(d, this.props.Document, this.props.addDocument), false) + added = de.data.droppedDocuments.reduce((added: boolean, d) => added || move(d, this.props.Document, this.props.addDocument), false); } else { - added = de.data.droppedDocuments.reduce((added: boolean, d) => added || this.props.addDocument(d), false) + added = de.data.droppedDocuments.reduce((added: boolean, d) => added || this.props.addDocument(d), false); } e.stopPropagation(); return added; } if (de.data instanceof DragManager.LinkDragData) { let sourceDoc: Document = de.data.linkSourceDocumentView.props.Document; - if (sourceDoc) runInAction(() => { - let srcTarg = sourceDoc.GetT(KeyStore.Prototype, Document) + if (sourceDoc) { runInAction(() => { + let srcTarg = sourceDoc.GetT(KeyStore.Prototype, Document); if (srcTarg && srcTarg !== FieldWaiting) { let linkDocs = srcTarg.GetList(KeyStore.LinkedToDocs, [] as Document[]); linkDocs.map(linkDoc => { @@ -97,9 +97,10 @@ export class CollectionSubView extends React.Component { de.data.droppedDocuments.push(dropdoc); this.props.addDocument(dropdoc, false); } - }) + }); } - }) + }); + } return true; } return false; @@ -133,7 +134,7 @@ export class CollectionSubView extends React.Component { alias.SetNumber(KeyStore.Height, options.height || options.width || 300); this.props.addDocument(alias, false); } - }) + }); return undefined; } ctor = Documents.WebDocument; @@ -151,8 +152,8 @@ export class CollectionSubView extends React.Component { if (text && text.startsWith(" { let prom = new Promise(res => e.dataTransfer.items[i].getAsString(res)).then(action((s: string) => { str = s; - return rp.head(ServerUtils.prepend(RouteStore.corsProxy + "/" + s)) + return rp.head(ServerUtils.prepend(RouteStore.corsProxy + "/" + s)); })).then(res => { let type = res.headers["content-type"]; if (type) { - let doc = this.getDocumentFromType(type, str, { ...options, width: 300, nativeWidth: 300 }) + let doc = this.getDocumentFromType(type, str, { ...options, width: 300, nativeWidth: 300 }); if (doc) { this.props.addDocument(doc, false); } @@ -186,13 +187,13 @@ export class CollectionSubView extends React.Component { promises.push(prom); // this.props.addDocument(Documents.WebDocument(s, { ...options, width: 300, height: 300 }), false) } - let type = item.type + let type = item.type; if (item.kind === "file") { let file = item.getAsFile(); - let formData = new FormData() + let formData = new FormData(); if (file) { - formData.append('file', file) + formData.append('file', file); } let prom = fetch(upload, { @@ -201,15 +202,15 @@ export class CollectionSubView extends React.Component { }).then(async (res: Response) => { const json = await res.json(); json.map((file: any) => { - let path = window.location.origin + file + let path = window.location.origin + file; runInAction(() => { - let doc = this.getDocumentFromType(type, path, { ...options, nativeWidth: 300, width: 300 }) + let doc = this.getDocumentFromType(type, path, { ...options, nativeWidth: 300, width: 300 }); let docs = this.props.Document.GetT(KeyStore.Data, ListField); if (docs !== FieldWaiting) { if (!docs) { docs = new ListField(); - this.props.Document.Set(KeyStore.Data, docs) + this.props.Document.Set(KeyStore.Data, docs); } if (doc) { docs.Data.push(doc); diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 2bdf0baa6..659cff9fe 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -12,7 +12,7 @@ import { EditableView } from "../EditableView"; import "./CollectionTreeView.scss"; import { CollectionView } from "./CollectionView"; import { CollectionSubView } from "./CollectionSubView"; -import React = require("react") +import React = require("react"); import { COLLECTION_BORDER_WIDTH } from './CollectionBaseView'; import { props } from 'bluebird'; @@ -58,7 +58,7 @@ class TreeView extends React.Component { return true; } //TODO This should check if it was removed - this.remove(document) + this.remove(document); return addDoc(document); } @@ -69,7 +69,7 @@ class TreeView extends React.Component { case BulletType.Collapsed: bullet = "caret-right"; break; case BulletType.Collapsible: bullet = "caret-down"; break; } - return
{bullet ? : ""}
+ return
{bullet ? : ""}
; } /** @@ -93,7 +93,7 @@ class TreeView extends React.Component {
{editableView(this.props.document.Title)}
-
) +
); } render() { @@ -105,7 +105,7 @@ class TreeView extends React.Component { bulletType = BulletType.Collapsible; childElements =
    {children.Data.map(value => )} -
+ ; } else bulletType = BulletType.Collapsed; } @@ -115,7 +115,7 @@ class TreeView extends React.Component { {this.renderTitle()} {childElements ? childElements : (null)} - + ; } } @@ -136,7 +136,7 @@ export class CollectionTreeView extends CollectionSubView { let childrenElement = !children || children === FieldWaiting ? (null) : (children.Data.map(value => ) - ) + ); return (
e.stopPropagation()} onDrop={(e: React.DragEvent) => this.onDrop(e, {})} ref={this.createDropTarget} style={{ borderWidth: `${COLLECTION_BORDER_WIDTH}px` }}> diff --git a/src/client/views/collections/CollectionVideoView.tsx b/src/client/views/collections/CollectionVideoView.tsx index 1acc76c85..b02983a2e 100644 --- a/src/client/views/collections/CollectionVideoView.tsx +++ b/src/client/views/collections/CollectionVideoView.tsx @@ -4,7 +4,7 @@ import { KeyStore } from "../../../fields/KeyStore"; import { ContextMenu } from "../ContextMenu"; import { CollectionViewType, CollectionBaseView, CollectionRenderProps } from "./CollectionBaseView"; import React = require("react"); -import "./CollectionVideoView.scss" +import "./CollectionVideoView.scss"; import { CollectionFreeFormView } from "./collectionFreeForm/CollectionFreeFormView"; import { FieldView, FieldViewProps } from "../nodes/FieldView"; @@ -111,7 +111,7 @@ export class CollectionVideoView extends React.Component { {this.props.isSelected() ? this.uIButtons : (null)} - ) + ); } render() { @@ -119,6 +119,6 @@ export class CollectionVideoView extends React.Component { return ( {this.subView} - ) + ); } } \ No newline at end of file diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index b31dcc888..8abd0a02d 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -1,4 +1,4 @@ -import * as React from 'react' +import * as React from 'react'; import { FieldViewProps, FieldView } from '../nodes/FieldView'; import { CollectionBaseView, CollectionViewType, CollectionRenderProps } from './CollectionBaseView'; import { CollectionFreeFormView } from './collectionFreeForm/CollectionFreeFormView'; @@ -13,26 +13,26 @@ import { undoBatch } from '../../util/UndoManager'; @observer export class CollectionView extends React.Component { - public static LayoutString(fieldStr: string = "DataKey") { return FieldView.LayoutString(CollectionView, fieldStr) } + public static LayoutString(fieldStr: string = "DataKey") { return FieldView.LayoutString(CollectionView, fieldStr); } private SubView = (type: CollectionViewType, renderProps: CollectionRenderProps) => { let props = { ...this.props, ...renderProps }; switch (type) { - case CollectionViewType.Schema: return () - case CollectionViewType.Docking: return () - case CollectionViewType.Tree: return () + case CollectionViewType.Schema: return (); + case CollectionViewType.Docking: return (); + case CollectionViewType.Tree: return (); case CollectionViewType.Freeform: default: - return () + return (); } return (null); } onContextMenu = (e: React.MouseEvent): void => { if (!e.isPropagationStopped() && this.props.Document.Id !== CurrentUserUtils.MainDocId) { // need to test this because GoldenLayout causes a parallel hierarchy in the React DOM for its children and the main document view7 - ContextMenu.Instance.addItem({ description: "Freeform", event: undoBatch(() => this.props.Document.SetNumber(KeyStore.ViewType, CollectionViewType.Freeform)) }) - ContextMenu.Instance.addItem({ description: "Schema", event: undoBatch(() => this.props.Document.SetNumber(KeyStore.ViewType, CollectionViewType.Schema)) }) - ContextMenu.Instance.addItem({ description: "Treeview", event: undoBatch(() => this.props.Document.SetNumber(KeyStore.ViewType, CollectionViewType.Tree)) }) + ContextMenu.Instance.addItem({ description: "Freeform", event: undoBatch(() => this.props.Document.SetNumber(KeyStore.ViewType, CollectionViewType.Freeform)) }); + ContextMenu.Instance.addItem({ description: "Schema", event: undoBatch(() => this.props.Document.SetNumber(KeyStore.ViewType, CollectionViewType.Schema)) }); + ContextMenu.Instance.addItem({ description: "Treeview", event: undoBatch(() => this.props.Document.SetNumber(KeyStore.ViewType, CollectionViewType.Tree)) }); } } @@ -41,6 +41,6 @@ export class CollectionView extends React.Component { {this.SubView} - ) + ); } } \ No newline at end of file diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx index 3dfd74ec8..081b3eb6c 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx @@ -32,6 +32,6 @@ export class CollectionFreeFormLinkView extends React.Component - ) + ); } } \ No newline at end of file diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx index c288e7abf..cf058090d 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx @@ -17,7 +17,7 @@ export class CollectionFreeFormLinksView extends React.Component DocumentManager.Instance.getAllDocumentViews(this.HackToAvoidReactionFiringUnnecessarily!). map(dv => dv.props.Document.GetNumber(KeyStore.X, 0)), @@ -31,13 +31,14 @@ export class CollectionFreeFormLinksView extends React.Component) => field.Data.findIndex(brush => { let bdocs = brush ? brush.GetList(KeyStore.BrushingDocs, [] as Document[]) : []; - return (bdocs.length && ((bdocs[0] === dstTarg && bdocs[1] === srcTarg)) ? true : false) + return (bdocs.length && ((bdocs[0] === dstTarg && bdocs[1] === srcTarg)) ? true : false); }); let brushAction = (field: ListField) => { let found = findBrush(field); @@ -64,13 +65,13 @@ export class CollectionFreeFormLinksView extends React.Component sv.props.ContainingCollectionView && sv.props.ContainingCollectionView.props.Document === this.props.Document); } @@ -86,15 +87,16 @@ export class CollectionFreeFormLinksView extends React.Component { let match = (possiblePair.a === drawnPair.a && possiblePair.b === drawnPair.b); if (match) { - if (!drawnPair.l.reduce((found, link) => found || link.Id === connection.l.Id, false)) + if (!drawnPair.l.reduce((found, link) => found || link.Id === connection.l.Id, false)) { drawnPair.l.push(connection.l); + } } return match || found; }, false)) { drawnPairs.push({ a: possiblePair.a, b: possiblePair.b, l: [connection.l] }); } - }) - return drawnPairs + }); + return drawnPairs; }, [] as { a: Document, b: Document, l: Document[] }[]); return connections.map(c => ); } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx index 17656e4ae..fc832264d 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx @@ -57,7 +57,7 @@ export class CollectionFreeFormRemoteCursors extends React.Component { if (el) this.crosshairs = el }} + ref={(el) => { if (el) this.crosshairs = el; }} width={20} height={20} style={{ @@ -93,7 +93,7 @@ export class CollectionFreeFormRemoteCursors extends React.Component ); } - }) + }); } render() { diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 1c3899b24..e694bc7a7 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -49,7 +49,7 @@ export class CollectionFreeFormView extends CollectionSubView { if (dv) { SelectionManager.SelectDoc(dv, true); } - }) + }); } public getActiveDocuments = () => { @@ -70,8 +70,8 @@ export class CollectionFreeFormView extends CollectionSubView { private outerElement?: HTMLDivElement; - @computed get panX(): number { return this.props.Document.GetNumber(KeyStore.PanX, 0) } - @computed get panY(): number { return this.props.Document.GetNumber(KeyStore.PanY, 0) } + @computed get panX(): number { return this.props.Document.GetNumber(KeyStore.PanX, 0); } + @computed get panY(): number { return this.props.Document.GetNumber(KeyStore.PanY, 0); } @computed get scale(): number { return this.props.Document.GetNumber(KeyStore.Scale, 1); } @computed get isAnnotationOverlay() { return this.props.fieldKey && this.props.fieldKey.Id === KeyStore.Annotations.Id; } // bcz: ? Why do we need to compare Id's? @computed get nativeWidth() { return this.props.Document.GetNumber(KeyStore.NativeWidth, 0); } @@ -109,7 +109,7 @@ export class CollectionFreeFormView extends CollectionSubView { d.SetNumber(KeyStore.Height, 300); } this.bringToFront(d); - }) + }); } } return true; @@ -133,8 +133,9 @@ export class CollectionFreeFormView extends CollectionSubView { document.addEventListener("pointerup", this.onPointerUp); this._lastX = this.DownX = e.pageX; this._lastY = this.DownY = e.pageY; - if (this.props.isSelected()) + if (this.props.isSelected()) { e.stopPropagation(); + } } } @@ -182,12 +183,13 @@ export class CollectionFreeFormView extends CollectionSubView { let transform = this.getTransform(); let deltaScale = (1 - (e.deltaY / coefficient)); - if (deltaScale * this.zoomScaling < 1 && this.isAnnotationOverlay) + if (deltaScale * this.zoomScaling < 1 && this.isAnnotationOverlay) { deltaScale = 1 / this.zoomScaling; + } let [x, y] = transform.transformPoint(e.clientX, e.clientY); - let localTransform = this.getLocalTransform() - localTransform = localTransform.inverse().scaleAbout(deltaScale, x, y) + let localTransform = this.getLocalTransform(); + localTransform = localTransform.inverse().scaleAbout(deltaScale, x, y); // console.log(localTransform) this.props.Document.SetNumber(KeyStore.Scale, localTransform.Scale); @@ -209,7 +211,7 @@ export class CollectionFreeFormView extends CollectionSubView { onDrop = (e: React.DragEvent): void => { var pt = this.getTransform().transformPoint(e.pageX, e.pageY); super.onDrop(e, { x: pt[0], y: pt[1] }); - }; + } onDragOver = (): void => { } @@ -228,7 +230,7 @@ export class CollectionFreeFormView extends CollectionSubView { } return doc1.GetNumber(KeyStore.ZIndex, 0) - doc2.GetNumber(KeyStore.ZIndex, 0); }).map((doc, index) => { - doc.SetNumber(KeyStore.ZIndex, index + 1) + doc.SetNumber(KeyStore.ZIndex, index + 1); }); } @@ -268,7 +270,7 @@ export class CollectionFreeFormView extends CollectionSubView { focus: this.focusDocument, parentActive: this.props.active, onActiveChanged: this.props.active, - } + }; } @computed @@ -276,10 +278,11 @@ export class CollectionFreeFormView extends CollectionSubView { var curPage = this.props.Document.GetNumber(KeyStore.CurPage, -1); return this.props.Document.GetList(this.props.fieldKey, [] as Document[]).filter(doc => doc).reduce((prev, doc) => { var page = doc.GetNumber(KeyStore.Page, -1); - if (page === curPage || page === -1) + if (page === curPage || page === -1) { prev.push(); + } return prev; - }, [] as JSX.Element[]) + }, [] as JSX.Element[]); } @computed @@ -295,8 +298,8 @@ export class CollectionFreeFormView extends CollectionSubView { layoutKey={KeyStore.OverlayLayout} isTopMost={this.props.isTopMost} isSelected={() => false} select={() => { }} />); } - getTransform = (): Transform => this.props.ScreenToLocalTransform().translate(-COLLECTION_BORDER_WIDTH, -COLLECTION_BORDER_WIDTH).translate(-this.centeringShiftX, -this.centeringShiftY).transform(this.getLocalTransform()) - getContainerTransform = (): Transform => this.props.ScreenToLocalTransform().translate(-COLLECTION_BORDER_WIDTH, -COLLECTION_BORDER_WIDTH) + getTransform = (): Transform => this.props.ScreenToLocalTransform().translate(-COLLECTION_BORDER_WIDTH, -COLLECTION_BORDER_WIDTH).translate(-this.centeringShiftX, -this.centeringShiftY).transform(this.getLocalTransform()); + getContainerTransform = (): Transform => this.props.ScreenToLocalTransform().translate(-COLLECTION_BORDER_WIDTH, -COLLECTION_BORDER_WIDTH); getLocalTransform = (): Transform => Transform.Identity().scale(1 / this.scale).translate(this.panX, this.panY); noScaling = () => 1; childViews = () => this.views; diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 704db1d4a..1e6faafb3 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -37,7 +37,7 @@ export class MarqueeView extends React.Component @action cleanupInteractions = (all: boolean = false) => { if (all) { - document.removeEventListener("pointermove", this.onPointerMove, true) + document.removeEventListener("pointermove", this.onPointerMove, true); document.removeEventListener("pointerup", this.onPointerUp, true); } else { this._used = true; @@ -52,7 +52,7 @@ export class MarqueeView extends React.Component this._downX = this._lastX = e.pageX; this._downY = this._lastY = e.pageY; this._used = false; - document.addEventListener("pointermove", this.onPointerMove, true) + document.addEventListener("pointermove", this.onPointerMove, true); document.addEventListener("pointerup", this.onPointerUp, true); document.addEventListener("keydown", this.marqueeCommand, true); } @@ -94,7 +94,7 @@ export class MarqueeView extends React.Component let top = this._downY < this._lastY ? this._downY : this._lastY; let topLeft = this.props.getTransform().transformPoint(left, top); let size = this.props.getTransform().transformDirection(this._lastX - this._downX, this._lastY - this._downY); - return { left: topLeft[0], top: topLeft[1], width: Math.abs(size[0]), height: Math.abs(size[1]) } + return { left: topLeft[0], top: topLeft[1], width: Math.abs(size[0]), height: Math.abs(size[1]) }; } @action @@ -180,9 +180,10 @@ export class MarqueeView extends React.Component var y = doc.GetNumber(KeyStore.Y, 0); var w = doc.GetNumber(KeyStore.Width, 0); var h = doc.GetNumber(KeyStore.Height, 0); - if (this.intersectRect({ left: x, top: y, width: w, height: h }, selRect)) - selection.push(doc) - }) + if (this.intersectRect({ left: x, top: y, width: w, height: h }, selRect)) { + selection.push(doc); + } + }); return selection; } @@ -190,7 +191,7 @@ export class MarqueeView extends React.Component get marqueeDiv() { let p = this.props.getContainerTransform().transformPoint(this._downX < this._lastX ? this._downX : this._lastX, this._downY < this._lastY ? this._downY : this._lastY); let v = this.props.getContainerTransform().transformDirection(this._lastX - this._downX, this._lastY - this._downY); - return
+ return
; } render() { diff --git a/src/client/views/collections/collectionFreeForm/PreviewCursor.tsx b/src/client/views/collections/collectionFreeForm/PreviewCursor.tsx index 599461f85..8eabb020a 100644 --- a/src/client/views/collections/collectionFreeForm/PreviewCursor.tsx +++ b/src/client/views/collections/collectionFreeForm/PreviewCursor.tsx @@ -90,7 +90,7 @@ export class PreviewCursor extends React.Component { {this.props.children}
- ) + ); } } @@ -109,8 +109,9 @@ export class PreviewCursorPrompt extends React.Component { render() { let p = this.props.getPoint(); - if (this.props.getVisible() && this._promptRef.current) + if (this.props.getVisible() && this._promptRef.current) { this._promptRef.current.focus(); + } return
I diff --git a/src/client/views/nodes/Annotation.tsx b/src/client/views/nodes/Annotation.tsx index e4f17940c..3e4ed6bf1 100644 --- a/src/client/views/nodes/Annotation.tsx +++ b/src/client/views/nodes/Annotation.tsx @@ -1,8 +1,8 @@ import "./ImageBox.scss"; -import React = require("react") -import { observer } from "mobx-react" +import React = require("react"); +import { observer } from "mobx-react"; import { observable, action } from 'mobx'; -import 'react-pdf/dist/Page/AnnotationLayer.css' +import 'react-pdf/dist/Page/AnnotationLayer.css'; interface IProps { Span: HTMLSpanElement; @@ -29,13 +29,13 @@ export class Annotation extends React.Component { */ onColorChange = (e: React.PointerEvent) => { if (e.currentTarget.innerHTML === "r") { - this.props.Span.style.backgroundColor = "rgba(255,0,0, 0.3)" + this.props.Span.style.backgroundColor = "rgba(255,0,0, 0.3)"; } else if (e.currentTarget.innerHTML === "b") { - this.props.Span.style.backgroundColor = "rgba(0,255, 255, 0.3)" + this.props.Span.style.backgroundColor = "rgba(0,255, 255, 0.3)"; } else if (e.currentTarget.innerHTML === "y") { - this.props.Span.style.backgroundColor = "rgba(255,255,0, 0.3)" + this.props.Span.style.backgroundColor = "rgba(255,255,0, 0.3)"; } else if (e.currentTarget.innerHTML === "g") { - this.props.Span.style.backgroundColor = "rgba(76, 175, 80, 0.3)" + this.props.Span.style.backgroundColor = "rgba(76, 175, 80, 0.3)"; } } @@ -54,11 +54,11 @@ export class Annotation extends React.Component { this.props.Highlights.splice(index, 1); } } - }) + }); //removing from CurrAnno and Annotation array this.props.Annotations.splice(index, 1); - this.props.CurrAnno.pop() + this.props.CurrAnno.pop(); //removing span from div if (this.props.Span.parentElement) { @@ -70,11 +70,11 @@ export class Annotation extends React.Component { if (item === e) { item.remove(); } - }) + }); e.remove(); } } - }) + }); } diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx index 1bd934c25..1493ff25b 100644 --- a/src/client/views/nodes/AudioBox.tsx +++ b/src/client/views/nodes/AudioBox.tsx @@ -1,18 +1,18 @@ -import React = require("react") +import React = require("react"); import { FieldViewProps, FieldView } from './FieldView'; import { FieldWaiting } from '../../../fields/Field'; -import { observer } from "mobx-react" +import { observer } from "mobx-react"; import { ContextMenu } from "../../views/ContextMenu"; import { observable, action } from 'mobx'; import { KeyStore } from '../../../fields/KeyStore'; import { AudioField } from "../../../fields/AudioField"; -import "./AudioBox.scss" +import "./AudioBox.scss"; import { NumberField } from "../../../fields/NumberField"; @observer export class AudioBox extends React.Component { - public static LayoutString() { return FieldView.LayoutString(AudioBox) } + public static LayoutString() { return FieldView.LayoutString(AudioBox); } constructor(props: FieldViewProps) { super(props); @@ -28,7 +28,7 @@ export class AudioBox extends React.Component { render() { - let field = this.props.Document.Get(this.props.fieldKey) + let field = this.props.Document.Get(this.props.fieldKey); let path = field === FieldWaiting ? "http://techslides.com/demos/samples/sample.mp3" : field instanceof AudioField ? field.Data.href : "http://techslides.com/demos/samples/sample.mp3"; @@ -39,6 +39,6 @@ export class AudioBox extends React.Component { Not supported.
- ) + ); } } \ No newline at end of file diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index dcf82ccd4..77f41105f 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -35,24 +35,24 @@ export class CollectionFreeFormDocumentView extends React.Component this.nativeWidth > 0 ? this.width / this.nativeWidth : 1 + contentScaling = () => this.nativeWidth > 0 ? this.width / this.nativeWidth : 1; getTransform = (): Transform => this.props.ScreenToLocalTransform() @@ -66,7 +66,7 @@ export class CollectionFreeFormDocumentView extends React.Component + />; } panelWidth = () => this.props.Document.GetBoolean(KeyStore.Minimized, false) ? 10 : this.props.PanelWidth(); panelHeight = () => this.props.Document.GetBoolean(KeyStore.Minimized, false) ? 10 : this.props.PanelHeight(); diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx index 34cc326aa..5836da396 100644 --- a/src/client/views/nodes/DocumentContentsView.tsx +++ b/src/client/views/nodes/DocumentContentsView.tsx @@ -26,7 +26,7 @@ import { FieldViewProps } from "./FieldView"; import { Without } from "../../../Utils"; const JsxParser = require('react-jsx-parser').default; //TODO Why does this need to be imported like this? -type BindingProps = Without +type BindingProps = Without; export interface JsxBindings { props: BindingProps; [keyName: string]: BindingProps | Field; @@ -92,7 +92,7 @@ export class DocumentContentsView extends React.Component { console.log(test) }} - /> + onError={(test: any) => { console.log(test); }} + />; } } \ No newline at end of file diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index ab9cd2d53..9670ca6b2 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -100,8 +100,9 @@ export class DocumentView extends React.Component { if (e.shiftKey && e.buttons === 2) { if (this.props.isTopMost) { this.startDragging(e.pageX, e.pageY, e.altKey || e.ctrlKey); - } else + } else { CollectionDockingView.Instance.StartOtherDrag([this.props.Document], e); + } e.stopPropagation(); } else { if (this.active && !e.isDefaultPrevented()) { @@ -112,7 +113,7 @@ export class DocumentView extends React.Component { document.addEventListener("pointerup", this.onPointerUp); } } - }; + } private dropDisposer?: DragManager.DragDropDisposer; @@ -179,7 +180,7 @@ export class DocumentView extends React.Component { } e.stopPropagation(); e.preventDefault(); - }; + } onPointerUp = (e: PointerEvent): void => { document.removeEventListener("pointermove", this.onPointerMove); document.removeEventListener("pointerup", this.onPointerUp); @@ -190,22 +191,22 @@ export class DocumentView extends React.Component { ) { SelectionManager.SelectDoc(this, e.ctrlKey); } - }; + } stopPropogation = (e: React.SyntheticEvent) => { e.stopPropagation(); - }; + } deleteClicked = (): void => { if (this.props.removeDocument) { this.props.removeDocument(this.props.Document); } - }; + } fieldsClicked = (e: React.MouseEvent): void => { if (this.props.addDocument) { this.props.addDocument(Documents.KVPDocument(this.props.Document, { width: 300, height: 300 }), false); } - }; + } fullScreenClicked = (e: React.MouseEvent): void => { CollectionDockingView.Instance.OpenFullScreen(this.props.Document); ContextMenu.Instance.clearItems(); @@ -214,7 +215,7 @@ export class DocumentView extends React.Component { event: this.closeFullScreenClicked }); ContextMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15); - }; + } closeFullScreenClicked = (e: React.MouseEvent): void => { CollectionDockingView.Instance.CloseFullScreen(); @@ -224,7 +225,7 @@ export class DocumentView extends React.Component { event: this.fullScreenClicked }); ContextMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15); - }; + } @action public minimize = (): void => { @@ -234,7 +235,7 @@ export class DocumentView extends React.Component { BooleanField ); SelectionManager.DeselectAll(); - }; + } @action drop = (e: Event, de: DragManager.DropEvent) => { @@ -276,7 +277,7 @@ export class DocumentView extends React.Component { ); e.stopPropagation(); } - }; + } onDrop = (e: React.DragEvent) => { if (e.isDefaultPrevented()) { @@ -290,7 +291,7 @@ export class DocumentView extends React.Component { e.stopPropagation(); e.preventDefault(); } - }; + } @action onContextMenu = (e: React.MouseEvent): void => { @@ -352,14 +353,14 @@ export class DocumentView extends React.Component { }); ContextMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15); SelectionManager.SelectDoc(this, e.ctrlKey); - }; + } isMinimized = () => { let field = this.props.Document.GetT(KeyStore.Minimized, BooleanField); if (field && field !== FieldWaiting) { return field.Data; } - }; + } @action expand = () => { @@ -368,13 +369,13 @@ export class DocumentView extends React.Component { false as boolean, BooleanField ); - }; + } - isSelected = () => SelectionManager.IsSelected(this) + isSelected = () => SelectionManager.IsSelected(this); select = (ctrlPressed: boolean) => { SelectionManager.SelectDoc(this, ctrlPressed); - }; + } render() { if (!this.props.Document) { diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx index d9422ae9b..07c5b332c 100644 --- a/src/client/views/nodes/FieldView.tsx +++ b/src/client/views/nodes/FieldView.tsx @@ -1,4 +1,4 @@ -import React = require("react") +import React = require("react"); import { observer } from "mobx-react"; import { computed } from "mobx"; import { Field, FieldWaiting, FieldValue } from "../../../fields/Field"; @@ -7,7 +7,7 @@ import { TextField } from "../../../fields/TextField"; import { NumberField } from "../../../fields/NumberField"; import { RichTextField } from "../../../fields/RichTextField"; import { ImageField } from "../../../fields/ImageField"; -import { VideoField } from "../../../fields/VideoField" +import { VideoField } from "../../../fields/VideoField"; import { Key } from "../../../fields/Key"; import { FormattedTextBox } from "./FormattedTextBox"; import { ImageBox } from "./ImageBox"; @@ -57,22 +57,22 @@ export class FieldView extends React.Component { render() { const field = this.field; if (!field) { - return

{''}

+ return

{''}

; } if (field instanceof TextField) { - return

{field.Data}

+ return

{field.Data}

; } else if (field instanceof RichTextField) { - return + return ; } else if (field instanceof ImageField) { - return + return ; } else if (field instanceof VideoField) { - return + return ; } else if (field instanceof AudioField) { - return + return ; } else if (field instanceof Document) { return ( @@ -92,25 +92,26 @@ export class FieldView extends React.Component { ContainingCollectionView={undefined} parentActive={this.props.active} onActiveChanged={this.props.onActiveChanged} /> - ) + ); } else if (field instanceof ListField) { return (
{(field as ListField).Data.map(f => f instanceof Document ? f.Title : f.GetValue().toString()).join(", ")} -
) +
); } // bcz: this belongs here, but it doesn't render well so taking it out for now // else if (field instanceof HtmlField) { // return // } else if (field instanceof NumberField) { - return

{field.Data}

+ return

{field.Data}

; } else if (field !== FieldWaiting) { - return

{JSON.stringify(field.GetValue())}

+ return

{JSON.stringify(field.GetValue())}

; } - else - return

{"Waiting for server..."}

+ else { + return

{"Waiting for server..."}

; + } } } \ No newline at end of file diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 7a94be12b..beca6cdc6 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -61,7 +61,7 @@ export class FormattedTextBox extends React.Component { ); // doc.SetData(fieldKey, JSON.stringify(state.toJSON()), RichTextField); } - }; + } get FieldDoc() { return this.props.fieldKey === KeyStore.Archives ? Main.Instance._textDoc! : this.props.Document; } get FieldKey() { return this.props.fieldKey === KeyStore.Archives ? KeyStore.Data : this.props.fieldKey; } @@ -81,12 +81,13 @@ export class FormattedTextBox extends React.Component { if (this.props.fieldKey === KeyStore.Archives) { this._inputReactionDisposer = reaction(() => Main.Instance._textDoc && Main.Instance._textDoc.Id, () => { - if (this._editorView) - this._editorView!.destroy(); + if (this._editorView) { + this._editorView.destroy(); + } this.setupEditor(config); } - ) + ); } this._reactionDisposer = reaction( @@ -153,7 +154,7 @@ export class FormattedTextBox extends React.Component { if (e.buttons === 1 && this.props.isSelected() && !e.altKey) { e.stopPropagation(); } - }; + } onPointerUp = (e: React.PointerEvent): void => { if (e.buttons === 1 && this.props.isSelected() && !e.altKey) { e.stopPropagation(); @@ -162,7 +163,7 @@ export class FormattedTextBox extends React.Component { e.preventDefault(); Main.Instance.SetTextDoc(this.props.Document, this._ref.current!); } - }; + } onFocused = (e: React.FocusEvent): void => { if (this.props.fieldKey !== KeyStore.Archives) { @@ -191,11 +192,11 @@ export class FormattedTextBox extends React.Component { // ] // }) // e.stopPropagation() - }; + } onPointerWheel = (e: React.WheelEvent): void => { e.stopPropagation(); - }; + } tooltipMenuPlugin() { return new Plugin({ diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index c5f29f7b0..6b0a3a799 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -9,13 +9,13 @@ import { KeyStore } from '../../../fields/KeyStore'; import { ContextMenu } from "../../views/ContextMenu"; import { FieldView, FieldViewProps } from './FieldView'; import "./ImageBox.scss"; -import React = require("react") +import React = require("react"); import { Utils } from '../../../Utils'; @observer export class ImageBox extends React.Component { - public static LayoutString() { return FieldView.LayoutString(ImageBox) } + public static LayoutString() { return FieldView.LayoutString(ImageBox); } private _ref: React.RefObject; private _imgRef: React.RefObject; private _downX: number = 0; @@ -39,7 +39,7 @@ export class ImageBox extends React.Component { onLoad = (target: any) => { var h = this._imgRef.current!.naturalHeight; var w = this._imgRef.current!.naturalWidth; - this.props.Document.SetNumber(KeyStore.NativeHeight, this.props.Document.GetNumber(KeyStore.NativeWidth, 0) * h / w) + this.props.Document.SetNumber(KeyStore.NativeHeight, this.props.Document.GetNumber(KeyStore.NativeWidth, 0) * h / w); } componentDidMount() { @@ -86,7 +86,7 @@ export class ImageBox extends React.Component { onMoveNextRequest={action(() => this._photoIndex = (this._photoIndex + 1) % images.length )} - />) + />); } } @@ -96,7 +96,7 @@ export class ImageBox extends React.Component { let url = field.Data.href; ContextMenu.Instance.addItem({ description: "Copy path", event: () => { - Utils.CopyText(url) + Utils.CopyText(url); } }); } @@ -111,6 +111,6 @@ export class ImageBox extends React.Component {
Image not found {this.lightbox(path)} -
) +
); } } \ No newline at end of file diff --git a/src/client/views/nodes/KeyValueBox.tsx b/src/client/views/nodes/KeyValueBox.tsx index 8a7f32e6d..bcac113f0 100644 --- a/src/client/views/nodes/KeyValueBox.tsx +++ b/src/client/views/nodes/KeyValueBox.tsx @@ -7,7 +7,7 @@ import { KeyStore } from '../../../fields/KeyStore'; import { FieldView, FieldViewProps } from './FieldView'; import "./KeyValueBox.scss"; import { KeyValuePair } from "./KeyValuePair"; -import React = require("react") +import React = require("react"); import { CompileScript, ToField } from "../../util/Scripting"; import { Key } from '../../../fields/Key'; import { observable, action } from "mobx"; @@ -15,7 +15,7 @@ import { observable, action } from "mobx"; @observer export class KeyValueBox extends React.Component { - public static LayoutString(fieldStr: string = "DataKey") { return FieldView.LayoutString(KeyValueBox, fieldStr) } + public static LayoutString(fieldStr: string = "DataKey") { return FieldView.LayoutString(KeyValueBox, fieldStr); } @observable private _keyInput: string = ""; @observable private _valueInput: string = ""; @@ -36,7 +36,7 @@ export class KeyValueBox extends React.Component { if (this._keyInput && this._valueInput) { let doc = this.props.Document.GetT(KeyStore.Data, Document); if (!doc || doc === FieldWaiting) { - return + return; } let realDoc = doc; @@ -55,8 +55,8 @@ export class KeyValueBox extends React.Component { realDoc.Set(new Key(this._keyInput), dataField); } } - this._keyInput = "" - this._valueInput = "" + this._keyInput = ""; + this._valueInput = ""; } } } @@ -73,7 +73,7 @@ export class KeyValueBox extends React.Component { createTable = () => { let doc = this.props.Document.GetT(KeyStore.Data, Document); if (!doc || doc === FieldWaiting) { - return Loading... + return Loading...; } let realDoc = doc; @@ -84,13 +84,13 @@ export class KeyValueBox extends React.Component { if (!(key in ids)) { ids[key] = key; } - }) + }); } let rows: JSX.Element[] = []; let i = 0; for (let key in ids) { - rows.push() + rows.push(); } return rows; } @@ -125,6 +125,6 @@ export class KeyValueBox extends React.Component { {this.newKeyValue()} - ) + ); } } \ No newline at end of file diff --git a/src/client/views/nodes/KeyValuePair.tsx b/src/client/views/nodes/KeyValuePair.tsx index c6a0a7296..a1050dc6e 100644 --- a/src/client/views/nodes/KeyValuePair.tsx +++ b/src/client/views/nodes/KeyValuePair.tsx @@ -1,14 +1,14 @@ import 'react-image-lightbox/style.css'; // This only needs to be imported once in your app import "./KeyValueBox.scss"; import "./KeyValuePair.scss"; -import React = require("react") +import React = require("react"); import { FieldViewProps, FieldView } from './FieldView'; import { Opt, Field } from '../../../fields/Field'; -import { observer } from "mobx-react" +import { observer } from "mobx-react"; import { observable, action } from 'mobx'; import { Document } from '../../../fields/Document'; import { Key } from '../../../fields/Key'; -import { Server } from "../../Server" +import { Server } from "../../Server"; import { EditableView } from "../EditableView"; import { CompileScript, ToField } from "../../util/Scripting"; import { Transform } from '../../util/Transform'; @@ -25,7 +25,7 @@ export interface KeyValuePairProps { export class KeyValuePair extends React.Component { @observable - private key: Opt + private key: Opt; constructor(props: KeyValuePairProps) { super(props); @@ -41,7 +41,7 @@ export class KeyValuePair extends React.Component { render() { if (!this.key) { - return error + return error; } let props: FieldViewProps = { @@ -55,7 +55,7 @@ export class KeyValuePair extends React.Component { onActiveChanged: emptyFunction, ScreenToLocalTransform: Transform.Identity, focus: emptyFunction, - } + }; let contents = ( ); @@ -101,6 +101,6 @@ export class KeyValuePair extends React.Component { return false; }}> - ) + ); } } \ No newline at end of file diff --git a/src/client/views/nodes/LinkBox.tsx b/src/client/views/nodes/LinkBox.tsx index 4791d6029..b016a3d48 100644 --- a/src/client/views/nodes/LinkBox.tsx +++ b/src/client/views/nodes/LinkBox.tsx @@ -2,8 +2,8 @@ import { observable, computed, action } from "mobx"; import React = require("react"); import { SelectionManager } from "../../util/SelectionManager"; import { observer } from "mobx-react"; -import './LinkBox.scss' -import { KeyStore } from '../../../fields/KeyStore' +import './LinkBox.scss'; +import { KeyStore } from '../../../fields/KeyStore'; import { props } from "bluebird"; import { DocumentView } from "./DocumentView"; import { Document } from "../../../fields/Document"; @@ -30,7 +30,7 @@ interface Props { linkName: String; pairedDoc: Document; type: String; - showEditor: () => void + showEditor: () => void; } @observer @@ -49,15 +49,16 @@ export class LinkBox extends React.Component { } else if (contextDoc instanceof Document) { this.props.pairedDoc.GetTAsync(KeyStore.Page, NumberField).then((pfield: any) => { contextDoc.GetTAsync(KeyStore.CurPage, NumberField).then((cfield: any) => { - if (pfield !== cfield) + if (pfield !== cfield) { contextDoc.SetNumber(KeyStore.CurPage, pfield.Data); + } let contextView = DocumentManager.Instance.getDocumentView(contextDoc); if (contextView) { contextView.props.focus(contextDoc); } else { CollectionDockingView.Instance.AddRightSplit(contextDoc); } - }) + }); }); } }); @@ -80,7 +81,7 @@ export class LinkBox extends React.Component { if (field) { field.Data.splice(field.Data.indexOf(this.props.linkDoc)); } - }) + }); } }); this.props.linkDoc.GetTAsync(KeyStore.LinkedToDocs, Document, field => { @@ -89,7 +90,7 @@ export class LinkBox extends React.Component { if (field) { field.Data.splice(field.Data.indexOf(this.props.linkDoc)); } - }) + }); } }); } @@ -117,6 +118,6 @@ export class LinkBox extends React.Component { - ) + ); } } \ No newline at end of file diff --git a/src/client/views/nodes/LinkEditor.tsx b/src/client/views/nodes/LinkEditor.tsx index 3f7b4bf2d..bde50fed8 100644 --- a/src/client/views/nodes/LinkEditor.tsx +++ b/src/client/views/nodes/LinkEditor.tsx @@ -2,8 +2,8 @@ import { observable, computed, action } from "mobx"; import React = require("react"); import { SelectionManager } from "../../util/SelectionManager"; import { observer } from "mobx-react"; -import './LinkEditor.scss' -import { KeyStore } from '../../../fields/KeyStore' +import './LinkEditor.scss'; +import { KeyStore } from '../../../fields/KeyStore'; import { props } from "bluebird"; import { DocumentView } from "./DocumentView"; import { Document } from "../../../fields/Document"; @@ -43,7 +43,7 @@ export class LinkEditor extends React.Component {
SAVE
- ) + ); } @action diff --git a/src/client/views/nodes/LinkMenu.tsx b/src/client/views/nodes/LinkMenu.tsx index 6c2d24630..ac09da305 100644 --- a/src/client/views/nodes/LinkMenu.tsx +++ b/src/client/views/nodes/LinkMenu.tsx @@ -13,7 +13,7 @@ import React = require("react"); interface Props { docView: DocumentView; - changeFlyout: () => void + changeFlyout: () => void; } @observer @@ -25,9 +25,9 @@ export class LinkMenu extends React.Component { return links.map(link => { let doc = link.GetT(key, Document); if (doc && doc !== FieldWaiting) { - return this._editingLink = link)} type={type} /> + return this._editingLink = link)} type={type} />; } - }) + }); } render() { @@ -43,11 +43,11 @@ export class LinkMenu extends React.Component { {this.renderLinkItems(linkFrom, KeyStore.LinkedFromDocs, "Source: ")} - ) + ); } else { return ( this._editingLink = undefined)}> - ) + ); } } diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index 774d9be3e..81ceb37f6 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -17,7 +17,7 @@ import { FieldView, FieldViewProps } from './FieldView'; import "./ImageBox.scss"; import "./PDFBox.scss"; import { Sticky } from './Sticky'; //you should look at sticky and annotation, because they are used here -import React = require("react") +import React = require("react"); import { SelectionManager } from "../../util/SelectionManager"; /** ALSO LOOK AT: Annotation.tsx, Sticky.tsx @@ -55,7 +55,7 @@ import { SelectionManager } from "../../util/SelectionManager"; export class PDFBox extends React.Component { public static LayoutString() { return FieldView.LayoutString(PDFBox); } - private _mainDiv = React.createRef() + private _mainDiv = React.createRef(); private _pdf = React.createRef(); @observable private _renderAsSvg = true; @@ -72,7 +72,7 @@ export class PDFBox extends React.Component { private _currTool: any; //keeps track of current tool button reference private _drawToolOn: boolean = false; //boolean that keeps track of the drawing tool - private _drawTool = React.createRef()//drawing tool button reference + private _drawTool = React.createRef();//drawing tool button reference private _colorTool = React.createRef(); //color button reference private _currColor: string = "black"; //current color that user selected (for ink/pen) @@ -85,7 +85,7 @@ export class PDFBox extends React.Component { @observable private _perPageInfo: Object[] = []; //stores pageInfo @observable private _pageInfo: any = { area: [], divs: [], anno: [] }; //divs is array of objects linked to anno - @observable private _currAnno: any = [] + @observable private _currAnno: any = []; @observable private _interactive: boolean = false; @observable private _loaded: boolean = false; @@ -168,24 +168,24 @@ export class PDFBox extends React.Component { let obj: Object = { parentDivs: [], spans: [] }; //@ts-ignore if (range.commonAncestorContainer.className === 'react-pdf__Page__textContent') { //multiline highlighting case - obj = this.highlightNodes(range.commonAncestorContainer.childNodes) + obj = this.highlightNodes(range.commonAncestorContainer.childNodes); } else { //single line highlighting case - let parentDiv = range.commonAncestorContainer.parentElement + let parentDiv = range.commonAncestorContainer.parentElement; if (parentDiv) { if (parentDiv.className === 'react-pdf__Page__textContent') { //when highlight is overwritten - obj = this.highlightNodes(parentDiv.childNodes) + obj = this.highlightNodes(parentDiv.childNodes); } else { parentDiv.childNodes.forEach((child) => { if (child.nodeName === 'SPAN') { //@ts-ignore - obj.parentDivs.push(parentDiv) + obj.parentDivs.push(parentDiv); //@ts-ignore - child.id = "highlighted" + child.id = "highlighted"; //@ts-ignore - obj.spans.push(child) + obj.spans.push(child); child.addEventListener("mouseover", this.onEnter); //adds mouseover annotation handler } - }) + }); } } } @@ -196,21 +196,21 @@ export class PDFBox extends React.Component { } highlightNodes = (nodes: NodeListOf) => { - let temp = { parentDivs: [], spans: [] } + let temp = { parentDivs: [], spans: [] }; nodes.forEach((div) => { div.childNodes.forEach((child) => { if (child.nodeName === 'SPAN') { //@ts-ignore - temp.parentDivs.push(div) + temp.parentDivs.push(div); //@ts-ignore - child.id = "highlighted" + child.id = "highlighted"; //@ts-ignore - temp.spans.push(child) + temp.spans.push(child); child.addEventListener("mouseover", this.onEnter); //adds mouseover annotation handler } - }) + }); - }) + }); return temp; } @@ -228,8 +228,8 @@ export class PDFBox extends React.Component { index = this._pageInfo.divs.indexOf(obj); } } - }) - }) + }); + }); if (this._pageInfo.anno.length >= index + 1) { if (this._currAnno.length === 0) { @@ -239,13 +239,13 @@ export class PDFBox extends React.Component { if (this._currAnno.length === 0) { //if there are no current annotation let div = span.offsetParent; //@ts-ignore - let divX = div.style.left + let divX = div.style.left; //@ts-ignore - let divY = div.style.top + let divY = div.style.top; //slicing "px" from the end divX = divX.slice(0, divX.length - 2); //gets X of the DIV element (parent of Span) divY = divY.slice(0, divY.length - 2); //gets Y of the DIV element (parent of Span) - let annotation = + let annotation = ; this._pageInfo.anno.push(annotation); this._currAnno.push(annotation); } @@ -263,7 +263,7 @@ export class PDFBox extends React.Component { this.makeEditableAndHighlight(color); } } catch (ex) { - this.makeEditableAndHighlight(color) + this.makeEditableAndHighlight(color); } } } @@ -305,7 +305,7 @@ export class PDFBox extends React.Component { } if (this._mainDiv.current) { - let sticky = + let sticky = ; this._pageInfo.area.push(sticky); } this._toolOn = false; @@ -404,19 +404,19 @@ export class PDFBox extends React.Component { if (e instanceof HTMLCanvasElement) { this._pdfCanvas = e; - this._pdfContext = e.getContext("2d") + this._pdfContext = e.getContext("2d"); } - }) + }); } - }) + }); } // bcz: the number of pages should really be set when the document is imported. this.props.Document.SetNumber(KeyStore.NumPages, page._transport.numPages); if (this._perPageInfo.length === 0) { //Makes sure it only runs once - this._perPageInfo = [...Array(page._transport.numPages)] + this._perPageInfo = [...Array(page._transport.numPages)]; } this._loaded = true; } diff --git a/src/client/views/nodes/Sticky.tsx b/src/client/views/nodes/Sticky.tsx index 4a4d69e90..11719831b 100644 --- a/src/client/views/nodes/Sticky.tsx +++ b/src/client/views/nodes/Sticky.tsx @@ -39,7 +39,7 @@ export class Sticky extends React.Component { document.addEventListener("pointermove", this.drawMove); document.addEventListener("pointerup", this.drawUp); } - }; + } //when user drags drawMove = (e: PointerEvent): void => { @@ -49,7 +49,7 @@ export class Sticky extends React.Component { //connects the point this.ctx.lineTo(x, y); this.ctx.stroke(); - }; + } /** * when user lifts the mouse, the drawing ends @@ -58,7 +58,7 @@ export class Sticky extends React.Component { this.ctx.closePath(); console.log(this.ctx); document.removeEventListener("pointermove", this.drawMove); - }; + } render() { return ( diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx index a08b320e8..314af64c9 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -1,4 +1,4 @@ -import React = require("react") +import React = require("react"); import { observer } from "mobx-react"; import { FieldWaiting, Opt } from '../../../fields/Field'; import { VideoField } from '../../../fields/VideoField'; @@ -13,8 +13,8 @@ import { number } from "prop-types"; export class VideoBox extends React.Component { private _reactionDisposer: Opt; - private _videoRef = React.createRef() - public static LayoutString() { return FieldView.LayoutString(VideoBox) } + private _videoRef = React.createRef(); + public static LayoutString() { return FieldView.LayoutString(VideoBox); } constructor(props: FieldViewProps) { super(props); @@ -58,7 +58,7 @@ export class VideoBox extends React.Component { render() { let field = this.props.Document.GetT(this.props.fieldKey, VideoField); if (!field || field === FieldWaiting) { - return
Loading
+ return
Loading
; } let path = field.Data.href; trace(); @@ -73,6 +73,6 @@ export class VideoBox extends React.Component { } - ) + ); } } \ No newline at end of file diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index c1d389001..90ce72c41 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -1,9 +1,9 @@ import "./WebBox.scss"; -import React = require("react") +import React = require("react"); import { WebField } from '../../../fields/WebField'; import { FieldViewProps, FieldView } from './FieldView'; import { FieldWaiting } from '../../../fields/Field'; -import { observer } from "mobx-react" +import { observer } from "mobx-react"; import { computed } from 'mobx'; import { KeyStore } from '../../../fields/KeyStore'; @@ -33,6 +33,6 @@ export class WebBox extends React.Component { return (
{content} -
) + ); } } \ No newline at end of file diff --git a/src/debug/Test.tsx b/src/debug/Test.tsx index c8de33f41..11f2b0c4e 100644 --- a/src/debug/Test.tsx +++ b/src/debug/Test.tsx @@ -1,10 +1,10 @@ import * as React from 'react'; import * as ReactDOM from 'react-dom'; -import JsxParser from 'react-jsx-parser' +import JsxParser from 'react-jsx-parser'; class Hello extends React.Component<{ firstName: string, lastName: string }> { render() { - return
Hello {this.props.firstName} {this.props.lastName}
+ return
Hello {this.props.firstName} {this.props.lastName}
; } } @@ -16,8 +16,8 @@ class Test extends React.Component { firstName: "First", lastName: "Last" } - } - return + }; + return ; } } diff --git a/src/debug/Viewer.tsx b/src/debug/Viewer.tsx index f13cccd24..857da1ebb 100644 --- a/src/debug/Viewer.tsx +++ b/src/debug/Viewer.tsx @@ -40,22 +40,22 @@ class ListViewer extends React.Component<{ field: ListField }>{
{this.props.field.Data.map(field => )}
- ) + ); } else { - content = <>[...] ({this.props.field.Id}) + content = <>[...] ({this.props.field.Id}); } return (
{content}
- ) + ); } } @observer class DocumentViewer extends React.Component<{ field: Document }> { - private keyMap: ObservableMap = new ObservableMap + private keyMap: ObservableMap = new ObservableMap; private disposer?: Lambda; @@ -67,12 +67,12 @@ class DocumentViewer extends React.Component<{ field: Document }> { if (field && field instanceof Key) { this.keyMap.set(id, field); } - }) + }); } }); - } - this.disposer = this.props.field._proxies.observe(f) - f() + }; + this.disposer = this.props.field._proxies.observe(f); + f(); } componentWillUnmount() { @@ -89,8 +89,8 @@ class DocumentViewer extends React.Component<{ field: Document }> { ({key ? key.Name : kv[0]}): - ) - }) + ); + }); return (
Document ({this.props.field.Id}) @@ -98,7 +98,7 @@ class DocumentViewer extends React.Component<{ field: Document }> { {fields}
- ) + ); } } @@ -111,15 +111,15 @@ class DebugViewer extends React.Component<{ fieldId: string }> { private error?: string; constructor(props: { fieldId: string }) { - super(props) - this.update() + super(props); + this.update(); } update() { Server.GetField(this.props.fieldId, action((field: Opt) => { this.field = field; if (!field) { - this.error = `Field with id ${this.props.fieldId} not found` + this.error = `Field with id ${this.props.fieldId} not found`; } })); @@ -130,20 +130,20 @@ class DebugViewer extends React.Component<{ fieldId: string }> { if (this.field) { // content = this.field.ToJson(); if (this.field instanceof ListField) { - content = () + content = (); } else if (this.field instanceof Document) { - content = () + content = (); } else if (this.field instanceof BasicField) { - content = () + content = (); } else if (this.field instanceof Key) { - content = () + content = (); } else { - content = (Unrecognized field type) + content = (Unrecognized field type); } } else if (this.error) { - content = Field {this.props.fieldId} not found + content = Field {this.props.fieldId} not found ; } else { - content = Field loading: {this.props.fieldId} + content = Field loading: {this.props.fieldId}; } return content; } @@ -165,8 +165,8 @@ class Viewer extends React.Component { @action onKeyPress = (e: React.KeyboardEvent) => { if (e.key === "Enter") { - this.ids.push(this.idToAdd) - this.idToAdd = "" + this.ids.push(this.idToAdd); + this.idToAdd = ""; } } @@ -180,7 +180,7 @@ class Viewer extends React.Component { {this.ids.map(id => )} - ) + ); } } diff --git a/src/fields/AudioField.ts b/src/fields/AudioField.ts index 252a5b74e..996d2556d 100644 --- a/src/fields/AudioField.ts +++ b/src/fields/AudioField.ts @@ -25,7 +25,7 @@ export class AudioField extends BasicField { type: Types.Audio, data: this.Data.href, _id: this.Id - } + }; } } \ No newline at end of file diff --git a/src/fields/BasicField.ts b/src/fields/BasicField.ts index 3083a1937..17b1fc4e8 100644 --- a/src/fields/BasicField.ts +++ b/src/fields/BasicField.ts @@ -1,4 +1,4 @@ -import { Field, FieldId } from "./Field" +import { Field, FieldId } from "./Field"; import { observable, computed, action } from "mobx"; import { Server } from "../client/Server"; import { UndoManager } from "../client/util/UndoManager"; @@ -9,7 +9,7 @@ export abstract class BasicField extends Field { this.data = data; if (save) { - Server.UpdateField(this) + Server.UpdateField(this); } } @@ -36,7 +36,7 @@ export abstract class BasicField extends Field { UndoManager.AddEvent({ undo: () => this.Data = oldValue, redo: () => this.Data = value - }) + }); Server.UpdateField(this); } diff --git a/src/fields/Document.ts b/src/fields/Document.ts index 4fa478f32..4584660fb 100644 --- a/src/fields/Document.ts +++ b/src/fields/Document.ts @@ -37,21 +37,24 @@ export class Document extends Field { } } - public Width = () => this.GetNumber(KeyStore.Width, 0) + public Width = () => this.GetNumber(KeyStore.Width, 0); public Height = () => this.GetNumber(KeyStore.Height, this.GetNumber(KeyStore.NativeWidth, 0) ? (this.GetNumber(KeyStore.NativeHeight, 0) / this.GetNumber(KeyStore.NativeWidth, 0)) * this.GetNumber(KeyStore.Width, 0) : 0); - public Scale = () => this.GetNumber(KeyStore.Scale, 1) + public Scale = () => this.GetNumber(KeyStore.Scale, 1); @computed public get Title(): string { let title = this.Get(KeyStore.Title, true); - if (title) - if (title !== FieldWaiting && title instanceof TextField) + if (title) { + if (title !== FieldWaiting && title instanceof TextField) { return title.Data; + } else return "-waiting-"; + } let parTitle = this.GetT(KeyStore.Title, TextField); - if (parTitle) + if (parTitle) { if (parTitle !== FieldWaiting) return parTitle.Data + ".alias"; else return "-waiting-.alias"; + } return "-untitled-"; } @@ -398,11 +401,13 @@ export class Document extends Field { } } else - if (field instanceof Document) // ... TODO bcz: should we copy documents or reference them - copy.Set(key!, field) - else if (field) - copy.Set(key!, field.Copy()) - }) + if (field instanceof Document) { // ... TODO bcz: should we copy documents or reference them + copy.Set(key!, field); + } + else if (field) { + copy.Set(key!, field.Copy()); + } + }); } }); return copy; diff --git a/src/fields/DocumentReference.ts b/src/fields/DocumentReference.ts index 9d3c209b4..6c0c1ef82 100644 --- a/src/fields/DocumentReference.ts +++ b/src/fields/DocumentReference.ts @@ -52,6 +52,6 @@ export class DocumentReference extends Field { type: Types.DocumentReference, data: this.document.Id, _id: this.Id - } + }; } } \ No newline at end of file diff --git a/src/fields/Field.ts b/src/fields/Field.ts index 0d0e56f77..d9db23b9e 100644 --- a/src/fields/Field.ts +++ b/src/fields/Field.ts @@ -65,5 +65,5 @@ export abstract class Field { abstract Copy(): Field; - abstract ToJson(): { _id: string, type: Types, data: any } + abstract ToJson(): { _id: string, type: Types, data: any }; } \ No newline at end of file diff --git a/src/fields/HtmlField.ts b/src/fields/HtmlField.ts index 7cbdf7e58..65665cf7a 100644 --- a/src/fields/HtmlField.ts +++ b/src/fields/HtmlField.ts @@ -20,6 +20,6 @@ export class HtmlField extends BasicField { type: Types.Html, data: this.Data, _id: this.Id, - } + }; } } \ No newline at end of file diff --git a/src/fields/ImageField.ts b/src/fields/ImageField.ts index ef616b2ad..dd843026f 100644 --- a/src/fields/ImageField.ts +++ b/src/fields/ImageField.ts @@ -24,6 +24,6 @@ export class ImageField extends BasicField { type: Types.Image, data: this.Data.href, _id: this.Id - } + }; } } \ No newline at end of file diff --git a/src/fields/InkField.ts b/src/fields/InkField.ts index 2a4ed18e7..ab706ee30 100644 --- a/src/fields/InkField.ts +++ b/src/fields/InkField.ts @@ -36,7 +36,7 @@ export class InkField extends BasicField { type: Types.Ink, data: this.Data, _id: this.Id, - } + }; } UpdateFromServer(data: any) { diff --git a/src/fields/Key.ts b/src/fields/Key.ts index 00d78d516..c7f806b88 100644 --- a/src/fields/Key.ts +++ b/src/fields/Key.ts @@ -1,4 +1,4 @@ -import { Field, FieldId } from "./Field" +import { Field, FieldId } from "./Field"; import { Utils } from "../Utils"; import { observable } from "mobx"; import { Types } from "../server/Message"; @@ -16,7 +16,7 @@ export class Key extends Field { this.name = name; if (save) { - Server.UpdateField(this) + Server.UpdateField(this); } } @@ -45,6 +45,6 @@ export class Key extends Field { type: Types.Key, data: this.name, _id: this.Id - } + }; } } \ No newline at end of file diff --git a/src/fields/KeyStore.ts b/src/fields/KeyStore.ts index e24e9c8ec..425408273 100644 --- a/src/fields/KeyStore.ts +++ b/src/fields/KeyStore.ts @@ -56,8 +56,9 @@ export namespace KeyStore { ]; export function KeyLookup(keyid: string) { for (const key of KeyList) { - if (key.Id === keyid) + if (key.Id === keyid) { return key; + } } return undefined; } diff --git a/src/fields/ListField.ts b/src/fields/ListField.ts index 815a3df73..b6eab5f86 100644 --- a/src/fields/ListField.ts +++ b/src/fields/ListField.ts @@ -7,7 +7,7 @@ import { Field, FieldId } from "./Field"; import { FieldMap } from "../client/SocketStub"; export class ListField extends BasicField { - private _proxies: string[] = [] + private _proxies: string[] = []; constructor(data: T[] = [], id?: FieldId, save: boolean = true) { super(data, save, id); this.updateProxies(); @@ -22,23 +22,24 @@ export class ListField extends BasicField { private observeDisposer: Lambda | undefined; private observeList(): void { if (this.observeDisposer) { - this.observeDisposer() + this.observeDisposer(); } this.observeDisposer = observe(this.Data as IObservableArray, (change: IArrayChange | IArraySplice) => { - this.updateProxies() + this.updateProxies(); if (change.type === "splice") { UndoManager.AddEvent({ undo: () => this.Data.splice(change.index, change.addedCount, ...change.removed), redo: () => this.Data.splice(change.index, change.removedCount, ...change.added) - }) + }); } else { UndoManager.AddEvent({ undo: () => this.Data[change.index] = change.oldValue, redo: () => this.Data[change.index] = change.newValue - }) + }); } - if (!this._processingServerUpdate) + if (!this._processingServerUpdate) { Server.UpdateField(this); + } }); } @@ -78,19 +79,23 @@ export class ListField extends BasicField { var proxies = this._proxies.map(p => p); var added = this.data.length < this._proxies.length; var deleted = this.data.length > this._proxies.length; - for (let i = 0; i < dataids.length && added; i++) + for (let i = 0; i < dataids.length && added; i++) { added = proxies.indexOf(dataids[i]) !== -1; - for (let i = 0; i < this._proxies.length && deleted; i++) + } + for (let i = 0; i < this._proxies.length && deleted; i++) { deleted = dataids.indexOf(proxies[i]) !== -1; + } this._processingServerUpdate = true; for (let i = 0; i < proxies.length && added; i++) { - if (dataids.indexOf(proxies[i]) === -1) + if (dataids.indexOf(proxies[i]) === -1) { this.Data.splice(i, 0, fields[proxies[i]] as T); + } } for (let i = dataids.length - 1; i >= 0 && deleted; i--) { - if (proxies.indexOf(dataids[i]) === -1) + if (proxies.indexOf(dataids[i]) === -1) { this.Data.splice(i, 1); + } } if (!added && !deleted) {// otherwise, just rebuild the whole list this.setData(proxies.map(id => fields[id] as T)); @@ -98,7 +103,7 @@ export class ListField extends BasicField { this._processingServerUpdate = false; } callback(this); - })) + })); } ToScriptString(): string { @@ -114,12 +119,12 @@ export class ListField extends BasicField { type: Types.List, data: this._proxies || [], _id: this.Id - } + }; } static FromJson(id: string, ids: string[]): ListField { let list = new ListField([], id, false); list._proxies = ids; - return list + return list; } } \ No newline at end of file diff --git a/src/fields/NumberField.ts b/src/fields/NumberField.ts index e0c8648de..45b920e31 100644 --- a/src/fields/NumberField.ts +++ b/src/fields/NumberField.ts @@ -1,4 +1,4 @@ -import { BasicField } from "./BasicField" +import { BasicField } from "./BasicField"; import { Types } from "../server/Message"; import { FieldId } from "./Field"; @@ -20,6 +20,6 @@ export class NumberField extends BasicField { _id: this.Id, type: Types.Number, data: this.Data - } + }; } } \ No newline at end of file diff --git a/src/fields/PDFField.ts b/src/fields/PDFField.ts index 436c1cf2b..65e179894 100644 --- a/src/fields/PDFField.ts +++ b/src/fields/PDFField.ts @@ -1,6 +1,6 @@ import { BasicField } from "./BasicField"; import { Field, FieldId } from "./Field"; -import { observable } from "mobx" +import { observable } from "mobx"; import { Types } from "../server/Message"; @@ -27,7 +27,7 @@ export class PDFField extends BasicField { type: Types.PDF, data: this.Data.href, _id: this.Id - } + }; } @observable diff --git a/src/fields/RichTextField.ts b/src/fields/RichTextField.ts index 5efb43314..6f7b3074a 100644 --- a/src/fields/RichTextField.ts +++ b/src/fields/RichTextField.ts @@ -20,7 +20,7 @@ export class RichTextField extends BasicField { type: Types.RichText, data: this.Data, _id: this.Id - } + }; } } \ No newline at end of file diff --git a/src/fields/TextField.ts b/src/fields/TextField.ts index 71d8ea310..69d26f42f 100644 --- a/src/fields/TextField.ts +++ b/src/fields/TextField.ts @@ -1,4 +1,4 @@ -import { BasicField } from "./BasicField" +import { BasicField } from "./BasicField"; import { FieldId } from "./Field"; import { Types } from "../server/Message"; @@ -20,6 +20,6 @@ export class TextField extends BasicField { type: Types.Text, data: this.Data, _id: this.Id - } + }; } } \ No newline at end of file diff --git a/src/fields/TupleField.ts b/src/fields/TupleField.ts index e2162c751..ad0f6f350 100644 --- a/src/fields/TupleField.ts +++ b/src/fields/TupleField.ts @@ -21,7 +21,7 @@ export class TupleField extends BasicField<[T, U]> { UndoManager.AddEvent({ undo: () => this.Data[change.index] = change.oldValue, redo: () => this.Data[change.index] = change.newValue - }) + }); Server.UpdateField(this); } else { throw new Error("Why are you messing with the length of a tuple, huh?"); @@ -31,7 +31,7 @@ export class TupleField extends BasicField<[T, U]> { protected setData(value: [T, U]) { if (this.observeDisposer) { - this.observeDisposer() + this.observeDisposer(); } this.data = observable(value) as (T | U)[] as [T, U]; this.observeTuple(); @@ -54,6 +54,6 @@ export class TupleField extends BasicField<[T, U]> { type: Types.Tuple, data: this.Data, _id: this.Id - } + }; } } \ No newline at end of file diff --git a/src/fields/VideoField.ts b/src/fields/VideoField.ts index 992cc1641..d7cd7e968 100644 --- a/src/fields/VideoField.ts +++ b/src/fields/VideoField.ts @@ -24,7 +24,7 @@ export class VideoField extends BasicField { type: Types.Video, data: this.Data.href, _id: this.Id - } + }; } } \ No newline at end of file diff --git a/src/fields/WebField.ts b/src/fields/WebField.ts index 0cbcc6d33..6023e9e6b 100644 --- a/src/fields/WebField.ts +++ b/src/fields/WebField.ts @@ -24,7 +24,7 @@ export class WebField extends BasicField { type: Types.Web, data: this.Data.href, _id: this.Id - } + }; } } \ No newline at end of file diff --git a/src/mobile/ImageUpload.tsx b/src/mobile/ImageUpload.tsx index c3684a0eb..ec89a1194 100644 --- a/src/mobile/ImageUpload.tsx +++ b/src/mobile/ImageUpload.tsx @@ -22,7 +22,7 @@ import { Opt } from '../fields/Field'; // } const onFileLoad = async (file: any) => { - let imgPrev = document.getElementById("img_preview") + let imgPrev = document.getElementById("img_preview"); if (imgPrev) { let files: File[] = file.target.files; if (files.length !== 0) { @@ -30,15 +30,15 @@ const onFileLoad = async (file: any) => { let formData = new FormData(); formData.append("file", files[0]); - const upload = window.location.origin + "/upload" + const upload = window.location.origin + "/upload"; const res = await fetch(upload, { method: 'POST', body: formData }); const json = await res.json(); json.map(async (file: any) => { - let path = window.location.origin + file - var doc: Document = Documents.ImageDocument(path, { nativeWidth: 200, width: 200 }) + let path = window.location.origin + file; + var doc: Document = Documents.ImageDocument(path, { nativeWidth: 200, width: 200 }); const res = await rp.get(ServerUtils.prepend(RouteStore.getUserDocumentId)); if (!res) { @@ -47,12 +47,12 @@ const onFileLoad = async (file: any) => { const field = await Server.GetField(res); let pending: Opt; if (field instanceof Document) { - pending = await field.GetTAsync(KeyStore.OptionalRightCollection, Document) + pending = await field.GetTAsync(KeyStore.OptionalRightCollection, Document); } if (pending) { pending.GetOrCreateAsync(KeyStore.Data, ListField, list => { list.Data.push(doc); - }) + }); } }); @@ -61,7 +61,7 @@ const onFileLoad = async (file: any) => { //imgPrev.setAttribute("src", window.location.origin + files[0].name) } } -} +}; ReactDOM.render((
diff --git a/src/server/Client.ts b/src/server/Client.ts index 6b8841658..02402a5a0 100644 --- a/src/server/Client.ts +++ b/src/server/Client.ts @@ -2,14 +2,14 @@ import { computed } from "mobx"; export class Client { constructor(guid: string) { - this.guid = guid + this.guid = guid; } private guid: string; @computed public get GUID(): string { - return this.guid + return this.guid; } } \ No newline at end of file diff --git a/src/server/authentication/config/passport.ts b/src/server/authentication/config/passport.ts index b6fe15655..d42741410 100644 --- a/src/server/authentication/config/passport.ts +++ b/src/server/authentication/config/passport.ts @@ -1,4 +1,4 @@ -import * as passport from 'passport' +import * as passport from 'passport'; import * as passportLocal from 'passport-local'; import * as mongodb from 'mongodb'; import * as _ from "lodash"; @@ -22,7 +22,7 @@ passport.deserializeUser((id, done) => { passport.use(new LocalStrategy({ usernameField: 'email', passReqToCallback: true }, (req, email, password, done) => { User.findOne({ email: email.toLowerCase() }, (error: any, user: any) => { if (error) return done(error); - if (!user) return done(undefined, false, { message: "Invalid email or password" }) // invalid email + if (!user) return done(undefined, false, { message: "Invalid email or password" }); // invalid email user.comparePassword(password, (error: Error, isMatch: boolean) => { if (error) return done(error); if (!isMatch) return done(undefined, false, { message: "Invalid email or password" }); // invalid password @@ -37,7 +37,7 @@ export let isAuthenticated = (req: Request, res: Response, next: NextFunction) = return next(); } return res.redirect(RouteStore.login); -} +}; export let isAuthorized = (req: Request, res: Response, next: NextFunction) => { const provider = req.path.split("/").slice(-1)[0]; diff --git a/src/server/authentication/controllers/WorkspacesMenu.tsx b/src/server/authentication/controllers/WorkspacesMenu.tsx index 835432c8e..b08c1aebe 100644 --- a/src/server/authentication/controllers/WorkspacesMenu.tsx +++ b/src/server/authentication/controllers/WorkspacesMenu.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; import { observable, action, configure, reaction, computed, ObservableMap, runInAction } from 'mobx'; import { observer } from "mobx-react"; -import './WorkspacesMenu.css' +import './WorkspacesMenu.css'; import { Document } from '../../../fields/Document'; import { EditableView } from '../../../client/views/EditableView'; import { KeyStore } from '../../../fields/KeyStore'; diff --git a/src/server/authentication/controllers/user_controller.ts b/src/server/authentication/controllers/user_controller.ts index 2bbb334b5..1dacdf3fa 100644 --- a/src/server/authentication/controllers/user_controller.ts +++ b/src/server/authentication/controllers/user_controller.ts @@ -109,12 +109,12 @@ export let postLogin = (req: Request, res: Response, next: NextFunction) => { } passport.authenticate("local", (err: Error, user: DashUserModel, info: IVerifyOptions) => { - if (err) { next(err); return } + if (err) { next(err); return; } if (!user) { return res.redirect(RouteStore.signup); } req.logIn(user, (err) => { - if (err) { next(err); return } + if (err) { next(err); return; } res.redirect(RouteStore.home); }); })(req, res, next); @@ -132,14 +132,14 @@ export let getLogout = (req: Request, res: Response) => { sess.destroy((err) => { if (err) { console.log(err); } }); } res.redirect(RouteStore.login); -} +}; export let getForgot = function (req: Request, res: Response) { res.render("forgot.pug", { title: "Recover Password", user: req.user, }); -} +}; export let postForgot = function (req: Request, res: Response, next: NextFunction) { const email = req.body.email; @@ -152,14 +152,14 @@ export let postForgot = function (req: Request, res: Response, next: NextFunctio return; } done(null, buffer.toString('hex')); - }) + }); }, function (token: string, done: any) { User.findOne({ email }, function (err, user: DashUserModel) { if (!user) { // NO ACCOUNT WITH SUBMITTED EMAIL res.redirect(RouteStore.forgot); - return + return; } user.passwordResetToken = token; user.passwordResetExpires = new Date(Date.now() + 3600000); // 1 HOUR @@ -193,8 +193,8 @@ export let postForgot = function (req: Request, res: Response, next: NextFunctio ], function (err) { if (err) return next(err); res.redirect(RouteStore.forgot); - }) -} + }); +}; export let getReset = function (req: Request, res: Response) { User.findOne({ passwordResetToken: req.params.token, passwordResetExpires: { $gt: Date.now() } }, function (err, user: DashUserModel) { @@ -206,7 +206,7 @@ export let getReset = function (req: Request, res: Response) { user: req.user, }); }); -} +}; export let postReset = function (req: Request, res: Response) { async.waterfall([ @@ -263,4 +263,4 @@ export let postReset = function (req: Request, res: Response) { ], function (err) { res.redirect(RouteStore.login); }); -} \ No newline at end of file +}; \ No newline at end of file diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts index 0ac85b446..13eddafbf 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -70,7 +70,7 @@ export class CurrentUserUtils { let doc = new Document(id); doc.Set(KeyStore.Workspaces, new ListField()); - doc.Set(KeyStore.OptionalRightCollection, Documents.SchemaDocument([], { title: "Pending documents" })) + doc.Set(KeyStore.OptionalRightCollection, Documents.SchemaDocument([], { title: "Pending documents" })); return doc; } @@ -81,7 +81,7 @@ export class CurrentUserUtils { CurrentUserUtils.curr_id = obj.id as string; CurrentUserUtils.curr_email = obj.email as string; } else { - throw new Error("There should be a user! Why does Dash think there isn't one?") + throw new Error("There should be a user! Why does Dash think there isn't one?"); } }); let userDocPromise = rp.get(ServerUtils.prepend(RouteStore.getUserDocumentId)).then(id => { @@ -92,9 +92,9 @@ export class CurrentUserUtils { } else { this.user_document = this.createUserDocument(id); } - }) + }); } else { - throw new Error("There should be a user id! Why does Dash think there isn't one?") + throw new Error("There should be a user id! Why does Dash think there isn't one?"); } }); return Promise.all([userPromise, userDocPromise]); diff --git a/src/server/authentication/models/user_model.ts b/src/server/authentication/models/user_model.ts index 81580aad5..1c6926517 100644 --- a/src/server/authentication/models/user_model.ts +++ b/src/server/authentication/models/user_model.ts @@ -2,7 +2,7 @@ import * as bcrypt from "bcrypt-nodejs"; //@ts-ignore import * as mongoose from "mongoose"; -var url = 'mongodb://localhost:27017/Dash' +var url = 'mongodb://localhost:27017/Dash'; mongoose.connect(url, { useNewUrlParser: true }); diff --git a/src/server/database.ts b/src/server/database.ts index 415acc09a..0bc806253 100644 --- a/src/server/database.ts +++ b/src/server/database.ts @@ -1,15 +1,15 @@ import * as mongodb from 'mongodb'; export class Database { - public static Instance = new Database() + public static Instance = new Database(); private MongoClient = mongodb.MongoClient; private url = 'mongodb://localhost:27017/Dash'; private db?: mongodb.Db; constructor() { this.MongoClient.connect(this.url, (err, client) => { - this.db = client.db() - }) + this.db = client.db(); + }); } private currentWrites: { [_id: string]: Promise } = {}; @@ -30,19 +30,19 @@ export class Database { // console.log(JSON.stringify(res.result)); // } if (this.currentWrites[id] === promise) { - delete this.currentWrites[id] + delete this.currentWrites[id]; } if (resolve) { resolve(); } callback(); }); - } + }; if (prom) { const newProm: Promise = prom.then(() => run(newProm)); this.currentWrites[id] = newProm; } else { - const newProm: Promise = new Promise(res => run(newProm, res)) + const newProm: Promise = new Promise(res => run(newProm, res)); this.currentWrites[id] = newProm; } } @@ -61,7 +61,7 @@ export class Database { let collection = this.db.collection(collectionName); collection.deleteMany({}, res); } - }) + }); } public insert(kvpairs: any) { @@ -70,7 +70,7 @@ export class Database { collection.insertOne(kvpairs, (err: any, res: any) => { if (err) { // console.log(err) - return + return; } }); } @@ -81,30 +81,30 @@ export class Database { if (this.db) { let collection = this.db.collection('documents'); collection.findOne({ _id: id }, (err: any, res: any) => { - result = res + result = res; if (!result) { - fn(undefined) + fn(undefined); } - fn(result) - }) - }; + fn(result); + }); + } } public getDocuments(ids: string[], fn: (res: any) => void) { if (this.db) { let collection = this.db.collection('documents'); - let cursor = collection.find({ _id: { "$in": ids } }) + let cursor = collection.find({ _id: { "$in": ids } }); cursor.toArray((err, docs) => { if (err) { console.log(err.message); console.log(err.errmsg); } fn(docs); - }) - }; + }); + } } public print() { - console.log("db says hi!") + console.log("db says hi!"); } } diff --git a/src/server/index.ts b/src/server/index.ts index f60e6e293..b9c7448b4 100644 --- a/src/server/index.ts +++ b/src/server/index.ts @@ -1,10 +1,10 @@ -import * as express from 'express' -const app = express() -import * as webpack from 'webpack' +import * as express from 'express'; +const app = express(); +import * as webpack from 'webpack'; import * as wdm from 'webpack-dev-middleware'; import * as whm from 'webpack-hot-middleware'; -import * as path from 'path' -import * as formidable from 'formidable' +import * as path from 'path'; +import * as formidable from 'formidable'; import * as passport from 'passport'; import { MessageStore, Transferable } from "./Message"; import { Client } from './Client'; @@ -13,7 +13,7 @@ import { Utils } from '../Utils'; import { ObservableMap } from 'mobx'; import { FieldId, Field } from '../fields/Field'; import { Database } from './database'; -import * as io from 'socket.io' +import * as io from 'socket.io'; import { getLogin, postLogin, getSignup, postSignup, getLogout, postReset, getForgot, postForgot, getReset } from './authentication/controllers/user_controller'; const config = require('../../webpack.config'); const compiler = webpack(config); @@ -31,19 +31,19 @@ const MongoStore = require('connect-mongo')(session); const mongoose = require('mongoose'); import { DashUserModel } from './authentication/models/user_model'; import * as fs from 'fs'; -import * as request from 'request' +import * as request from 'request'; import { RouteStore } from './RouteStore'; -import { exec } from 'child_process' +import { exec } from 'child_process'; const download = (url: string, dest: fs.PathLike) => { request.get(url).pipe(fs.createWriteStream(dest)); -} +}; const mongoUrl = 'mongodb://localhost:27017/Dash'; -mongoose.connect(mongoUrl) +mongoose.connect(mongoUrl); mongoose.connection.on('connected', function () { console.log("connected"); -}) +}); // SESSION MANAGEMENT AND AUTHENTICATION MIDDLEWARE // ORDER OF IMPORTS MATTERS @@ -73,7 +73,7 @@ app.use((req, res, next) => { app.get("/hello", (req, res) => { res.send("

Hello

"); -}) +}); enum Method { GET, @@ -98,7 +98,7 @@ function addSecureRoute(method: Method, const dashUser: DashUserModel = req.user; if (!dashUser) return onRejection(res); handler(dashUser, res, req); - } + }; subscribers.forEach(route => { switch (method) { case Method.GET: @@ -116,7 +116,7 @@ function addSecureRoute(method: Method, let FieldStore: ObservableMap = new ObservableMap(); app.use(express.static(__dirname + RouteStore.public)); -app.use(RouteStore.images, express.static(__dirname + RouteStore.public)) +app.use(RouteStore.images, express.static(__dirname + RouteStore.public)); app.get("/pull", (req, res) => { exec('"C:\\Program Files\\Git\\git-bash.exe" -c "git pull"', (err, stdout, stderr) => { @@ -125,7 +125,7 @@ app.get("/pull", (req, res) => { return; } res.redirect("/"); - }) + }); }); // GETTERS @@ -178,13 +178,13 @@ addSecureRoute( addSecureRoute( Method.POST, (user, res, req) => { - let form = new formidable.IncomingForm() - form.uploadDir = __dirname + "/public/files/" - form.keepExtensions = true + let form = new formidable.IncomingForm(); + form.uploadDir = __dirname + "/public/files/"; + form.keepExtensions = true; // let path = req.body.path; - console.log("upload") + console.log("upload"); form.parse(req, (err, fields, files) => { - console.log("parsing") + console.log("parsing"); let names: any[] = []; for (const name in files) { let file = files[name]; @@ -211,8 +211,8 @@ app.post(RouteStore.login, postLogin); app.get(RouteStore.logout, getLogout); // FORGOT PASSWORD EMAIL HANDLING -app.get(RouteStore.forgot, getForgot) -app.post(RouteStore.forgot, postForgot) +app.get(RouteStore.forgot, getForgot); +app.post(RouteStore.forgot, postForgot); // RESET PASSWORD EMAIL HANDLING app.get(RouteStore.reset, getReset); @@ -232,32 +232,32 @@ app.get(RouteStore.deleteAll, (req, res) => { app.use(wdm(compiler, { publicPath: config.output.publicPath -})) +})); -app.use(whm(compiler)) +app.use(whm(compiler)); // start the Express server app.listen(port, () => { console.log(`server started at http://localhost:${port}`); -}) +}); const server = io(); interface Map { [key: string]: Client; } -let clients: Map = {} +let clients: Map = {}; server.on("connection", function (socket: Socket) { - console.log("a user has connected") + console.log("a user has connected"); - Utils.Emit(socket, MessageStore.Foo, "handshooken") + Utils.Emit(socket, MessageStore.Foo, "handshooken"); - Utils.AddServerHandler(socket, MessageStore.Bar, barReceived) - Utils.AddServerHandler(socket, MessageStore.SetField, (args) => setField(socket, args)) - Utils.AddServerHandlerCallback(socket, MessageStore.GetField, getField) - Utils.AddServerHandlerCallback(socket, MessageStore.GetFields, getFields) - Utils.AddServerHandler(socket, MessageStore.DeleteAll, deleteFields) -}) + Utils.AddServerHandler(socket, MessageStore.Bar, barReceived); + Utils.AddServerHandler(socket, MessageStore.SetField, (args) => setField(socket, args)); + Utils.AddServerHandlerCallback(socket, MessageStore.GetField, getField); + Utils.AddServerHandlerCallback(socket, MessageStore.GetFields, getFields); + Utils.AddServerHandler(socket, MessageStore.DeleteAll, deleteFields); +}); function deleteFields() { return Database.Instance.deleteAll(); @@ -276,12 +276,12 @@ function barReceived(guid: String) { function getField([id, callback]: [string, (result: any) => void]) { Database.Instance.getDocument(id, (result: any) => { if (result) { - callback(result) + callback(result); } else { - callback(undefined) + callback(undefined); } - }) + }); } function getFields([ids, callback]: [string[], (result: any) => void]) { @@ -291,7 +291,7 @@ function getFields([ids, callback]: [string[], (result: any) => void]) { function setField(socket: Socket, newValue: Transferable) { Database.Instance.update(newValue._id, newValue, () => { socket.broadcast.emit(MessageStore.SetField.Message, newValue); - }) + }); } server.listen(serverPort); diff --git a/test/test.ts b/test/test.ts index db24cae5f..16cace026 100644 --- a/test/test.ts +++ b/test/test.ts @@ -1,6 +1,6 @@ import { NumberField } from "../src/fields/NumberField"; import { expect } from 'chai'; -import 'mocha' +import 'mocha'; import { Key } from "../src/fields/Key"; import { Document } from "../src/fields/Document"; import { autorun, reaction } from "mobx"; @@ -17,7 +17,7 @@ describe('Number Controller', () => { it('Should update', () => { const numController = new NumberField(15); let ran = false; - reaction(() => numController.Data, (data) => { ran = true; }) + reaction(() => numController.Data, (data) => { ran = true; }); expect(ran).to.equal(false); numController.Data = 5; expect(ran).to.equal(true); @@ -42,7 +42,7 @@ describe("Document", () => { let key = new Key("Test"); let key2 = new Key("Test2"); let ran = false; - reaction(() => doc.Get(key), (field) => { ran = true }); + reaction(() => doc.Get(key), (field) => { ran = true; }); expect(ran).to.equal(false); doc.Set(key2, new NumberField(4)); diff --git a/tslint.json b/tslint.json index 54876916e..aa4dee4e5 100644 --- a/tslint.json +++ b/tslint.json @@ -27,14 +27,14 @@ "arrow-return-shorthand": true, // "object-literal-shorthand": true, // "object-literal-sort-keys": true, - // "semicolon": [ - // true, - // "always" - // ], - // "curly": [ - // true, - // "ignore-same-line" - // ], + "semicolon": [ + true, + "always" + ], + "curly": [ + true, + "ignore-same-line" + ], // "quotemark": [ // true, // "double", -- cgit v1.2.3-70-g09d2 From 4e45ad641bd34c4703188e69a93a23243f3659a4 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Wed, 10 Apr 2019 21:35:12 -0400 Subject: fixed text menu and text dragging. --- src/client/util/TooltipTextMenu.tsx | 14 +++++++++----- src/client/views/DocumentDecorations.scss | 3 +++ src/client/views/Main.scss | 1 + src/client/views/Main.tsx | 23 +++++++++++++++++++---- src/client/views/nodes/FormattedTextBox.tsx | 13 +++++++++---- 5 files changed, 41 insertions(+), 13 deletions(-) (limited to 'src/client/util/TooltipTextMenu.tsx') diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx index bd5753093..7951e5686 100644 --- a/src/client/util/TooltipTextMenu.tsx +++ b/src/client/util/TooltipTextMenu.tsx @@ -12,19 +12,23 @@ const { toggleMark, setBlockType, wrapIn } = require("prosemirror-commands"); import { library } from '@fortawesome/fontawesome-svg-core'; import { wrapInList, bulletList } from 'prosemirror-schema-list'; import { faListUl } from '@fortawesome/free-solid-svg-icons'; +import { FieldViewProps } from "../views/nodes/FieldView"; +import { throwStatement } from "babel-types"; //appears above a selection of text in a RichTextBox to give user options such as Bold, Italics, etc. export class TooltipTextMenu { private tooltip: HTMLElement; + private editorProps: FieldViewProps; - constructor(view: EditorView) { + constructor(view: EditorView, editorProps: FieldViewProps) { + this.editorProps = editorProps; this.tooltip = document.createElement("div"); this.tooltip.className = "tooltipMenu"; //add the div which is the tooltip - view.dom.parentNode!.appendChild(this.tooltip); + view.dom.parentNode!.parentNode!.appendChild(this.tooltip); //add additional icons library.add(faListUl); @@ -124,13 +128,13 @@ export class TooltipTextMenu { // Find a center-ish x position from the selection endpoints (when // crossing lines, end may be more to the left) let left = Math.max((start.left + end.left) / 2, start.left + 3); - this.tooltip.style.left = (left - box.left) + "px"; - let width = Math.abs(start.left - end.left) / 2; + this.tooltip.style.left = (left - box.left) * this.editorProps.ScreenToLocalTransform().Scale + "px"; + let width = Math.abs(start.left - end.left) / 2 * this.editorProps.ScreenToLocalTransform().Scale; let mid = Math.min(start.left, end.left) + width; //THIS WIDTH IS 15 * NUMBER OF ICONS + 15 this.tooltip.style.width = 122 + "px"; - this.tooltip.style.bottom = (box.bottom - start.top) + "px"; + this.tooltip.style.bottom = (box.bottom - start.top) * this.editorProps.ScreenToLocalTransform().Scale + "px"; } destroy() { this.tooltip.remove(); } diff --git a/src/client/views/DocumentDecorations.scss b/src/client/views/DocumentDecorations.scss index c4e4aed8e..b2096bccb 100644 --- a/src/client/views/DocumentDecorations.scss +++ b/src/client/views/DocumentDecorations.scss @@ -1,5 +1,8 @@ @import "global_variables"; +.documentDecorations { + position: absolute; +} #documentDecorations-container { position: absolute; top: 0; diff --git a/src/client/views/Main.scss b/src/client/views/Main.scss index c4da47e0e..a68b90dd4 100644 --- a/src/client/views/Main.scss +++ b/src/client/views/Main.scss @@ -176,6 +176,7 @@ button:hover { overflow: visible; top: 0; left: 0; + z-index: 1000; .formattedTextBox-cont { background-color: rgba(248, 6, 6, 0.001); width: 100%; diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx index e96e4cbf8..b73b55fb1 100644 --- a/src/client/views/Main.tsx +++ b/src/client/views/Main.tsx @@ -28,7 +28,7 @@ import '../northstar/model/ModelExtensions'; import { HistogramOperation } from '../northstar/operations/HistogramOperation'; import '../northstar/utils/Extensions'; import { Server } from '../Server'; -import { setupDrag } from '../util/DragManager'; +import { setupDrag, DragManager } from '../util/DragManager'; import { Transform } from '../util/Transform'; import { UndoManager } from '../util/UndoManager'; import { CollectionDockingView } from './collections/CollectionDockingView'; @@ -38,6 +38,7 @@ import { InkingControl } from './InkingControl'; import "./Main.scss"; import { DocumentView } from './nodes/DocumentView'; import { FormattedTextBox } from './nodes/FormattedTextBox'; +import { REPLCommand } from 'repl'; @observer export class Main extends React.Component { @@ -228,6 +229,21 @@ export class Main extends React.Component { } } + textBoxDown = (e: React.PointerEvent) => { + let dragData = new DragManager.DocumentDragData([this._textDoc!]); + const [left, top] = this._textXf + .inverse() + .transformPoint(0, 0); + dragData.xOffset = e.clientX - left; + dragData.yOffset = e.clientY - top; + DragManager.StartDocumentDrag([this._textTargetDiv!], dragData, e.clientX, e.clientY, { + handlers: { + dragComplete: action(emptyFunction), + }, + hideSource: false + }); + } + @computed get activeTextBox() { if (this._textDoc) { @@ -239,9 +255,8 @@ export class Main extends React.Component { let s = this._textXf.transformPoint(1, 0); s[0] = Math.sqrt((s[0] - t[0]) * (s[0] - t[0]) + (s[1] - t[1]) * (s[1] - t[1])); return
-
- { }} /> - +
+ this._textXf} focus={(doc) => { }} />
; } diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index eb40a03a5..69086df42 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -70,12 +70,16 @@ export class FormattedTextBox extends React.Component { const config = { schema, inpRules, //these currently don't do anything, but could eventually be helpful - plugins: [ + plugins: this.props.fieldKey === KeyStore.Archives ? [ history(), keymap({ "Mod-z": undo, "Mod-y": redo }), keymap(baseKeymap), this.tooltipMenuPlugin() - ] + ] : [ + history(), + keymap({ "Mod-z": undo, "Mod-y": redo }), + keymap(baseKeymap), + ] }; if (this.props.fieldKey === KeyStore.Archives) { @@ -150,7 +154,7 @@ export class FormattedTextBox extends React.Component { // doc.SetData(fieldKey, e.target.value, RichTextField); } onPointerDown = (e: React.PointerEvent): void => { - if (e.buttons === 1 && this.props.isSelected() && !e.altKey) { + if (e.buttons === 1 && this.props.isSelected() && !e.altKey && !e.ctrlKey && !e.metaKey) { e.stopPropagation(); } } @@ -202,9 +206,10 @@ export class FormattedTextBox extends React.Component { } tooltipMenuPlugin() { + let myprops = this.props; return new Plugin({ view(_editorView) { - return new TooltipTextMenu(_editorView); + return new TooltipTextMenu(_editorView, myprops); } }); } -- cgit v1.2.3-70-g09d2 From 15514b0f3d685764d1bd7ebeac9cdee1f778e184 Mon Sep 17 00:00:00 2001 From: laurawilsonri Date: Thu, 11 Apr 2019 12:06:46 -0400 Subject: font style and size dropdowns work --- package.json | 332 +++++++++--------- src/client/util/RichTextSchema.tsx | 507 ++++++++++++++++------------ src/client/util/TooltipTextMenu.scss | 238 ++++++++++++- src/client/util/TooltipTextMenu.tsx | 173 +++++++--- src/client/views/nodes/FormattedTextBox.tsx | 7 +- 5 files changed, 830 insertions(+), 427 deletions(-) (limited to 'src/client/util/TooltipTextMenu.tsx') diff --git a/package.json b/package.json index 135bd4a91..11eb6f0f5 100644 --- a/package.json +++ b/package.json @@ -1,168 +1,168 @@ { - "name": "dash", - "version": "1.0.0", - "description": "", - "main": "index.js", - "scripts": { - "start": "nodemon --watch src/server/**/*.ts --exec ts-node src/server/index.ts", - "build": "webpack --env production", - "test": "mocha -r ts-node/register test/**/*.ts", - "tsc": "tsc" - }, - "devDependencies": { - "@types/chai": "^4.1.7", - "@types/mocha": "^5.2.6", - "@types/react-dom": "^16.8.2", - "@types/webpack-dev-middleware": "^2.0.2", - "@types/webpack-hot-middleware": "^2.16.4", - "awesome-typescript-loader": "^5.2.1", - "chai": "^4.2.0", - "copy-webpack-plugin": "^4.6.0", - "css-loader": "^2.1.1", - "file-loader": "^3.0.1", - "mocha": "^5.2.0", - "sass-loader": "^7.1.0", - "scss-loader": "0.0.1", - "style-loader": "^0.23.1", - "ts-node": "^7.0.1", - "typescript": "^3.4.1", - "webpack": "^4.29.6", - "webpack-cli": "^3.2.3", - "webpack-dev-middleware": "^3.6.1", - "webpack-dev-server": "^3.2.1", - "webpack-hot-middleware": "^2.24.3" - }, - "dependencies": { - "@fortawesome/fontawesome-free-solid": "^5.0.13", - "@fortawesome/fontawesome-svg-core": "^1.2.15", - "@fortawesome/free-solid-svg-icons": "^5.7.2", - "@fortawesome/react-fontawesome": "^0.1.4", - "@hig/flyout": "^1.0.3", - "@hig/theme-context": "^2.1.3", - "@hig/theme-data": "^2.3.3", - "@trendmicro/react-dropdown": "^1.3.0", - "@types/async": "^2.4.1", - "@types/bcrypt-nodejs": "0.0.30", - "@types/bluebird": "^3.5.25", - "@types/body-parser": "^1.17.0", - "@types/connect-flash": "0.0.34", - "@types/cookie-parser": "^1.4.1", - "@types/cookie-session": "^2.0.36", - "@types/d3-format": "^1.3.1", - "@types/express": "^4.16.1", - "@types/express-flash": "0.0.0", - "@types/express-session": "^1.15.12", - "@types/express-validator": "^3.0.0", - "@types/formidable": "^1.0.31", - "@types/jquery": "^3.3.29", - "@types/jsonwebtoken": "^8.3.2", - "@types/lodash": "^4.14.121", - "@types/mobile-detect": "^1.3.4", - "@types/mongodb": "^3.1.22", - "@types/mongoose": "^5.3.21", - "@types/node": "^10.12.30", - "@types/nodemailer": "^4.6.6", - "@types/passport": "^1.0.0", - "@types/passport-local": "^1.0.33", - "@types/prosemirror-commands": "^1.0.1", - "@types/prosemirror-history": "^1.0.1", - "@types/prosemirror-inputrules": "^1.0.2", - "@types/prosemirror-keymap": "^1.0.1", - "@types/prosemirror-menu": "^1.0.1", - "@types/prosemirror-model": "^1.7.0", - "@types/prosemirror-schema-basic": "^1.0.1", - "@types/prosemirror-schema-list": "^1.0.1", - "@types/prosemirror-state": "^1.2.3", - "@types/prosemirror-transform": "^1.1.0", - "@types/prosemirror-view": "^1.3.1", - "@types/pug": "^2.0.4", - "@types/react": "^16.8.7", - "@types/react-color": "^2.14.1", - "@types/react-measure": "^2.0.4", - "@types/react-table": "^6.7.22", - "@types/request": "^2.48.1", - "@types/request-promise": "^4.1.42", - "@types/socket.io": "^2.1.2", - "@types/socket.io-client": "^1.4.32", - "@types/typescript": "^2.0.0", - "@types/uuid": "^3.4.4", - "@types/webpack": "^4.4.25", - "async": "^2.6.2", - "babel-runtime": "^6.26.0", - "bcrypt-nodejs": "0.0.3", - "bluebird": "^3.5.3", - "body-parser": "^1.18.3", - "bootstrap": "^4.3.1", - "class-transformer": "^0.2.0", - "connect-flash": "^0.1.1", - "connect-mongo": "^2.0.3", - "cookie-parser": "^1.4.4", - "cookie-session": "^2.0.0-beta.3", - "crypto-browserify": "^3.11.0", - "d3-format": "^1.3.2", - "express": "^4.16.4", - "express-flash": "0.0.2", - "express-session": "^1.15.6", - "express-validator": "^5.3.1", - "expressjs": "^1.0.1", - "flexlayout-react": "^0.3.3", - "font-awesome": "^4.7.0", - "formidable": "^1.2.1", - "golden-layout": "^1.5.9", - "html-to-image": "^0.1.0", - "i": "^0.3.6", - "jsonwebtoken": "^8.5.0", - "jsx-to-string": "^1.4.0", - "lodash": "^4.17.11", - "mobile-detect": "^1.4.3", - "mobx": "^5.9.0", - "mobx-react": "^5.3.5", - "mobx-react-devtools": "^6.1.1", - "mongodb": "^3.1.13", - "mongoose": "^5.4.18", - "node-sass": "^4.11.0", - "nodemailer": "^5.1.1", - "nodemon": "^1.18.10", - "normalize.css": "^8.0.1", - "npm": "^6.9.0", - "passport": "^0.4.0", - "passport-local": "^1.0.0", - "prosemirror-commands": "^1.0.7", - "prosemirror-example-setup": "^1.0.1", - "prosemirror-history": "^1.0.4", - "prosemirror-keymap": "^1.0.1", - "prosemirror-model": "^1.7.0", - "prosemirror-schema-basic": "^1.0.0", - "prosemirror-schema-list": "^1.0.2", - "prosemirror-state": "^1.2.2", - "prosemirror-transform": "^1.1.3", - "prosemirror-view": "^1.8.3", - "pug": "^2.0.3", - "raw-loader": "^1.0.0", - "react": "^16.8.4", - "react-bootstrap": "^1.0.0-beta.5", - "react-bootstrap-dropdown-menu": "^1.1.15", - "react-color": "^2.17.0", - "react-dimensions": "^1.3.1", - "react-dom": "^16.8.4", - "react-golden-layout": "^1.0.6", - "react-image-lightbox": "^5.1.0", - "react-jsx-parser": "^1.15.0", - "react-measure": "^2.2.4", - "react-mosaic": "0.0.20", - "react-pdf": "^4.0.2", - "react-pdf-highlighter": "^2.1.2", - "react-pdf-js": "^4.0.2", - "react-simple-dropdown": "^3.2.3", - "react-split-pane": "^0.1.85", - "react-table": "^6.9.2", - "request": "^2.88.0", - "request-promise": "^4.2.4", - "socket.io": "^2.2.0", - "socket.io-client": "^2.2.0", - "typescript-collections": "^1.3.2", - "url-loader": "^1.1.2", - "uuid": "^3.3.2", - "xoauth2": "^1.2.0" - } + "name": "dash", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "start": "nodemon --watch src/server/**/*.ts --exec ts-node src/server/index.ts", + "build": "webpack --env production", + "test": "mocha -r ts-node/register test/**/*.ts", + "tsc": "tsc" + }, + "devDependencies": { + "@types/chai": "^4.1.7", + "@types/mocha": "^5.2.6", + "@types/react-dom": "^16.8.2", + "@types/webpack-dev-middleware": "^2.0.2", + "@types/webpack-hot-middleware": "^2.16.4", + "awesome-typescript-loader": "^5.2.1", + "chai": "^4.2.0", + "copy-webpack-plugin": "^4.6.0", + "css-loader": "^2.1.1", + "file-loader": "^3.0.1", + "mocha": "^5.2.0", + "sass-loader": "^7.1.0", + "scss-loader": "0.0.1", + "style-loader": "^0.23.1", + "ts-node": "^7.0.1", + "typescript": "^3.4.1", + "webpack": "^4.29.6", + "webpack-cli": "^3.2.3", + "webpack-dev-middleware": "^3.6.1", + "webpack-dev-server": "^3.2.1", + "webpack-hot-middleware": "^2.24.3" + }, + "dependencies": { + "@fortawesome/fontawesome-free-solid": "^5.0.13", + "@fortawesome/fontawesome-svg-core": "^1.2.15", + "@fortawesome/free-solid-svg-icons": "^5.7.2", + "@fortawesome/react-fontawesome": "^0.1.4", + "@hig/flyout": "^1.0.3", + "@hig/theme-context": "^2.1.3", + "@hig/theme-data": "^2.3.3", + "@trendmicro/react-dropdown": "^1.3.0", + "@types/async": "^2.4.1", + "@types/bcrypt-nodejs": "0.0.30", + "@types/bluebird": "^3.5.25", + "@types/body-parser": "^1.17.0", + "@types/connect-flash": "0.0.34", + "@types/cookie-parser": "^1.4.1", + "@types/cookie-session": "^2.0.36", + "@types/d3-format": "^1.3.1", + "@types/express": "^4.16.1", + "@types/express-flash": "0.0.0", + "@types/express-session": "^1.15.12", + "@types/express-validator": "^3.0.0", + "@types/formidable": "^1.0.31", + "@types/jquery": "^3.3.29", + "@types/jsonwebtoken": "^8.3.2", + "@types/lodash": "^4.14.121", + "@types/mobile-detect": "^1.3.4", + "@types/mongodb": "^3.1.22", + "@types/mongoose": "^5.3.21", + "@types/node": "^10.12.30", + "@types/nodemailer": "^4.6.6", + "@types/passport": "^1.0.0", + "@types/passport-local": "^1.0.33", + "@types/prosemirror-commands": "^1.0.1", + "@types/prosemirror-history": "^1.0.1", + "@types/prosemirror-inputrules": "^1.0.2", + "@types/prosemirror-keymap": "^1.0.1", + "@types/prosemirror-menu": "^1.0.1", + "@types/prosemirror-model": "^1.7.0", + "@types/prosemirror-schema-basic": "^1.0.1", + "@types/prosemirror-schema-list": "^1.0.1", + "@types/prosemirror-state": "^1.2.3", + "@types/prosemirror-transform": "^1.1.0", + "@types/prosemirror-view": "^1.3.1", + "@types/pug": "^2.0.4", + "@types/react": "^16.8.7", + "@types/react-color": "^2.14.1", + "@types/react-measure": "^2.0.4", + "@types/react-table": "^6.7.22", + "@types/request": "^2.48.1", + "@types/request-promise": "^4.1.42", + "@types/socket.io": "^2.1.2", + "@types/socket.io-client": "^1.4.32", + "@types/typescript": "^2.0.0", + "@types/uuid": "^3.4.4", + "@types/webpack": "^4.4.25", + "async": "^2.6.2", + "babel-runtime": "^6.26.0", + "bcrypt-nodejs": "0.0.3", + "bluebird": "^3.5.3", + "body-parser": "^1.18.3", + "bootstrap": "^4.3.1", + "class-transformer": "^0.2.0", + "connect-flash": "^0.1.1", + "connect-mongo": "^2.0.3", + "cookie-parser": "^1.4.4", + "cookie-session": "^2.0.0-beta.3", + "crypto-browserify": "^3.11.0", + "d3-format": "^1.3.2", + "express": "^4.16.4", + "express-flash": "0.0.2", + "express-session": "^1.15.6", + "express-validator": "^5.3.1", + "expressjs": "^1.0.1", + "flexlayout-react": "^0.3.3", + "font-awesome": "^4.7.0", + "formidable": "^1.2.1", + "golden-layout": "^1.5.9", + "html-to-image": "^0.1.0", + "i": "^0.3.6", + "jsonwebtoken": "^8.5.0", + "jsx-to-string": "^1.4.0", + "lodash": "^4.17.11", + "mobile-detect": "^1.4.3", + "mobx": "^5.9.0", + "mobx-react": "^5.3.5", + "mobx-react-devtools": "^6.1.1", + "mongodb": "^3.1.13", + "mongoose": "^5.4.18", + "node-sass": "^4.11.0", + "nodemailer": "^5.1.1", + "nodemon": "^1.18.10", + "normalize.css": "^8.0.1", + "npm": "^6.9.0", + "passport": "^0.4.0", + "passport-local": "^1.0.0", + "prosemirror-commands": "^1.0.7", + "prosemirror-example-setup": "^1.0.1", + "prosemirror-history": "^1.0.4", + "prosemirror-keymap": "^1.0.1", + "prosemirror-model": "^1.7.0", + "prosemirror-schema-basic": "^1.0.0", + "prosemirror-schema-list": "^1.0.2", + "prosemirror-state": "^1.2.2", + "prosemirror-transform": "^1.1.3", + "prosemirror-view": "^1.8.3", + "pug": "^2.0.3", + "raw-loader": "^1.0.0", + "react": "^16.8.4", + "react-bootstrap": "^1.0.0-beta.5", + "react-bootstrap-dropdown-menu": "^1.1.15", + "react-color": "^2.17.0", + "react-dimensions": "^1.3.1", + "react-dom": "^16.8.4", + "react-golden-layout": "^1.0.6", + "react-image-lightbox": "^5.1.0", + "react-jsx-parser": "^1.15.0", + "react-measure": "^2.2.4", + "react-mosaic": "0.0.20", + "react-pdf": "^4.0.2", + "react-pdf-highlighter": "^2.1.2", + "react-pdf-js": "^4.0.2", + "react-simple-dropdown": "^3.2.3", + "react-split-pane": "^0.1.85", + "react-table": "^6.9.2", + "request": "^2.88.0", + "request-promise": "^4.2.4", + "socket.io": "^2.2.0", + "socket.io-client": "^2.2.0", + "typescript-collections": "^1.3.2", + "url-loader": "^1.1.2", + "uuid": "^3.3.2", + "xoauth2": "^1.2.0" + } } diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx index 489c22a57..765ac0ae3 100644 --- a/src/client/util/RichTextSchema.tsx +++ b/src/client/util/RichTextSchema.tsx @@ -7,134 +7,134 @@ import { EditorState, Transaction, NodeSelection, } from "prosemirror-state"; import { EditorView, } from "prosemirror-view"; const pDOM: DOMOutputSpecArray = ["p", 0], blockquoteDOM: DOMOutputSpecArray = ["blockquote", 0], hrDOM: DOMOutputSpecArray = ["hr"], - preDOM: DOMOutputSpecArray = ["pre", ["code", 0]], brDOM: DOMOutputSpecArray = ["br"], ulDOM: DOMOutputSpecArray = ["ul", 0] + preDOM: DOMOutputSpecArray = ["pre", ["code", 0]], brDOM: DOMOutputSpecArray = ["br"], ulDOM: DOMOutputSpecArray = ["ul", 0] // :: Object // [Specs](#model.NodeSpec) for the nodes defined in this schema. export const nodes: { [index: string]: NodeSpec } = { - // :: NodeSpec The top level document node. - doc: { - content: "block+" - }, - - // :: NodeSpec A plain paragraph textblock. Represented in the DOM - // as a `

` element. - paragraph: { - content: "inline*", - group: "block", - parseDOM: [{ tag: "p" }], - toDOM() { return pDOM } - }, - - // :: NodeSpec A blockquote (`

`) wrapping one or more blocks. - blockquote: { - content: "block+", - group: "block", - defining: true, - parseDOM: [{ tag: "blockquote" }], - toDOM() { return blockquoteDOM } - }, - - // :: NodeSpec A horizontal rule (`
`). - horizontal_rule: { - group: "block", - parseDOM: [{ tag: "hr" }], - toDOM() { return hrDOM } - }, - - // :: NodeSpec A heading textblock, with a `level` attribute that - // should hold the number 1 to 6. Parsed and serialized as `

` to - // `

` elements. - heading: { - attrs: { level: { default: 1 } }, - content: "inline*", - group: "block", - defining: true, - parseDOM: [{ tag: "h1", attrs: { level: 1 } }, - { tag: "h2", attrs: { level: 2 } }, - { tag: "h3", attrs: { level: 3 } }, - { tag: "h4", attrs: { level: 4 } }, - { tag: "h5", attrs: { level: 5 } }, - { tag: "h6", attrs: { level: 6 } }], - toDOM(node: any) { return ["h" + node.attrs.level, 0] } - }, - - // :: NodeSpec A code listing. Disallows marks or non-text inline - // nodes by default. Represented as a `
` element with a
-  // `` element inside of it.
-  code_block: {
-    content: "text*",
-    marks: "",
-    group: "block",
-    code: true,
-    defining: true,
-    parseDOM: [{ tag: "pre", preserveWhitespace: "full" }],
-    toDOM() { return preDOM }
-  },
-
-  // :: NodeSpec The text node.
-  text: {
-    group: "inline"
-  },
-
-  // :: NodeSpec An inline image (``) node. Supports `src`,
-  // `alt`, and `href` attributes. The latter two default to the empty
-  // string.
-  image: {
-    inline: true,
-    attrs: {
-      src: {},
-      alt: { default: null },
-      title: { default: null }
-    },
-    group: "inline",
-    draggable: true,
-    parseDOM: [{
-      tag: "img[src]", getAttrs(dom: any) {
-        return {
-          src: dom.getAttribute("src"),
-          title: dom.getAttribute("title"),
-          alt: dom.getAttribute("alt")
-        }
-      }
-    }],
-    toDOM(node: any) { return ["img", node.attrs] }
-  },
-
-  // :: NodeSpec A hard line break, represented in the DOM as `
`. - hard_break: { - inline: true, - group: "inline", - selectable: false, - parseDOM: [{ tag: "br" }], - toDOM() { return brDOM } - }, - - ordered_list: { - ...orderedList, - content: 'list_item+', - group: 'block' - }, - //this doesn't currently work for some reason - bullet_list: { - ...bulletList, - content: 'list_item+', - group: 'block', - // parseDOM: [{ tag: "ul" }, { style: 'list-style-type=disc' }], - // toDOM() { return ulDOM } - }, - //bullet_list: { - // content: 'list_item+', - // group: 'block', - //active: blockActive(schema.nodes.bullet_list), - //enable: wrapInList(schema.nodes.bullet_list), - //run: wrapInList(schema.nodes.bullet_list), - //select: state => true, - // }, - list_item: { - ...listItem, - content: 'paragraph block*' - } + // :: NodeSpec The top level document node. + doc: { + content: "block+" + }, + + // :: NodeSpec A plain paragraph textblock. Represented in the DOM + // as a `

` element. + paragraph: { + content: "inline*", + group: "block", + parseDOM: [{ tag: "p" }], + toDOM() { return pDOM } + }, + + // :: NodeSpec A blockquote (`

`) wrapping one or more blocks. + blockquote: { + content: "block+", + group: "block", + defining: true, + parseDOM: [{ tag: "blockquote" }], + toDOM() { return blockquoteDOM } + }, + + // :: NodeSpec A horizontal rule (`
`). + horizontal_rule: { + group: "block", + parseDOM: [{ tag: "hr" }], + toDOM() { return hrDOM } + }, + + // :: NodeSpec A heading textblock, with a `level` attribute that + // should hold the number 1 to 6. Parsed and serialized as `

` to + // `

` elements. + heading: { + attrs: { level: { default: 1 } }, + content: "inline*", + group: "block", + defining: true, + parseDOM: [{ tag: "h1", attrs: { level: 1 } }, + { tag: "h2", attrs: { level: 2 } }, + { tag: "h3", attrs: { level: 3 } }, + { tag: "h4", attrs: { level: 4 } }, + { tag: "h5", attrs: { level: 5 } }, + { tag: "h6", attrs: { level: 6 } }], + toDOM(node: any) { return ["h" + node.attrs.level, 0] } + }, + + // :: NodeSpec A code listing. Disallows marks or non-text inline + // nodes by default. Represented as a `
` element with a
+    // `` element inside of it.
+    code_block: {
+        content: "text*",
+        marks: "",
+        group: "block",
+        code: true,
+        defining: true,
+        parseDOM: [{ tag: "pre", preserveWhitespace: "full" }],
+        toDOM() { return preDOM }
+    },
+
+    // :: NodeSpec The text node.
+    text: {
+        group: "inline"
+    },
+
+    // :: NodeSpec An inline image (``) node. Supports `src`,
+    // `alt`, and `href` attributes. The latter two default to the empty
+    // string.
+    image: {
+        inline: true,
+        attrs: {
+            src: {},
+            alt: { default: null },
+            title: { default: null }
+        },
+        group: "inline",
+        draggable: true,
+        parseDOM: [{
+            tag: "img[src]", getAttrs(dom: any) {
+                return {
+                    src: dom.getAttribute("src"),
+                    title: dom.getAttribute("title"),
+                    alt: dom.getAttribute("alt")
+                }
+            }
+        }],
+        toDOM(node: any) { return ["img", node.attrs] }
+    },
+
+    // :: NodeSpec A hard line break, represented in the DOM as `
`. + hard_break: { + inline: true, + group: "inline", + selectable: false, + parseDOM: [{ tag: "br" }], + toDOM() { return brDOM } + }, + + ordered_list: { + ...orderedList, + content: 'list_item+', + group: 'block' + }, + //this doesn't currently work for some reason + bullet_list: { + ...bulletList, + content: 'list_item+', + group: 'block', + // parseDOM: [{ tag: "ul" }, { style: 'list-style-type=disc' }], + // toDOM() { return ulDOM } + }, + //bullet_list: { + // content: 'list_item+', + // group: 'block', + //active: blockActive(schema.nodes.bullet_list), + //enable: wrapInList(schema.nodes.bullet_list), + //run: wrapInList(schema.nodes.bullet_list), + //select: state => true, + // }, + list_item: { + ...listItem, + content: 'paragraph block*' + } } const emDOM: DOMOutputSpecArray = ["em", 0]; @@ -144,92 +144,179 @@ const underlineDOM: DOMOutputSpecArray = ["underline", 0]; // :: Object [Specs](#model.MarkSpec) for the marks in the schema. export const marks: { [index: string]: MarkSpec } = { - // :: MarkSpec A link. Has `href` and `title` attributes. `title` - // defaults to the empty string. Rendered and parsed as an `` - // element. - link: { - attrs: { - href: {}, - title: { default: null } - }, - inclusive: false, - parseDOM: [{ - tag: "a[href]", getAttrs(dom: any) { - return { href: dom.getAttribute("href"), title: dom.getAttribute("title") } - } - }], - toDOM(node: any) { return ["a", node.attrs, 0] } - }, - - // :: MarkSpec An emphasis mark. Rendered as an `` element. - // Has parse rules that also match `` and `font-style: italic`. - em: { - parseDOM: [{ tag: "i" }, { tag: "em" }, { style: "font-style=italic" }], - toDOM() { return emDOM } - }, - - // :: MarkSpec A strong mark. Rendered as ``, parse rules - // also match `` and `font-weight: bold`. - strong: { - parseDOM: [{ tag: "strong" }, - { tag: "b" }, - { style: "font-weight" }], - toDOM() { return strongDOM } - }, - - underline: { - parseDOM: [ - { tag: 'u' }, - { style: 'text-decoration=underline' } - ], - toDOM: () => ['span', { - style: 'text-decoration:underline' - }] - }, - - strikethrough: { - parseDOM: [ - { tag: 'strike' }, - { style: 'text-decoration=line-through' }, - { style: 'text-decoration-line=line-through' } - ], - toDOM: () => ['span', { - style: 'text-decoration-line:line-through' - }] - }, - - subscript: { - excludes: 'superscript', - parseDOM: [ - { tag: 'sub' }, - { style: 'vertical-align=sub' } - ], - toDOM: () => ['sub'] - }, - - superscript: { - excludes: 'subscript', - parseDOM: [ - { tag: 'sup' }, - { style: 'vertical-align=super' } - ], - toDOM: () => ['sup'] - }, - - - // :: MarkSpec Code font mark. Represented as a `` element. - code: { - parseDOM: [{ tag: "code" }], - toDOM() { return codeDOM } - }, - - - timesNewRoman: { - parseDOM: [{ style: 'font-family: "Times New Roman", Times, serif;' }], - toDOM: () => ['span', { - style: 'font-family: "Times New Roman", Times, serif;' - }] - }, + // :: MarkSpec A link. Has `href` and `title` attributes. `title` + // defaults to the empty string. Rendered and parsed as an `` + // element. + link: { + attrs: { + href: {}, + title: { default: null } + }, + inclusive: false, + parseDOM: [{ + tag: "a[href]", getAttrs(dom: any) { + return { href: dom.getAttribute("href"), title: dom.getAttribute("title") } + } + }], + toDOM(node: any) { return ["a", node.attrs, 0] } + }, + + // :: MarkSpec An emphasis mark. Rendered as an `` element. + // Has parse rules that also match `` and `font-style: italic`. + em: { + parseDOM: [{ tag: "i" }, { tag: "em" }, { style: "font-style=italic" }], + toDOM() { return emDOM } + }, + + // :: MarkSpec A strong mark. Rendered as ``, parse rules + // also match `` and `font-weight: bold`. + strong: { + parseDOM: [{ tag: "strong" }, + { tag: "b" }, + { style: "font-weight" }], + toDOM() { return strongDOM } + }, + + underline: { + parseDOM: [ + { tag: 'u' }, + { style: 'text-decoration=underline' } + ], + toDOM: () => ['span', { + style: 'text-decoration:underline' + }] + }, + + strikethrough: { + parseDOM: [ + { tag: 'strike' }, + { style: 'text-decoration=line-through' }, + { style: 'text-decoration-line=line-through' } + ], + toDOM: () => ['span', { + style: 'text-decoration-line:line-through' + }] + }, + + subscript: { + excludes: 'superscript', + parseDOM: [ + { tag: 'sub' }, + { style: 'vertical-align=sub' } + ], + toDOM: () => ['sub'] + }, + + superscript: { + excludes: 'subscript', + parseDOM: [ + { tag: 'sup' }, + { style: 'vertical-align=super' } + ], + toDOM: () => ['sup'] + }, + + + // :: MarkSpec Code font mark. Represented as a `` element. + code: { + parseDOM: [{ tag: "code" }], + toDOM() { return codeDOM } + }, + + + /* FONTS */ + timesNewRoman: { + parseDOM: [{ style: 'font-family: "Times New Roman", Times, serif;' }], + toDOM: () => ['span', { + style: 'font-family: "Times New Roman", Times, serif;' + }] + }, + + arial: { + parseDOM: [{ style: 'font-family: Arial, Helvetica, sans-serif;' }], + toDOM: () => ['span', { + style: 'font-family: Arial, Helvetica, sans-serif;' + }] + }, + + georgia: { + parseDOM: [{ style: 'font-family: Georgia, serif;' }], + toDOM: () => ['span', { + style: 'font-family: Georgia, serif;' + }] + }, + + comicSans: { + parseDOM: [{ style: 'font-family: "Comic Sans MS", cursive, sans-serif;' }], + toDOM: () => ['span', { + style: 'font-family: "Comic Sans MS", cursive, sans-serif;' + }] + }, + + tahoma: { + parseDOM: [{ style: 'font-family: Tahoma, Geneva, sans-serif;' }], + toDOM: () => ['span', { + style: 'font-family: Tahoma, Geneva, sans-serif;' + }] + }, + + impact: { + parseDOM: [{ style: 'font-family: Impact, Charcoal, sans-serif;' }], + toDOM: () => ['span', { + style: 'font-family: Impact, Charcoal, sans-serif;' + }] + }, + + /** FONT SIZES */ + + p10: { + parseDOM: [{ style: 'font-size: 10px;' }], + toDOM: () => ['span', { + style: 'font-size: 10px;' + }] + }, + + p12: { + parseDOM: [{ style: 'font-size: 12px;' }], + toDOM: () => ['span', { + style: 'font-size: 12px;' + }] + }, + + p16: { + parseDOM: [{ style: 'font-size: 16px;' }], + toDOM: () => ['span', { + style: 'font-size: 16px;' + }] + }, + + p24: { + parseDOM: [{ style: 'font-size: 24px;' }], + toDOM: () => ['span', { + style: 'font-size: 24px;' + }] + }, + + p32: { + parseDOM: [{ style: 'font-size: 32px;' }], + toDOM: () => ['span', { + style: 'font-size: 32px;' + }] + }, + + p48: { + parseDOM: [{ style: 'font-size: 48px;' }], + toDOM: () => ['span', { + style: 'font-size: 48px;' + }] + }, + + p72: { + parseDOM: [{ style: 'font-size: 72px;' }], + toDOM: () => ['span', { + style: 'font-size: 72px;' + }] + }, } // :: Schema diff --git a/src/client/util/TooltipTextMenu.scss b/src/client/util/TooltipTextMenu.scss index ea580d104..b23074239 100644 --- a/src/client/util/TooltipTextMenu.scss +++ b/src/client/util/TooltipTextMenu.scss @@ -1,5 +1,241 @@ @import "../views/global_variables"; +.ProseMirror-textblock-dropdown { + min-width: 3em; + } + + .ProseMirror-menu { + margin: 0 -4px; + line-height: 1; + } + + .ProseMirror-tooltip .ProseMirror-menu { + width: -webkit-fit-content; + width: fit-content; + white-space: pre; + } + + .ProseMirror-menuitem { + margin-right: 3px; + display: inline-block; + } + + .ProseMirror-menuseparator { + // border-right: 1px solid #ddd; + margin-right: 3px; + } + + .ProseMirror-menu-dropdown, .ProseMirror-menu-dropdown-menu { + font-size: 90%; + white-space: nowrap; + } + + .ProseMirror-menu-dropdown { + vertical-align: 1px; + cursor: pointer; + position: relative; + padding-right: 15px; + } + + .ProseMirror-menu-dropdown-wrap { + padding: 1px 0 1px 4px; + display: inline-block; + position: relative; + } + + .ProseMirror-menu-dropdown:after { + content: ""; + border-left: 4px solid transparent; + border-right: 4px solid transparent; + border-top: 4px solid currentColor; + opacity: .6; + position: absolute; + right: 4px; + top: calc(50% - 2px); + } + + .ProseMirror-menu-dropdown-menu, .ProseMirror-menu-submenu { + position: absolute; + background: $dark-color; + color:white; + border: 1px solid #aaa; + padding: 2px; + } + + .ProseMirror-menu-dropdown-menu { + z-index: 15; + min-width: 6em; + } + + .ProseMirror-menu-dropdown-item { + cursor: pointer; + padding: 2px 8px 2px 4px; + width: auto; + } + + .ProseMirror-menu-dropdown-item:hover { + background: #2e2b2b; + } + + .ProseMirror-menu-submenu-wrap { + position: relative; + margin-right: -4px; + } + + .ProseMirror-menu-submenu-label:after { + content: ""; + border-top: 4px solid transparent; + border-bottom: 4px solid transparent; + border-left: 4px solid currentColor; + opacity: .6; + position: absolute; + right: 4px; + top: calc(50% - 4px); + } + + .ProseMirror-menu-submenu { + display: none; + min-width: 4em; + left: 100%; + top: -3px; + } + + .ProseMirror-menu-active { + background: #eee; + border-radius: 4px; + } + + .ProseMirror-menu-active { + background: #eee; + border-radius: 4px; + } + + .ProseMirror-menu-disabled { + opacity: .3; + } + + .ProseMirror-menu-submenu-wrap:hover .ProseMirror-menu-submenu, .ProseMirror-menu-submenu-wrap-active .ProseMirror-menu-submenu { + display: block; + } + + .ProseMirror-menubar { + border-top-left-radius: inherit; + border-top-right-radius: inherit; + position: relative; + min-height: 1em; + color: white; + padding: 1px 6px; + top: 0; left: 0; right: 0; + border-bottom: 1px solid silver; + background:$dark-color; + z-index: 10; + -moz-box-sizing: border-box; + box-sizing: border-box; + overflow: visible; + } + + .ProseMirror-icon { + display: inline-block; + line-height: .8; + vertical-align: -2px; /* Compensate for padding */ + padding: 2px 8px; + cursor: pointer; + } + + .ProseMirror-menu-disabled.ProseMirror-icon { + cursor: default; + } + + .ProseMirror-icon svg { + fill: currentColor; + height: 1em; + } + + .ProseMirror-icon span { + vertical-align: text-top; + } +.ProseMirror-example-setup-style hr { + padding: 2px 10px; + border: none; + margin: 1em 0; + } + + .ProseMirror-example-setup-style hr:after { + content: ""; + display: block; + height: 1px; + background-color: silver; + line-height: 2px; + } + + .ProseMirror ul, .ProseMirror ol { + padding-left: 30px; + } + + .ProseMirror blockquote { + padding-left: 1em; + border-left: 3px solid #eee; + margin-left: 0; margin-right: 0; + } + + .ProseMirror-example-setup-style img { + cursor: default; + } + + .ProseMirror-prompt { + background: white; + padding: 5px 10px 5px 15px; + border: 1px solid silver; + position: fixed; + border-radius: 3px; + z-index: 11; + box-shadow: -.5px 2px 5px rgba(0, 0, 0, .2); + } + + .ProseMirror-prompt h5 { + margin: 0; + font-weight: normal; + font-size: 100%; + color: #444; + } + + .ProseMirror-prompt input[type="text"], + .ProseMirror-prompt textarea { + background: #eee; + border: none; + outline: none; + } + + .ProseMirror-prompt input[type="text"] { + padding: 0 4px; + } + + .ProseMirror-prompt-close { + position: absolute; + left: 2px; top: 1px; + color: #666; + border: none; background: transparent; padding: 0; + } + + .ProseMirror-prompt-close:after { + content: "✕"; + font-size: 12px; + } + + .ProseMirror-invalid { + background: #ffc; + border: 1px solid #cc7; + border-radius: 4px; + padding: 5px 10px; + position: absolute; + min-width: 10em; + } + + .ProseMirror-prompt-buttons { + margin-top: 5px; + display: none; + } + .tooltipMenu { position: absolute; z-index: 20; @@ -39,7 +275,7 @@ display: inline-block; border-right: 1px solid rgba(0, 0, 0, 0.2); //color: rgb(19, 18, 18); - color: $light-color; + color: white; line-height: 1; padding: 0px 2px; margin: 1px; diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx index 82e9d1bac..777abe030 100644 --- a/src/client/util/TooltipTextMenu.tsx +++ b/src/client/util/TooltipTextMenu.tsx @@ -1,12 +1,12 @@ import { action, IReactionDisposer, reaction } from "mobx"; -import { Dropdown, DropdownSubmenu, MenuItem } from "prosemirror-menu"; +import { Dropdown, DropdownSubmenu, MenuItem, MenuItemSpec, renderGrouped, icons, } from "prosemirror-menu"; //no import css import { baseKeymap, lift } from "prosemirror-commands"; import { history, redo, undo } from "prosemirror-history"; import { keymap } from "prosemirror-keymap"; -import { EditorState, Transaction, NodeSelection } from "prosemirror-state"; +import { EditorState, Transaction, NodeSelection, TextSelection } from "prosemirror-state"; import { EditorView } from "prosemirror-view"; import { schema } from "./RichTextSchema"; -import { Schema, NodeType } from "prosemirror-model"; +import { Schema, NodeType, MarkType } from "prosemirror-model"; import React = require("react"); import "./TooltipTextMenu.scss"; const { toggleMark, setBlockType, wrapIn } = require("prosemirror-commands"); @@ -24,8 +24,12 @@ export class TooltipTextMenu { private tooltip: HTMLElement; private num_icons = 0; + private view: EditorView; + private fontStyles: MarkType[]; + private fontSizes: MarkType[]; constructor(view: EditorView) { + this.view = view; this.tooltip = document.createElement("div"); this.tooltip.className = "tooltipMenu"; @@ -34,7 +38,6 @@ export class TooltipTextMenu { //add additional icons library.add(faListUl); - //add the buttons to the tooltip let items = [ { command: toggleMark(schema.marks.strong), dom: this.icon("B", "strong") }, @@ -44,44 +47,142 @@ export class TooltipTextMenu { { command: toggleMark(schema.marks.superscript), dom: this.icon("s", "superscript") }, { command: toggleMark(schema.marks.subscript), dom: this.icon("s", "subscript") }, { command: wrapInList(schema.nodes.bullet_list), dom: this.icon(":", "bullets") }, - { command: toggleMark(schema.marks.timesNewRoman), dom: this.icon("x", "TNR") }, { command: lift, dom: this.icon("<", "lift") }, ] //add menu items items.forEach(({ dom, command }) => { this.tooltip.appendChild(dom); - }); - //add dropdowns - - //pointer down handler to activate button effects - this.tooltip.addEventListener("pointerdown", e => { - e.preventDefault(); - view.focus(); - //update view of icons - this.num_icons = 0; - items.forEach(({ command, dom }) => { - if (e.srcElement && dom.contains(e.srcElement as Node)) { - //let active = command(view.state, view.dispatch, view); - let active = command(view.state, view.dispatch, view); - //uncomment this if we want the bullet button to disappear if current selection is bulleted - //dom.style.display = active ? "" : "none"; - } + //pointer down handler to activate button effects + dom.addEventListener("pointerdown", e => { + e.preventDefault(); + view.focus(); + command(view.state, view.dispatch, view); }) - }) + + }); + + //dropdowns + //list of font btns to add + this.fontStyles = [ + schema.marks.timesNewRoman, + schema.marks.arial, + schema.marks.georgia, + schema.marks.comicSans, + schema.marks.tahoma, + schema.marks.impact, + ] + this.fontSizes = [ + schema.marks.p10, + schema.marks.p12, + schema.marks.p16, + schema.marks.p24, + schema.marks.p32, + schema.marks.p48, + schema.marks.p72, + ] + this.addFontDropdowns(); this.update(view, undefined); } + //adds font size and font style dropdowns + addFontDropdowns() { + //filtering function - might be unecessary + let cut = (arr: MenuItem[]) => arr.filter(x => x); + let fontBtns = [ + this.dropdownBtn("Times New Roman", "font-family: Times New Roman, Times, serif; width: 120px;", schema.marks.timesNewRoman, this.view, this.changeToMarkInGroup, this.fontStyles), + this.dropdownBtn("Arial", "font-family: Arial, Helvetica, sans-serif; width: 120px;", schema.marks.arial, this.view, this.changeToMarkInGroup, this.fontStyles), + this.dropdownBtn("Georgia", "font-family: Georgia, serif; width: 120px; width: 120px;", schema.marks.georgia, this.view, this.changeToMarkInGroup, this.fontStyles), + this.dropdownBtn("ComicSans", "font-family: Comic Sans MS, cursive, sans-serif; width: 120px;", schema.marks.comicSans, this.view, this.changeToMarkInGroup, this.fontStyles), + this.dropdownBtn("Tahoma", "font-family: Tahoma, Geneva, sans-serif; width: 120px;", schema.marks.tahoma, this.view, this.changeToMarkInGroup, this.fontStyles), + this.dropdownBtn("Impact", "font-family: Impact, Charcoal, sans-serif; width: 120px;", schema.marks.impact, this.view, this.changeToMarkInGroup, this.fontStyles), + ] + + let fontSizeBtns = [ + this.dropdownBtn("10", "width: 50px;", schema.marks.p10, this.view, this.changeToMarkInGroup, this.fontSizes), + this.dropdownBtn("12", "width: 50px;", schema.marks.p12, this.view, this.changeToMarkInGroup, this.fontSizes), + this.dropdownBtn("16", "width: 50px;", schema.marks.p16, this.view, this.changeToMarkInGroup, this.fontSizes), + this.dropdownBtn("24", "width: 50px;", schema.marks.p24, this.view, this.changeToMarkInGroup, this.fontSizes), + this.dropdownBtn("32", "width: 50px;", schema.marks.p32, this.view, this.changeToMarkInGroup, this.fontSizes), + this.dropdownBtn("48", "width: 50px;", schema.marks.p48, this.view, this.changeToMarkInGroup, this.fontSizes), + this.dropdownBtn("72", "width: 50px;", schema.marks.p72, this.view, this.changeToMarkInGroup, this.fontSizes), + ] + + //dropdown to hold font btns + let dd_fontStyle = new Dropdown(cut(fontBtns), { label: "Font Style", css: "color:white;" }) as MenuItem; + let dd_fontSize = new Dropdown(cut(fontSizeBtns), { label: "Font Size", css: "color:white;" }) as MenuItem; + this.tooltip.appendChild(dd_fontStyle.render(this.view).dom); + this.tooltip.appendChild(dd_fontSize.render(this.view).dom); + } + + //for a specific grouping of marks (passed in), remove all and apply the passed-in one to the selected text + changeToMarkInGroup(markType: MarkType, view: EditorView, fontMarks: MarkType[]) { + let { empty, $cursor, ranges } = view.state.selection as TextSelection; + let state = view.state; + let dispatch = view.dispatch; + + //remove all other active font marks + fontMarks.forEach((type) => { + if (dispatch) { + if ($cursor) { + if (type.isInSet(state.storedMarks || $cursor.marks())) { + dispatch(state.tr.removeStoredMark(type)); + } + } else { + let has = false, tr = state.tr + for (let i = 0; !has && i < ranges.length; i++) { + let { $from, $to } = ranges[i] + has = state.doc.rangeHasMark($from.pos, $to.pos, type) + } + for (let i = 0; i < ranges.length; i++) { + let { $from, $to } = ranges[i] + if (has) { + toggleMark(type)(view.state, view.dispatch, view); + } + } + } + } + }); //actually apply font + return toggleMark(markType)(view.state, view.dispatch, view); + } + + //makes a button for the drop down + //css is the style you want applied to the button + dropdownBtn(label: string, css: string, markType: MarkType, view: EditorView, changeToMarkInGroup: (markType: MarkType, view: EditorView, groupMarks: MarkType[]) => any, groupMarks: MarkType[]) { + return new MenuItem({ + title: "", + label: label, + execEvent: "", + class: "menuicon", + css: css, + enable(state) { return true; }, + run() { + changeToMarkInGroup(markType, view, groupMarks); + } + }); + } // Helper function to create menu icons icon(text: string, name: string) { let span = document.createElement("span"); span.className = "menuicon " + name; span.title = name; span.textContent = text; + span.style.color = "white"; return span; } + //method for checking whether node can be inserted + canInsert(state: EditorState, nodeType: NodeType>) { + let $from = state.selection.$from + for (let d = $from.depth; d >= 0; d--) { + let index = $from.index(d) + if ($from.node(d).canReplaceWith(index, index, nodeType)) return true + } + return false + } + + //adapted this method - use it to check if block has a tag (ie bulleting) blockActive(type: NodeType>, state: EditorState) { let attrs = {}; @@ -100,30 +201,6 @@ export class TooltipTextMenu { } } - //this doesn't currently work but could be used to use icons for buttons - unorderedListIcon(): HTMLSpanElement { - let span = document.createElement("span"); - //let icon = document.createElement("FontAwesomeIcon"); - //icon.className = "menuicon"; - //icon.style.color = "white"; - //span.appendChild(); - let i = document.createElement("i"); - i.className = "fa falist-ul"; - span.appendChild(i); - //span.appendChild(icon); - //return liftItem.spec.icon.sty - - //let sym = document.createElementNS(SVG, "symbol") - // sym.id = name - //sym.style.color = "white"; - //width then height - //sym.setAttribute("viewBox", "0 0 " + 1024 + " " + 1024); - //let path = sym.appendChild(document.createElementNS(SVG, "path")); - //path.setAttribute("d", "M219 310v329q0 7-5 12t-12 5q-8 0-13-5l-164-164q-5-5-5-13t5-13l164-164q5-5 13-5 7 0 12 5t5 12zM1024 749v109q0 7-5 12t-12 5h-987q-7 0-12-5t-5-12v-109q0-7 5-12t12-5h987q7 0 12 5t5 12zM1024 530v109q0 7-5 12t-12 5h-621q-7 0-12-5t-5-12v-109q0-7 5-12t12-5h621q7 0 12 5t5 12zM1024 310v109q0 7-5 12t-12 5h-621q-7 0-12-5t-5-12v-109q0-7 5-12t12-5h621q7 0 12 5t5 12zM1024 91v109q0 7-5 12t-12 5h-987q-7 0-12-5t-5-12v-109q0-7 5-12t12-5h987q7 0 12 5t5 12z"); - //span.appendChild(sym); - return span; - } - // Create an icon for a heading at the given level heading(level: number) { return { @@ -156,10 +233,8 @@ export class TooltipTextMenu { let left = Math.max((start.left + end.left) / 2, start.left + 3) this.tooltip.style.left = (left - box.left) + "px" //let width = Math.abs(start.left - end.left) / 2; - let width = 8 * 16 + 15; + let width = 220; let mid = Math.min(start.left, end.left) + width; - - //THIS WIDTH IS 15 * NUMBER OF ICONS + 15 this.tooltip.style.width = width + "px"; this.tooltip.style.bottom = (box.bottom - start.top) + "px"; } diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index e59179874..fdb1b97be 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -74,7 +74,12 @@ export class FormattedTextBox extends React.Component { history(), keymap({ "Mod-z": undo, "Mod-y": redo }), keymap(baseKeymap), - this.tooltipMenuPlugin() + this.tooltipMenuPlugin(), + new Plugin({ + props: { + attributes: { class: "ProseMirror-example-setup-style" } + } + }) ] }; -- cgit v1.2.3-70-g09d2 From e981d9d228507fc573febc997eb691a5428126e8 Mon Sep 17 00:00:00 2001 From: laurawilsonri Date: Mon, 15 Apr 2019 17:40:38 -0400 Subject: fixed small pointer event bug with tooltip menu --- src/.DS_Store | Bin 6148 -> 6148 bytes src/client/util/TooltipTextMenu.scss | 3 ++- src/client/util/TooltipTextMenu.tsx | 2 +- src/client/views/nodes/FormattedTextBox.tsx | 1 - 4 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src/client/util/TooltipTextMenu.tsx') diff --git a/src/.DS_Store b/src/.DS_Store index 90213270f..d70e95c0a 100644 Binary files a/src/.DS_Store and b/src/.DS_Store differ diff --git a/src/client/util/TooltipTextMenu.scss b/src/client/util/TooltipTextMenu.scss index 8fddbd3cf..a9a98c426 100644 --- a/src/client/util/TooltipTextMenu.scss +++ b/src/client/util/TooltipTextMenu.scss @@ -58,7 +58,7 @@ position: absolute; background: $dark-color; color:white; - border: 1px solid #aaa; + border: 1px solid rgb(223, 223, 223); padding: 2px; } @@ -246,6 +246,7 @@ margin-bottom: 7px; -webkit-transform: translateX(-50%); transform: translateX(-50%); + pointer-events: all; } .tooltipMenu:before { diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx index 3869db41a..a28a8eaeb 100644 --- a/src/client/util/TooltipTextMenu.tsx +++ b/src/client/util/TooltipTextMenu.tsx @@ -38,7 +38,7 @@ export class TooltipTextMenu { this.tooltip.className = "tooltipMenu"; //add the div which is the tooltip - view.dom.parentNode!.appendChild(this.tooltip); + view.dom.parentNode!.parentNode!.appendChild(this.tooltip); //add additional icons library.add(faListUl); diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 19ed65272..be530416e 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -249,7 +249,6 @@ export class FormattedTextBox extends React.Component<(FieldViewProps & Formatte return (
Date: Mon, 15 Apr 2019 20:07:37 -0400 Subject: added a font size indicator --- src/client/util/RichTextSchema.tsx | 7 ++ src/client/util/TooltipTextMenu.scss | 6 +- src/client/util/TooltipTextMenu.tsx | 126 +++++++++++++++++++--------- src/client/views/nodes/FormattedTextBox.tsx | 1 - 4 files changed, 100 insertions(+), 40 deletions(-) (limited to 'src/client/util/TooltipTextMenu.tsx') diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx index 42bcf2ae2..9ef71e305 100644 --- a/src/client/util/RichTextSchema.tsx +++ b/src/client/util/RichTextSchema.tsx @@ -267,6 +267,13 @@ export const marks: { [index: string]: MarkSpec } = { }] }, + crimson: { + parseDOM: [{ style: 'font-family: "Crimson Text", sans-serif;' }], + toDOM: () => ['span', { + style: 'font-family: "Crimson Text", sans-serif;' + }] + }, + /** FONT SIZES */ p10: { diff --git a/src/client/util/TooltipTextMenu.scss b/src/client/util/TooltipTextMenu.scss index a9a98c426..7e6659a52 100644 --- a/src/client/util/TooltipTextMenu.scss +++ b/src/client/util/TooltipTextMenu.scss @@ -289,4 +289,8 @@ .underline {text-decoration: underline} .superscript {vertical-align:super} .subscript { vertical-align:sub } - .strikethrough {text-decoration-line:line-through} \ No newline at end of file + .strikethrough {text-decoration-line:line-through} + .font-size-indicator { + font-size: 12px; + padding-right: 0px; + } diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx index a28a8eaeb..a92cbd263 100644 --- a/src/client/util/TooltipTextMenu.tsx +++ b/src/client/util/TooltipTextMenu.tsx @@ -30,9 +30,14 @@ export class TooltipTextMenu { private fontStyles: MarkType[]; private fontSizes: MarkType[]; private editorProps: FieldViewProps; + private state: EditorState; + private fontSizeToNum: Map; + private fontStylesToName: Map; + private fontSizeIndicator: HTMLSpanElement = document.createElement("span"); constructor(view: EditorView, editorProps: FieldViewProps) { this.view = view; + this.state = view.state; this.editorProps = editorProps; this.tooltip = document.createElement("div"); this.tooltip.className = "tooltipMenu"; @@ -66,25 +71,28 @@ export class TooltipTextMenu { }); - //dropdowns - //list of font btns to add - this.fontStyles = [ - schema.marks.timesNewRoman, - schema.marks.arial, - schema.marks.georgia, - schema.marks.comicSans, - schema.marks.tahoma, - schema.marks.impact, - ]; - this.fontSizes = [ - schema.marks.p10, - schema.marks.p12, - schema.marks.p16, - schema.marks.p24, - schema.marks.p32, - schema.marks.p48, - schema.marks.p72, - ]; + //list of font styles + this.fontStylesToName = new Map(); + this.fontStylesToName.set(schema.marks.timesNewRoman, "Times New Roman"); + this.fontStylesToName.set(schema.marks.arial, "Arial"); + this.fontStylesToName.set(schema.marks.georgia, "Georgia"); + this.fontStylesToName.set(schema.marks.comicSans, "Comic Sans"); + this.fontStylesToName.set(schema.marks.tahoma, "Tahoma"); + this.fontStylesToName.set(schema.marks.impact, "Impact"); + this.fontStylesToName.set(schema.marks.crimson, "Crimson Text"); + this.fontStyles = Array.from(this.fontStylesToName.keys()); + + //font sizes + this.fontSizeToNum = new Map(); + this.fontSizeToNum.set(schema.marks.p10, 10); + this.fontSizeToNum.set(schema.marks.p12, 12); + this.fontSizeToNum.set(schema.marks.p16, 16); + this.fontSizeToNum.set(schema.marks.p24, 24); + this.fontSizeToNum.set(schema.marks.p32, 32); + this.fontSizeToNum.set(schema.marks.p48, 48); + this.fontSizeToNum.set(schema.marks.p72, 72); + this.fontSizes = Array.from(this.fontSizeToNum.keys()); + this.addFontDropdowns(); this.update(view, undefined); @@ -94,30 +102,29 @@ export class TooltipTextMenu { addFontDropdowns() { //filtering function - might be unecessary let cut = (arr: MenuItem[]) => arr.filter(x => x); - let fontBtns = [ - this.dropdownBtn("Times New Roman", "font-family: Times New Roman, Times, serif; width: 120px;", schema.marks.timesNewRoman, this.view, this.changeToMarkInGroup, this.fontStyles), - this.dropdownBtn("Arial", "font-family: Arial, Helvetica, sans-serif; width: 120px;", schema.marks.arial, this.view, this.changeToMarkInGroup, this.fontStyles), - this.dropdownBtn("Georgia", "font-family: Georgia, serif; width: 120px; width: 120px;", schema.marks.georgia, this.view, this.changeToMarkInGroup, this.fontStyles), - this.dropdownBtn("ComicSans", "font-family: Comic Sans MS, cursive, sans-serif; width: 120px;", schema.marks.comicSans, this.view, this.changeToMarkInGroup, this.fontStyles), - this.dropdownBtn("Tahoma", "font-family: Tahoma, Geneva, sans-serif; width: 120px;", schema.marks.tahoma, this.view, this.changeToMarkInGroup, this.fontStyles), - this.dropdownBtn("Impact", "font-family: Impact, Charcoal, sans-serif; width: 120px;", schema.marks.impact, this.view, this.changeToMarkInGroup, this.fontStyles), - ]; + //font STYLES + let fontBtns: MenuItem[] = []; + this.fontStylesToName.forEach((name, mark) => { + fontBtns.push(this.dropdownBtn(name, "font-family: " + name + ", sans-serif; width: 120px;", mark, this.view, this.changeToMarkInGroup, this.fontStyles)); + }); - let fontSizeBtns = [ - this.dropdownBtn("10", "width: 50px;", schema.marks.p10, this.view, this.changeToMarkInGroup, this.fontSizes), - this.dropdownBtn("12", "width: 50px;", schema.marks.p12, this.view, this.changeToMarkInGroup, this.fontSizes), - this.dropdownBtn("16", "width: 50px;", schema.marks.p16, this.view, this.changeToMarkInGroup, this.fontSizes), - this.dropdownBtn("24", "width: 50px;", schema.marks.p24, this.view, this.changeToMarkInGroup, this.fontSizes), - this.dropdownBtn("32", "width: 50px;", schema.marks.p32, this.view, this.changeToMarkInGroup, this.fontSizes), - this.dropdownBtn("48", "width: 50px;", schema.marks.p48, this.view, this.changeToMarkInGroup, this.fontSizes), - this.dropdownBtn("72", "width: 50px;", schema.marks.p72, this.view, this.changeToMarkInGroup, this.fontSizes), - ]; + //font size indicator + this.fontSizeIndicator = this.icon("12", "font-size-indicator"); + + //font SIZES + let fontSizeBtns: MenuItem[] = []; + this.fontSizeToNum.forEach((number, mark) => { + fontSizeBtns.push(this.dropdownBtn(String(number), "width: 50px;", mark, this.view, this.changeToMarkInGroup, this.fontSizes)); + }); //dropdown to hold font btns let dd_fontStyle = new Dropdown(cut(fontBtns), { label: "Font Style", css: "color:white;" }) as MenuItem; - let dd_fontSize = new Dropdown(cut(fontSizeBtns), { label: "Font Size", css: "color:white;" }) as MenuItem; + let dd_fontSize = new Dropdown(cut(fontSizeBtns), { label: "Font Size", css: "color:white; margin-left: -6px;" }) as MenuItem; this.tooltip.appendChild(dd_fontStyle.render(this.view).dom); + this.tooltip.appendChild(this.fontSizeIndicator); this.tooltip.appendChild(dd_fontSize.render(this.view).dom); + dd_fontStyle.render(this.view).dom.nodeValue = "TEST"; + console.log(dd_fontStyle.render(this.view).dom.nodeValue); } //for a specific grouping of marks (passed in), remove all and apply the passed-in one to the selected text @@ -169,7 +176,7 @@ export class TooltipTextMenu { // Helper function to create menu icons icon(text: string, name: string) { let span = document.createElement("span"); - span.className = "menuicon " + name; + span.className = name + " menuicon"; span.title = name; span.textContent = text; span.style.color = "white"; @@ -241,6 +248,49 @@ export class TooltipTextMenu { this.tooltip.style.width = 220 + "px"; this.tooltip.style.bottom = (box.bottom - start.top) * this.editorProps.ScreenToLocalTransform().Scale + "px"; + + let activeStyles = this.activeMarksOnSelection(this.fontStyles); + if (activeStyles.length === 1) { + // if we want to update something somewhere with active font name + let fontName = this.fontStylesToName.get(activeStyles[0]); + } else if (activeStyles.length === 0) { + //crimson on default + } + + //update font size indicator + let activeSizes = this.activeMarksOnSelection(this.fontSizes); + if (activeSizes.length === 1) { //if there's only one active font size + let size = this.fontSizeToNum.get(activeSizes[0]); + if (size) { + this.fontSizeIndicator.innerHTML = String(size); + } + //should be 14 on default + } else if (activeSizes.length === 0) { + this.fontSizeIndicator.innerHTML = "14"; + //multiple font sizes selected + } else { + this.fontSizeIndicator.innerHTML = ""; + } + } + + //finds all active marks on selection + activeMarksOnSelection(markGroup: MarkType[]) { + //current selection + let { empty, $cursor, ranges } = this.view.state.selection as TextSelection; + let state = this.view.state; + let dispatch = this.view.dispatch; + + let activeMarks = markGroup.filter(mark => { + if (dispatch) { + let has = false, tr = state.tr; + for (let i = 0; !has && i < ranges.length; i++) { + let { $from, $to } = ranges[i]; + return state.doc.rangeHasMark($from.pos, $to.pos, mark); + } + } + return false; + }); + return activeMarks; } destroy() { this.tooltip.remove(); } diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index be530416e..631139d32 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -177,7 +177,6 @@ export class FormattedTextBox extends React.Component<(FieldViewProps & Formatte // doc.SetData(fieldKey, e.target.value, RichTextField); } onPointerDown = (e: React.PointerEvent): void => { - console.log("pointer down"); if (e.button === 1 && this.props.isSelected() && !e.altKey && !e.ctrlKey && !e.metaKey) { console.log("first"); e.stopPropagation(); -- cgit v1.2.3-70-g09d2 From 3808258fe452be2f71354989c0281dc4549f408b Mon Sep 17 00:00:00 2001 From: laurawilsonri Date: Tue, 16 Apr 2019 18:23:49 -0400 Subject: font dropdowns update now, ui change and bug fix --- src/client/util/TooltipTextMenu.scss | 4 ++ src/client/util/TooltipTextMenu.tsx | 75 +++++++++++++++++++++--------------- 2 files changed, 49 insertions(+), 30 deletions(-) (limited to 'src/client/util/TooltipTextMenu.tsx') diff --git a/src/client/util/TooltipTextMenu.scss b/src/client/util/TooltipTextMenu.scss index 5c2d66480..70d9ad772 100644 --- a/src/client/util/TooltipTextMenu.scss +++ b/src/client/util/TooltipTextMenu.scss @@ -35,6 +35,10 @@ cursor: pointer; position: relative; padding-right: 15px; + margin: 3px; + background: #333333; + border-radius: 3px; + text-align: center; } .ProseMirror-menu-dropdown-wrap { diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx index a92cbd263..4f0eb7d63 100644 --- a/src/client/util/TooltipTextMenu.tsx +++ b/src/client/util/TooltipTextMenu.tsx @@ -34,6 +34,9 @@ export class TooltipTextMenu { private fontSizeToNum: Map; private fontStylesToName: Map; private fontSizeIndicator: HTMLSpanElement = document.createElement("span"); + //dropdown doms + private fontSizeDom: Node; + private fontStyleDom: Node; constructor(view: EditorView, editorProps: FieldViewProps) { this.view = view; @@ -76,7 +79,7 @@ export class TooltipTextMenu { this.fontStylesToName.set(schema.marks.timesNewRoman, "Times New Roman"); this.fontStylesToName.set(schema.marks.arial, "Arial"); this.fontStylesToName.set(schema.marks.georgia, "Georgia"); - this.fontStylesToName.set(schema.marks.comicSans, "Comic Sans"); + this.fontStylesToName.set(schema.marks.comicSans, "Comic Sans MS"); this.fontStylesToName.set(schema.marks.tahoma, "Tahoma"); this.fontStylesToName.set(schema.marks.impact, "Impact"); this.fontStylesToName.set(schema.marks.crimson, "Crimson Text"); @@ -93,23 +96,15 @@ export class TooltipTextMenu { this.fontSizeToNum.set(schema.marks.p72, 72); this.fontSizes = Array.from(this.fontSizeToNum.keys()); - this.addFontDropdowns(); + //this.addFontDropdowns(); this.update(view, undefined); } - //adds font size and font style dropdowns - addFontDropdowns() { + //label of dropdown will change to given label + updateFontSizeDropdown(label: string) { //filtering function - might be unecessary let cut = (arr: MenuItem[]) => arr.filter(x => x); - //font STYLES - let fontBtns: MenuItem[] = []; - this.fontStylesToName.forEach((name, mark) => { - fontBtns.push(this.dropdownBtn(name, "font-family: " + name + ", sans-serif; width: 120px;", mark, this.view, this.changeToMarkInGroup, this.fontStyles)); - }); - - //font size indicator - this.fontSizeIndicator = this.icon("12", "font-size-indicator"); //font SIZES let fontSizeBtns: MenuItem[] = []; @@ -117,14 +112,32 @@ export class TooltipTextMenu { fontSizeBtns.push(this.dropdownBtn(String(number), "width: 50px;", mark, this.view, this.changeToMarkInGroup, this.fontSizes)); }); - //dropdown to hold font btns - let dd_fontStyle = new Dropdown(cut(fontBtns), { label: "Font Style", css: "color:white;" }) as MenuItem; - let dd_fontSize = new Dropdown(cut(fontSizeBtns), { label: "Font Size", css: "color:white; margin-left: -6px;" }) as MenuItem; - this.tooltip.appendChild(dd_fontStyle.render(this.view).dom); - this.tooltip.appendChild(this.fontSizeIndicator); - this.tooltip.appendChild(dd_fontSize.render(this.view).dom); - dd_fontStyle.render(this.view).dom.nodeValue = "TEST"; - console.log(dd_fontStyle.render(this.view).dom.nodeValue); + if (this.fontSizeDom) { this.tooltip.removeChild(this.fontSizeDom); } + this.fontSizeDom = (new Dropdown(cut(fontSizeBtns), { + label: label, + css: "color:white; min-width: 60px; padding-left: 5px; margin-right: 0;" + }) as MenuItem).render(this.view).dom; + this.tooltip.appendChild(this.fontSizeDom); + } + + //label of dropdown will change to given label + updateFontStyleDropdown(label: string) { + //filtering function - might be unecessary + let cut = (arr: MenuItem[]) => arr.filter(x => x); + + //font STYLES + let fontBtns: MenuItem[] = []; + this.fontStylesToName.forEach((name, mark) => { + fontBtns.push(this.dropdownBtn(name, "font-family: " + name + ", sans-serif; width: 125px;", mark, this.view, this.changeToMarkInGroup, this.fontStyles)); + }); + + if (this.fontStyleDom) { this.tooltip.removeChild(this.fontStyleDom); } + this.fontStyleDom = (new Dropdown(cut(fontBtns), { + label: label, + css: "color:white; width: 125px; margin-left: -3px; padding-left: 2px;" + }) as MenuItem).render(this.view).dom; + + this.tooltip.appendChild(this.fontStyleDom); } //for a specific grouping of marks (passed in), remove all and apply the passed-in one to the selected text @@ -246,30 +259,32 @@ export class TooltipTextMenu { let width = Math.abs(start.left - end.left) / 2 * this.editorProps.ScreenToLocalTransform().Scale; let mid = Math.min(start.left, end.left) + width; - this.tooltip.style.width = 220 + "px"; + this.tooltip.style.width = 225 + "px"; this.tooltip.style.bottom = (box.bottom - start.top) * this.editorProps.ScreenToLocalTransform().Scale + "px"; + //UPDATE FONT STYLE DROPDOWN let activeStyles = this.activeMarksOnSelection(this.fontStyles); if (activeStyles.length === 1) { // if we want to update something somewhere with active font name let fontName = this.fontStylesToName.get(activeStyles[0]); + if (fontName) { this.updateFontStyleDropdown(fontName); } } else if (activeStyles.length === 0) { //crimson on default + this.updateFontStyleDropdown("Crimson Text"); + } else { + this.updateFontStyleDropdown("Various"); } - //update font size indicator + //UPDATE FONT SIZE DROPDOWN let activeSizes = this.activeMarksOnSelection(this.fontSizes); if (activeSizes.length === 1) { //if there's only one active font size let size = this.fontSizeToNum.get(activeSizes[0]); - if (size) { - this.fontSizeIndicator.innerHTML = String(size); - } - //should be 14 on default + if (size) { this.updateFontSizeDropdown(String(size) + " pt"); } } else if (activeSizes.length === 0) { - this.fontSizeIndicator.innerHTML = "14"; - //multiple font sizes selected - } else { - this.fontSizeIndicator.innerHTML = ""; + //should be 14 on default + this.updateFontSizeDropdown("14 pt"); + } else { //multiple font sizes selected + this.updateFontSizeDropdown("Various"); } } -- cgit v1.2.3-70-g09d2 From b9b7409af655a0b936ec884de62b8a243be1011b Mon Sep 17 00:00:00 2001 From: laurawilsonri Date: Mon, 22 Apr 2019 22:13:10 -0400 Subject: added a dropdown for bullet types --- src/client/util/TooltipTextMenu.tsx | 79 ++++++++++++++++++++++++++++++++----- 1 file changed, 70 insertions(+), 9 deletions(-) (limited to 'src/client/util/TooltipTextMenu.tsx') diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx index 4f0eb7d63..95e7ba2bf 100644 --- a/src/client/util/TooltipTextMenu.tsx +++ b/src/client/util/TooltipTextMenu.tsx @@ -11,7 +11,8 @@ import React = require("react"); import "./TooltipTextMenu.scss"; const { toggleMark, setBlockType, wrapIn } = require("prosemirror-commands"); import { library } from '@fortawesome/fontawesome-svg-core'; -import { wrapInList, bulletList, liftListItem, listItem } from 'prosemirror-schema-list'; +import { wrapInList, bulletList, liftListItem, listItem, } from 'prosemirror-schema-list'; +import { liftTarget } from 'prosemirror-transform'; import { faListUl, } from '@fortawesome/free-solid-svg-icons'; @@ -29,14 +30,17 @@ export class TooltipTextMenu { private view: EditorView; private fontStyles: MarkType[]; private fontSizes: MarkType[]; + private listTypes: NodeType[]; private editorProps: FieldViewProps; private state: EditorState; private fontSizeToNum: Map; private fontStylesToName: Map; + private listTypeToIcon: Map; private fontSizeIndicator: HTMLSpanElement = document.createElement("span"); //dropdown doms private fontSizeDom: Node; private fontStyleDom: Node; + private listTypeBtnDom: Node; constructor(view: EditorView, editorProps: FieldViewProps) { this.view = view; @@ -58,8 +62,9 @@ export class TooltipTextMenu { { command: toggleMark(schema.marks.strikethrough), dom: this.icon("S", "strikethrough") }, { command: toggleMark(schema.marks.superscript), dom: this.icon("s", "superscript") }, { command: toggleMark(schema.marks.subscript), dom: this.icon("s", "subscript") }, - { command: wrapInList(schema.nodes.bullet_list), dom: this.icon(":", "bullets") }, - { command: lift, dom: this.icon("<", "lift") }, + // { command: wrapInList(schema.nodes.bullet_list), dom: this.icon(":", "bullets") }, + // { command: wrapInList(schema.nodes.ordered_list), dom: this.icon("1)", "bullets") }, + // { command: lift, dom: this.icon("<", "lift") }, ]; //add menu items items.forEach(({ dom, command }) => { @@ -96,7 +101,11 @@ export class TooltipTextMenu { this.fontSizeToNum.set(schema.marks.p72, 72); this.fontSizes = Array.from(this.fontSizeToNum.keys()); - //this.addFontDropdowns(); + //list types + this.listTypeToIcon = new Map(); + this.listTypeToIcon.set(schema.nodes.bullet_list, ":"); + this.listTypeToIcon.set(schema.nodes.ordered_list, "1)"); + this.listTypes = Array.from(this.listTypeToIcon.keys()); this.update(view, undefined); } @@ -109,7 +118,7 @@ export class TooltipTextMenu { //font SIZES let fontSizeBtns: MenuItem[] = []; this.fontSizeToNum.forEach((number, mark) => { - fontSizeBtns.push(this.dropdownBtn(String(number), "width: 50px;", mark, this.view, this.changeToMarkInGroup, this.fontSizes)); + fontSizeBtns.push(this.dropdownMarkBtn(String(number), "width: 50px;", mark, this.view, this.changeToMarkInGroup, this.fontSizes)); }); if (this.fontSizeDom) { this.tooltip.removeChild(this.fontSizeDom); } @@ -128,7 +137,7 @@ export class TooltipTextMenu { //font STYLES let fontBtns: MenuItem[] = []; this.fontStylesToName.forEach((name, mark) => { - fontBtns.push(this.dropdownBtn(name, "font-family: " + name + ", sans-serif; width: 125px;", mark, this.view, this.changeToMarkInGroup, this.fontStyles)); + fontBtns.push(this.dropdownMarkBtn(name, "font-family: " + name + ", sans-serif; width: 125px;", mark, this.view, this.changeToMarkInGroup, this.fontStyles)); }); if (this.fontStyleDom) { this.tooltip.removeChild(this.fontStyleDom); } @@ -140,6 +149,29 @@ export class TooltipTextMenu { this.tooltip.appendChild(this.fontStyleDom); } + //will display a remove-list-type button if selection is in list, otherwise will show list type dropdown + updateListItemDropdown(label: string, listTypeBtn: Node) { + //remove old btn + if (listTypeBtn) { this.tooltip.removeChild(listTypeBtn); } + + //Make a dropdown of all list types + let toAdd: MenuItem[] = []; + this.listTypeToIcon.forEach((icon, type) => { + toAdd.push(this.dropdownNodeBtn(icon, "width: 40px;", type, this.view, this.listTypes, this.changeToNodeType)); + }); + //option to remove the list formatting + toAdd.push(this.dropdownNodeBtn("X", "width: 40px;", undefined, this.view, this.listTypes, this.changeToNodeType)); + + listTypeBtn = (new Dropdown(toAdd, { + label: label, + css: "color:white; width: 40px;" + }) as MenuItem).render(this.view).dom; + + //add this new button and return it + this.tooltip.appendChild(listTypeBtn); + return listTypeBtn; + } + //for a specific grouping of marks (passed in), remove all and apply the passed-in one to the selected text changeToMarkInGroup(markType: MarkType, view: EditorView, fontMarks: MarkType[]) { let { empty, $cursor, ranges } = view.state.selection as TextSelection; @@ -171,9 +203,18 @@ export class TooltipTextMenu { return toggleMark(markType)(view.state, view.dispatch, view); } - //makes a button for the drop down + //remove all node typeand apply the passed-in one to the selected text + changeToNodeType(nodeType: NodeType | undefined, view: EditorView, allNodes: NodeType[]) { + //remove old + liftListItem(schema.nodes.list_item)(view.state, view.dispatch); + if (nodeType) { //add new + wrapInList(nodeType)(view.state, view.dispatch); + } + } + + //makes a button for the drop down FOR MARKS //css is the style you want applied to the button - dropdownBtn(label: string, css: string, markType: MarkType, view: EditorView, changeToMarkInGroup: (markType: MarkType, view: EditorView, groupMarks: MarkType[]) => any, groupMarks: MarkType[]) { + dropdownMarkBtn(label: string, css: string, markType: MarkType, view: EditorView, changeToMarkInGroup: (markType: MarkType, view: EditorView, groupMarks: MarkType[]) => any, groupMarks: MarkType[]) { return new MenuItem({ title: "", label: label, @@ -186,6 +227,23 @@ export class TooltipTextMenu { } }); } + + //makes a button for the drop down FOR NODE TYPES + //css is the style you want applied to the button + dropdownNodeBtn(label: string, css: string, nodeType: NodeType | undefined, view: EditorView, groupNodes: NodeType[], changeToNodeInGroup: (nodeType: NodeType | undefined, view: EditorView, groupNodes: NodeType[]) => any) { + return new MenuItem({ + title: "", + label: label, + execEvent: "", + class: "menuicon", + css: css, + enable(state) { return true; }, + run() { + changeToNodeInGroup(nodeType, view, groupNodes); + } + }); + } + // Helper function to create menu icons icon(text: string, name: string) { let span = document.createElement("span"); @@ -262,6 +320,9 @@ export class TooltipTextMenu { this.tooltip.style.width = 225 + "px"; this.tooltip.style.bottom = (box.bottom - start.top) * this.editorProps.ScreenToLocalTransform().Scale + "px"; + //UPDATE LIST ITEM DROPDOWN + this.listTypeBtnDom = this.updateListItemDropdown(":", this.listTypeBtnDom); + //UPDATE FONT STYLE DROPDOWN let activeStyles = this.activeMarksOnSelection(this.fontStyles); if (activeStyles.length === 1) { @@ -288,7 +349,7 @@ export class TooltipTextMenu { } } - //finds all active marks on selection + //finds all active marks on selection in given group activeMarksOnSelection(markGroup: MarkType[]) { //current selection let { empty, $cursor, ranges } = this.view.state.selection as TextSelection; -- cgit v1.2.3-70-g09d2 From 513e9042ea815e964462e824d85fbd229381250f Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Sat, 27 Apr 2019 01:19:52 -0400 Subject: A bunch more stuff --- src/client/DocServer.ts | 6 +- .../northstar/core/brusher/IBaseBrushable.ts | 4 +- src/client/northstar/core/filter/FilterModel.ts | 17 ++- .../northstar/core/filter/IBaseFilterConsumer.ts | 4 +- src/client/northstar/dash-fields/HistogramField.ts | 3 +- src/client/util/TooltipTextMenu.tsx | 4 +- src/client/views/InkingStroke.tsx | 2 +- src/client/views/Main.tsx | 152 ++++++++++----------- .../views/collections/CollectionDockingView.tsx | 8 +- src/client/views/collections/CollectionPDFView.tsx | 10 +- .../views/collections/CollectionSchemaView.tsx | 4 +- .../views/collections/CollectionVideoView.tsx | 9 +- .../CollectionFreeFormLinkView.tsx | 20 +-- .../CollectionFreeFormLinksView.tsx | 63 +++++---- .../CollectionFreeFormRemoteCursors.tsx | 1 - src/client/views/nodes/IconBox.tsx | 12 +- 16 files changed, 165 insertions(+), 154 deletions(-) (limited to 'src/client/util/TooltipTextMenu.tsx') diff --git a/src/client/DocServer.ts b/src/client/DocServer.ts index 02fd28a86..3f17baec6 100644 --- a/src/client/DocServer.ts +++ b/src/client/DocServer.ts @@ -1,5 +1,5 @@ import * as OpenSocket from 'socket.io-client'; -import { MessageStore, Types } from "./../server/Message"; +import { MessageStore, Types, Message } from "./../server/Message"; import { Opt, FieldWaiting, RefField, HandleUpdate } from '../new_fields/Doc'; import { Utils } from '../Utils'; import { SerializationHelper } from './util/SerializationHelper'; @@ -13,6 +13,10 @@ export namespace DocServer { return window.location.origin + extension; } + export function DeleteDatabase() { + Utils.Emit(_socket, MessageStore.DeleteAll, {}); + } + export async function GetRefField(id: string): Promise> { let cached = _cache[id]; if (cached === undefined) { diff --git a/src/client/northstar/core/brusher/IBaseBrushable.ts b/src/client/northstar/core/brusher/IBaseBrushable.ts index c46db4d22..87f4ba413 100644 --- a/src/client/northstar/core/brusher/IBaseBrushable.ts +++ b/src/client/northstar/core/brusher/IBaseBrushable.ts @@ -1,9 +1,9 @@ import { PIXIPoint } from '../../utils/MathUtil'; import { IEquatable } from '../../utils/IEquatable'; -import { Document } from '../../../../fields/Document'; +import { Doc } from '../../../../new_fields/Doc'; export interface IBaseBrushable extends IEquatable { - BrusherModels: Array; + BrusherModels: Array; BrushColors: Array; Position: PIXIPoint; Size: PIXIPoint; diff --git a/src/client/northstar/core/filter/FilterModel.ts b/src/client/northstar/core/filter/FilterModel.ts index e2ba3f652..6ab96b33d 100644 --- a/src/client/northstar/core/filter/FilterModel.ts +++ b/src/client/northstar/core/filter/FilterModel.ts @@ -2,10 +2,9 @@ import { ValueComparison } from "./ValueComparision"; import { Utils } from "../../utils/Utils"; import { IBaseFilterProvider } from "./IBaseFilterProvider"; import { FilterOperand } from "./FilterOperand"; -import { KeyStore } from "../../../../fields/KeyStore"; -import { FieldWaiting } from "../../../../fields/Field"; -import { Document } from "../../../../fields/Document"; import { HistogramField } from "../../dash-fields/HistogramField"; +import { Cast, FieldValue } from "../../../../new_fields/Types"; +import { Doc } from "../../../../new_fields/Doc"; export class FilterModel { public ValueComparisons: ValueComparison[]; @@ -52,12 +51,12 @@ export class FilterModel { let children = new Array(); let linkedGraphNodes = baseOperation.Links; linkedGraphNodes.map(linkVm => { - let filterDoc = linkVm.Get(KeyStore.LinkedFromDocs); - if (filterDoc && filterDoc !== FieldWaiting && filterDoc instanceof Document) { - let filterHistogram = filterDoc.GetT(KeyStore.Data, HistogramField); - if (filterHistogram && filterHistogram !== FieldWaiting) { - if (!visitedFilterProviders.has(filterHistogram.Data)) { - let child = FilterModel.GetFilterModelsRecursive(filterHistogram.Data, visitedFilterProviders, filterModels, false); + let filterDoc = FieldValue(Cast(linkVm.linkedFrom, Doc)); + if (filterDoc) { + let filterHistogram = Cast(filterDoc.data, HistogramField); + if (filterHistogram) { + if (!visitedFilterProviders.has(filterHistogram.HistoOp)) { + let child = FilterModel.GetFilterModelsRecursive(filterHistogram.HistoOp, visitedFilterProviders, filterModels, false); if (child !== "") { // if (linkVm.IsInverted) { // child = "! " + child; diff --git a/src/client/northstar/core/filter/IBaseFilterConsumer.ts b/src/client/northstar/core/filter/IBaseFilterConsumer.ts index 59d7adf4c..e7549d113 100644 --- a/src/client/northstar/core/filter/IBaseFilterConsumer.ts +++ b/src/client/northstar/core/filter/IBaseFilterConsumer.ts @@ -1,10 +1,10 @@ import { FilterOperand } from '../filter/FilterOperand'; import { IEquatable } from '../../utils/IEquatable'; -import { Document } from "../../../../fields/Document"; +import { Doc } from '../../../../new_fields/Doc'; export interface IBaseFilterConsumer extends IEquatable { FilterOperand: FilterOperand; - Links: Document[]; + Links: Doc[]; } export function instanceOfIBaseFilterConsumer(object: any): object is IBaseFilterConsumer { diff --git a/src/client/northstar/dash-fields/HistogramField.ts b/src/client/northstar/dash-fields/HistogramField.ts index baeaca1dd..118f4cf7f 100644 --- a/src/client/northstar/dash-fields/HistogramField.ts +++ b/src/client/northstar/dash-fields/HistogramField.ts @@ -7,8 +7,9 @@ import { ObjectField } from "../../../new_fields/Doc"; import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils"; import { OmitKeys } from "../../../Utils"; import { Deserializable } from "../../util/SerializationHelper"; + function serialize(field: HistogramField) { - return OmitKeys(field.HistoOp, ['Links', 'BrushLinks', 'Result', 'BrushColors', 'FilterModels', 'FilterOperand']).omit + return OmitKeys(field.HistoOp, ['Links', 'BrushLinks', 'Result', 'BrushColors', 'FilterModels', 'FilterOperand']).omit; } function deserialize(jp: any) { diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx index 4f0eb7d63..1b6647003 100644 --- a/src/client/util/TooltipTextMenu.tsx +++ b/src/client/util/TooltipTextMenu.tsx @@ -35,8 +35,8 @@ export class TooltipTextMenu { private fontStylesToName: Map; private fontSizeIndicator: HTMLSpanElement = document.createElement("span"); //dropdown doms - private fontSizeDom: Node; - private fontStyleDom: Node; + private fontSizeDom?: Node; + private fontStyleDom?: Node; constructor(view: EditorView, editorProps: FieldViewProps) { this.view = view; diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx index 0f05da22c..616299146 100644 --- a/src/client/views/InkingStroke.tsx +++ b/src/client/views/InkingStroke.tsx @@ -1,8 +1,8 @@ import { observer } from "mobx-react"; import { observable } from "mobx"; import { InkingControl } from "./InkingControl"; -import { InkTool } from "../../fields/InkField"; import React = require("react"); +import { InkTool } from "../../new_fields/InkField"; interface StrokeProps { diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx index c6b3f06d8..1e3d4e259 100644 --- a/src/client/views/Main.tsx +++ b/src/client/views/Main.tsx @@ -8,17 +8,12 @@ import * as React from 'react'; import * as ReactDOM from 'react-dom'; import Measure from 'react-measure'; import * as request from 'request'; -import { Document } from '../../fields/Document'; -import { Field, FieldWaiting, Opt, FIELD_WAITING } from '../../fields/Field'; -import { KeyStore } from '../../fields/KeyStore'; -import { ListField } from '../../fields/ListField'; import { WorkspacesMenu } from '../../server/authentication/controllers/WorkspacesMenu'; import { CurrentUserUtils } from '../../server/authentication/models/current_user_utils'; import { MessageStore } from '../../server/Message'; import { RouteStore } from '../../server/RouteStore'; -import { ServerUtils } from '../../server/ServerUtil'; -import { emptyDocFunction, emptyFunction, returnTrue, Utils, returnOne, returnZero } from '../../Utils'; -import { Documents } from '../documents/Documents'; +import { emptyFunction, returnTrue, Utils, returnOne, returnZero } from '../../Utils'; +import { Docs } from '../documents/Documents'; import { ColumnAttributeModel } from '../northstar/core/attribute/AttributeModel'; import { AttributeTransformationModel } from '../northstar/core/attribute/AttributeTransformationModel'; import { Gateway, NorthstarSettings } from '../northstar/manager/Gateway'; @@ -26,7 +21,6 @@ import { AggregateFunction, Catalog } from '../northstar/model/idea/idea'; import '../northstar/model/ModelExtensions'; import { HistogramOperation } from '../northstar/operations/HistogramOperation'; import '../northstar/utils/Extensions'; -import { Server } from '../Server'; import { SetupDrag, DragManager } from '../util/DragManager'; import { Transform } from '../util/Transform'; import { UndoManager } from '../util/UndoManager'; @@ -39,6 +33,10 @@ import { MainOverlayTextBox } from './MainOverlayTextBox'; import { DocumentView } from './nodes/DocumentView'; import { PreviewCursor } from './PreviewCursor'; import { SelectionManager } from '../util/SelectionManager'; +import { FieldResult, Field, Doc, Id, Opt } from '../../new_fields/Doc'; +import { Cast, FieldValue, StrCast } from '../../new_fields/Types'; +import { DocServer } from '../DocServer'; +import { listSpec } from '../../new_fields/Schema'; @observer @@ -48,11 +46,13 @@ export class Main extends React.Component { @observable public pwidth: number = 0; @observable public pheight: number = 0; - @computed private get mainContainer(): Document | undefined | FIELD_WAITING { - return CurrentUserUtils.UserDocument.GetT(KeyStore.ActiveWorkspace, Document); + @computed private get mainContainer(): Opt { + return FieldValue(Cast(CurrentUserUtils.UserDocument.activeWorkspace, Doc)); } - private set mainContainer(doc: Document | undefined | FIELD_WAITING) { - doc && CurrentUserUtils.UserDocument.Set(KeyStore.ActiveWorkspace, doc); + private set mainContainer(doc: Opt) { + if (doc) { + CurrentUserUtils.UserDocument.activeWorkspace = doc; + } } constructor(props: Readonly<{}>) { @@ -100,8 +100,8 @@ export class Main extends React.Component { if (window.location.pathname !== RouteStore.home) { let pathname = window.location.pathname.split("/"); CurrentUserUtils.MainDocId = pathname[pathname.length - 1]; - Server.GetField(CurrentUserUtils.MainDocId, action((field: Opt) => { - if (field instanceof Document) { + DocServer.GetRefField(CurrentUserUtils.MainDocId).then(action((field: Opt) => { + if (field instanceof Doc) { this.openWorkspace(field, true); } })); @@ -113,9 +113,9 @@ export class Main extends React.Component { window.addEventListener("drop", (e) => e.preventDefault(), false); // drop event handler window.addEventListener("dragover", (e) => e.preventDefault(), false); // drag event handler window.addEventListener("keydown", (e) => { - if (e.key == "Escape") { + if (e.key === "Escape") { DragManager.AbortDrag(); - SelectionManager.DeselectAll() + SelectionManager.DeselectAll(); } }, false); // drag event handler // click interactions for the context menu @@ -126,54 +126,55 @@ export class Main extends React.Component { }), true); } - initAuthenticationRouters = () => { + initAuthenticationRouters = async () => { // Load the user's active workspace, or create a new one if initial session after signup if (!CurrentUserUtils.MainDocId) { - CurrentUserUtils.UserDocument.GetTAsync(KeyStore.ActiveWorkspace, Document).then(doc => { - if (doc) { - CurrentUserUtils.MainDocId = doc.Id; - this.openWorkspace(doc); - } else { - this.createNewWorkspace(); - } - }); + const doc = await Cast(CurrentUserUtils.UserDocument.activeWorkspace, Doc); + if (doc) { + CurrentUserUtils.MainDocId = doc[Id]; + this.openWorkspace(doc); + } else { + this.createNewWorkspace(); + } } else { - Server.GetField(CurrentUserUtils.MainDocId).then(field => - field instanceof Document ? this.openWorkspace(field) : + DocServer.GetRefField(CurrentUserUtils.MainDocId).then(field => + field instanceof Doc ? this.openWorkspace(field) : this.createNewWorkspace(CurrentUserUtils.MainDocId)); } } @action - createNewWorkspace = (id?: string): void => { - CurrentUserUtils.UserDocument.GetTAsync>(KeyStore.Workspaces, ListField).then(action((list: Opt>) => { - if (list) { - let freeformDoc = Documents.FreeformDocument([], { x: 0, y: 400, title: "mini collection" }); - var dockingLayout = { content: [{ type: 'row', content: [CollectionDockingView.makeDocumentConfig(freeformDoc)] }] }; - let mainDoc = Documents.DockDocument(JSON.stringify(dockingLayout), { title: `Main Container ${list.Data.length + 1}` }, id); - list.Data.push(mainDoc); - CurrentUserUtils.MainDocId = mainDoc.Id; - // bcz: strangely, we need a timeout to prevent exceptions/issues initializing GoldenLayout (the rendering engine for Main Container) - setTimeout(() => { - this.openWorkspace(mainDoc); - let pendingDocument = Documents.SchemaDocument([], { title: "New Mobile Uploads" }); - mainDoc.Set(KeyStore.OptionalRightCollection, pendingDocument); - }, 0); - } - })); + createNewWorkspace = async (id?: string) => { + const list = Cast(CurrentUserUtils.UserDocument.workspaces, listSpec(Doc)); + if (list) { + let freeformDoc = Docs.FreeformDocument([], { x: 0, y: 400, title: "mini collection" }); + var dockingLayout = { content: [{ type: 'row', content: [CollectionDockingView.makeDocumentConfig(freeformDoc)] }] }; + let mainDoc = Docs.DockDocument(JSON.stringify(dockingLayout), { title: `Main Container ${list.length + 1}` }, id); + list.push(mainDoc); + CurrentUserUtils.MainDocId = mainDoc[Id]; + // bcz: strangely, we need a timeout to prevent exceptions/issues initializing GoldenLayout (the rendering engine for Main Container) + setTimeout(() => { + this.openWorkspace(mainDoc); + let pendingDocument = Docs.SchemaDocument([], { title: "New Mobile Uploads" }); + mainDoc.optionalRightCollection = pendingDocument; + }, 0); + } } @action - openWorkspace = (doc: Document, fromHistory = false): void => { + openWorkspace = async (doc: Doc, fromHistory = false) => { this.mainContainer = doc; - fromHistory || window.history.pushState(null, doc.Title, "/doc/" + doc.Id); - CurrentUserUtils.UserDocument.GetTAsync(KeyStore.OptionalRightCollection, Document).then(col => - // if there is a pending doc, and it has new data, show it (syip: we use a timeout to prevent collection docking view from being uninitialized) - setTimeout(() => - col && col.GetTAsync>(KeyStore.Data, ListField, (f: Opt>) => - f && f.Data.length > 0 && CollectionDockingView.Instance.AddRightSplit(col)) - , 100) - ); + fromHistory || window.history.pushState(null, StrCast(doc.title), "/doc/" + doc.Id); + const col = await Cast(CurrentUserUtils.UserDocument.optionalRightCollection, Doc); + // if there is a pending doc, and it has new data, show it (syip: we use a timeout to prevent collection docking view from being uninitialized) + setTimeout(async () => { + if (col) { + const l = Cast(col.data, listSpec(Doc)); + if (l && l.length > 0) { + CollectionDockingView.Instance.AddRightSplit(col); + } + } + }, 100); } @computed @@ -196,7 +197,7 @@ export class Main extends React.Component { PanelHeight={pheightFunc} isTopMost={true} selectOnLoad={false} - focus={emptyDocFunction} + focus={emptyFunction} parentActive={returnTrue} whenActiveChanged={emptyFunction} ContainingCollectionView={undefined} />} @@ -214,17 +215,17 @@ export class Main extends React.Component { let audiourl = "http://techslides.com/demos/samples/sample.mp3"; let videourl = "http://techslides.com/demos/sample-videos/small.mp4"; - let addTextNode = action(() => Documents.TextDocument({ width: 200, height: 200, title: "a text note" })); - let addColNode = action(() => Documents.FreeformDocument([], { width: 200, height: 200, title: "a freeform collection" })); - let addSchemaNode = action(() => Documents.SchemaDocument([], { width: 200, height: 200, title: "a schema collection" })); - let addTreeNode = action(() => Documents.TreeDocument(this._northstarSchemas, { width: 250, height: 400, title: "northstar schemas", copyDraggedItems: true })); - let addVideoNode = action(() => Documents.VideoDocument(videourl, { width: 200, title: "video node" })); - let addPDFNode = action(() => Documents.PdfDocument(pdfurl, { width: 200, height: 200, title: "a pdf doc" })); - let addImageNode = action(() => Documents.ImageDocument(imgurl, { width: 200, title: "an image of a cat" })); - let addWebNode = action(() => Documents.WebDocument(weburl, { width: 200, height: 200, title: "a sample web page" })); - let addAudioNode = action(() => Documents.AudioDocument(audiourl, { width: 200, height: 200, title: "audio node" })); + let addTextNode = action(() => Docs.TextDocument({ width: 200, height: 200, title: "a text note" })); + let addColNode = action(() => Docs.FreeformDocument([], { width: 200, height: 200, title: "a freeform collection" })); + let addSchemaNode = action(() => Docs.SchemaDocument([], { width: 200, height: 200, title: "a schema collection" })); + let addTreeNode = action(() => Docs.TreeDocument(this._northstarSchemas, { width: 250, height: 400, title: "northstar schemas", copyDraggedItems: true })); + let addVideoNode = action(() => Docs.VideoDocument(videourl, { width: 200, title: "video node" })); + let addPDFNode = action(() => Docs.PdfDocument(pdfurl, { width: 200, height: 200, title: "a pdf doc" })); + let addImageNode = action(() => Docs.ImageDocument(imgurl, { width: 200, title: "an image of a cat" })); + let addWebNode = action(() => Docs.WebDocument(weburl, { width: 200, height: 200, title: "a sample web page" })); + let addAudioNode = action(() => Docs.AudioDocument(audiourl, { width: 200, height: 200, title: "audio node" })); - let btns: [React.RefObject, IconName, string, () => Document][] = [ + let btns: [React.RefObject, IconName, string, () => Doc][] = [ [React.createRef(), "font", "Add Textbox", addTextNode], [React.createRef(), "image", "Add Image", addImageNode], [React.createRef(), "file-pdf", "Add PDF", addPDFNode], @@ -260,9 +261,8 @@ export class Main extends React.Component { let logoutRef = React.createRef(); let toggleWorkspaces = () => runInAction(() => this._workspacesShown = !this._workspacesShown); - let clearDatabase = action(() => Utils.Emit(Server.Socket, MessageStore.DeleteAll, {})); return [ - , + ,
@@ -271,7 +271,7 @@ export class Main extends React.Component {
,
-
+
]; } @@ -279,10 +279,10 @@ export class Main extends React.Component { get workspaceMenu() { let areWorkspacesShown = () => this._workspacesShown; let toggleWorkspaces = () => runInAction(() => this._workspacesShown = !this._workspacesShown); - let workspaces = CurrentUserUtils.UserDocument.GetT>(KeyStore.Workspaces, ListField); - return (!workspaces || workspaces === FieldWaiting || this.mainContainer === FieldWaiting) ? (null) : + let workspaces = Cast(CurrentUserUtils.UserDocument.workspaces, listSpec(Doc)); + return (!workspaces || !this.mainContainer) ? (null) : ; } @@ -303,17 +303,17 @@ export class Main extends React.Component { } // --------------- Northstar hooks ------------- / - private _northstarSchemas: Document[] = []; + private _northstarSchemas: Doc[] = []; @action SetNorthstarCatalog(ctlog: Catalog) { CurrentUserUtils.NorthstarDBCatalog = ctlog; if (ctlog && ctlog.schemas) { ctlog.schemas.map(schema => { - let schemaDocuments: Document[] = []; + let schemaDocuments: Doc[] = []; let attributesToBecomeDocs = CurrentUserUtils.GetAllNorthstarColumnAttributes(schema); Promise.all(attributesToBecomeDocs.reduce((promises, attr) => { - promises.push(Server.GetField(attr.displayName! + ".alias").then(action((field: Opt) => { - if (field instanceof Document) { + promises.push(DocServer.GetRefField(attr.displayName! + ".alias").then(action((field: Opt) => { + if (field instanceof Doc) { schemaDocuments.push(field); } else { var atmod = new ColumnAttributeModel(attr); @@ -321,12 +321,12 @@ export class Main extends React.Component { new AttributeTransformationModel(atmod, AggregateFunction.None), new AttributeTransformationModel(atmod, AggregateFunction.Count), new AttributeTransformationModel(atmod, AggregateFunction.Count)); - schemaDocuments.push(Documents.HistogramDocument(histoOp, { width: 200, height: 200, title: attr.displayName! }, undefined, attr.displayName! + ".alias")); + schemaDocuments.push(Docs.HistogramDocument(histoOp, { width: 200, height: 200, title: attr.displayName! })); } }))); return promises; }, [] as Promise[])).finally(() => - this._northstarSchemas.push(Documents.TreeDocument(schemaDocuments, { width: 50, height: 100, title: schema.displayName! }))); + this._northstarSchemas.push(Docs.TreeDocument(schemaDocuments, { width: 50, height: 100, title: schema.displayName! }))); }); } } @@ -338,7 +338,7 @@ export class Main extends React.Component { } (async () => { - await Documents.initProtos(); + await Docs.initProtos(); await CurrentUserUtils.loadCurrentUser(); ReactDOM.render(
, document.getElementById('root')); })(); diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 69401ceeb..2ff409b9b 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -6,13 +6,11 @@ import { observer } from "mobx-react"; import * as ReactDOM from 'react-dom'; import Measure from "react-measure"; import { Utils, returnTrue, emptyFunction, returnOne, returnZero } from "../../../Utils"; -import { Server } from "../../Server"; import { undoBatch, UndoManager } from "../../util/UndoManager"; import { DocumentView } from "../nodes/DocumentView"; import "./CollectionDockingView.scss"; import React = require("react"); import { SubCollectionViewProps } from "./CollectionSubView"; -import { ServerUtils } from "../../../server/ServerUtil"; import { DragManager, DragLinksAsDocuments } from "../../util/DragManager"; import { Transform } from '../../util/Transform'; import { Doc, Id, Opt, Field, FieldId } from "../../../new_fields/Doc"; @@ -206,7 +204,7 @@ export class CollectionDockingView extends React.Component) => + DocServer.GetRefField(docid).then(action(async (sourceDoc: Opt) => (sourceDoc instanceof Doc) && DragLinksAsDocuments(tab, x, y, sourceDoc))); } else if ((className === "lm_title" || className === "lm_tab lm_active") && !e.shiftKey) { @@ -216,7 +214,7 @@ export class CollectionDockingView extends React.Component) => { + DocServer.GetRefField(docid).then(action((f: Opt) => { if (f instanceof Doc) { DragManager.StartDocumentDrag([tab], new DragManager.DocumentDragData([f]), x, y, { @@ -301,7 +299,7 @@ export class CollectionDockingView extends React.Component { return FieldView.LayoutString(CollectionPDFView, fieldKey); } - private get curPage() { return this.props.Document.GetNumber(KeyStore.CurPage, -1); } - private get numPages() { return this.props.Document.GetNumber(KeyStore.NumPages, 0); } - @action onPageBack = () => this.curPage > 1 ? this.props.Document.SetNumber(KeyStore.CurPage, this.curPage - 1) : -1; - @action onPageForward = () => this.curPage < this.numPages ? this.props.Document.SetNumber(KeyStore.CurPage, this.curPage + 1) : -1; + private get curPage() { return NumCast(this.props.Document.curPage, -1); } + private get numPages() { return NumCast(this.props.Document.numPages); } + @action onPageBack = () => this.curPage > 1 ? (this.props.Document.curPage = this.curPage - 1) : -1; + @action onPageForward = () => this.curPage < this.numPages ? (this.props.Document.curPage = this.curPage + 1) : -1; private get uIButtons() { let scaling = Math.min(1.8, this.props.ScreenToLocalTransform().Scale); diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx index 2e1175f28..874170f3d 100644 --- a/src/client/views/collections/CollectionSchemaView.tsx +++ b/src/client/views/collections/CollectionSchemaView.tsx @@ -5,7 +5,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, computed, observable, untracked } from "mobx"; import { observer } from "mobx-react"; import ReactTable, { CellInfo, ComponentPropsGetterR, ReactTableDefaults } from "react-table"; -import { MAX_ROW_HEIGHT } from '../../views/globalCssVariables.scss' +import { MAX_ROW_HEIGHT } from '../../views/globalCssVariables.scss'; import "react-table/react-table.css"; import { emptyFunction, returnFalse, returnZero } from "../../../Utils"; import { SetupDrag } from "../../util/DragManager"; @@ -283,7 +283,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) { // then by the time the options button is clicked, all of the fields should be in place. If a new field is added while this menu // is displayed (unlikely) it won't show up until something else changes. //TODO Types - untracked(() => docs.map(doc => Doc.GetAllPrototypes(doc).map(proto => proto._proxies.forEach((val: any, key: string) => keys[key] = false)))); + untracked(() => docs.map(doc => Doc.GetAllPrototypes(doc).map(proto => Object.keys(proto).forEach(key => keys[key] = false)))); this.columns.forEach(key => keys[key] = true); return Array.from(Object.keys(keys)).map(item => diff --git a/src/client/views/collections/CollectionVideoView.tsx b/src/client/views/collections/CollectionVideoView.tsx index 779dc8fc3..d314e3fc0 100644 --- a/src/client/views/collections/CollectionVideoView.tsx +++ b/src/client/views/collections/CollectionVideoView.tsx @@ -1,6 +1,5 @@ import { action, observable, trace } from "mobx"; import { observer } from "mobx-react"; -import { KeyStore } from "../../../fields/KeyStore"; import { ContextMenu } from "../ContextMenu"; import { CollectionViewType, CollectionBaseView, CollectionRenderProps } from "./CollectionBaseView"; import React = require("react"); @@ -8,6 +7,7 @@ import "./CollectionVideoView.scss"; import { CollectionFreeFormView } from "./collectionFreeForm/CollectionFreeFormView"; import { FieldView, FieldViewProps } from "../nodes/FieldView"; import { emptyFunction } from "../../../Utils"; +import { NumCast } from "../../../new_fields/Types"; @observer @@ -44,8 +44,9 @@ export class CollectionVideoView extends React.Component { if (ele) { this._player = ele.getElementsByTagName("video")[0]; console.log(this._player); - if (this.props.Document.GetNumber(KeyStore.CurPage, -1) >= 0) { - this._currentTimecode = this.props.Document.GetNumber(KeyStore.CurPage, -1); + const curPage = NumCast(this.props.Document.curPage, -1); + if (curPage >= 0) { + this._currentTimecode = curPage; } } } @@ -69,7 +70,7 @@ export class CollectionVideoView extends React.Component { (this._player as any).AHackBecauseSomethingResetsTheVideoToZero = -1; } else { this._currentTimecode = this._player.currentTime; - this.props.Document.SetNumber(KeyStore.CurPage, Math.round(this._currentTimecode)); + this.props.Document.curPage = Math.round(this._currentTimecode); } } } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx index 20c5a84bf..d4987fc18 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx @@ -1,15 +1,15 @@ import { observer } from "mobx-react"; -import { Document } from "../../../../fields/Document"; -import { KeyStore } from "../../../../fields/KeyStore"; import { Utils } from "../../../../Utils"; import "./CollectionFreeFormLinkView.scss"; import React = require("react"); import v5 = require("uuid/v5"); +import { StrCast, NumCast, BoolCast } from "../../../../new_fields/Types"; +import { Doc } from "../../../../new_fields/Doc"; export interface CollectionFreeFormLinkViewProps { - A: Document; - B: Document; - LinkDocs: Document[]; + A: Doc; + B: Doc; + LinkDocs: Doc[]; } @observer @@ -17,16 +17,16 @@ export class CollectionFreeFormLinkView extends React.Component { this.props.LinkDocs.map(l => - console.log("Link:" + l.Title)); + console.log("Link:" + StrCast(l.title))); } render() { let l = this.props.LinkDocs; let a = this.props.A; let b = this.props.B; - let x1 = a.GetNumber(KeyStore.X, 0) + (a.GetBoolean(KeyStore.IsMinimized, false) ? 5 : a.Width() / 2); - let y1 = a.GetNumber(KeyStore.Y, 0) + (a.GetBoolean(KeyStore.IsMinimized, false) ? 5 : a.Height() / 2); - let x2 = b.GetNumber(KeyStore.X, 0) + (b.GetBoolean(KeyStore.IsMinimized, false) ? 5 : b.Width() / 2); - let y2 = b.GetNumber(KeyStore.Y, 0) + (b.GetBoolean(KeyStore.IsMinimized, false) ? 5 : b.Height() / 2); + let x1 = NumCast(a.x) + (BoolCast(a.isMinimized, false) ? 5 : NumCast(a.width) / 2); + let y1 = NumCast(a.y) + (BoolCast(a.isMinimized, false) ? 5 : NumCast(a.height) / 2); + let x2 = NumCast(b.x) + (BoolCast(b.isMinimized, false) ? 5 : NumCast(b.width) / 2); + let y2 = NumCast(b.y) + (BoolCast(b.isMinimized, false) ? 5 : NumCast(b.height) / 2); return ( { _brushReactionDisposer?: IReactionDisposer; componentDidMount() { - this._brushReactionDisposer = reaction(() => this.props.Document.GetList(this.props.fieldKey, [] as Document[]).map(doc => doc.GetNumber(KeyStore.X, 0)), + this._brushReactionDisposer = reaction(() => Cast(this.props.Document[this.props.fieldKey], listSpec(Doc), []).map(doc => NumCast(doc.x)), () => { - let views = this.props.Document.GetList(this.props.fieldKey, [] as Document[]).filter(doc => doc.GetText(KeyStore.BackgroundLayout, "").indexOf("istogram") !== -1); + let views = Cast(this.props.Document[this.props.fieldKey], listSpec(Doc), []).filter(doc => StrCast(doc.backgroundLayout, "").indexOf("istogram") !== -1); for (let i = 0; i < views.length; i++) { for (let j = 0; j < views.length; j++) { let srcDoc = views[j]; let dstDoc = views[i]; - let x1 = srcDoc.GetNumber(KeyStore.X, 0); - let x1w = srcDoc.GetNumber(KeyStore.Width, -1); - let x2 = dstDoc.GetNumber(KeyStore.X, 0); - let x2w = dstDoc.GetNumber(KeyStore.Width, -1); + let x1 = NumCast(srcDoc.x); + let x1w = NumCast(srcDoc.width, -1); + let x2 = NumCast(dstDoc.x); + let x2w = NumCast(dstDoc.width, -1); if (x1w < 0 || x2w < 0 || i === j) { continue; } let dstTarg = dstDoc; let srcTarg = srcDoc; - let findBrush = (field: ListField) => field.Data.findIndex(brush => { - let bdocs = brush ? brush.GetList(KeyStore.BrushingDocs, [] as Document[]) : []; + let findBrush = (field: List) => field.findIndex(brush => { + let bdocs = brush ? Cast(brush.brushingDocs, listSpec(Doc), []) : []; return (bdocs.length && ((bdocs[0] === dstTarg && bdocs[1] === srcTarg)) ? true : false); }); - let brushAction = (field: ListField) => { + let brushAction = (field: List) => { let found = findBrush(field); if (found !== -1) { console.log("REMOVE BRUSH " + srcTarg.Title + " " + dstTarg.Title); - field.Data.splice(found, 1); + field.splice(found, 1); } }; if (Math.abs(x1 + x1w - x2) < 20) { - let linkDoc: Document = new Document(); - linkDoc.SetText(KeyStore.Title, "Histogram Brush"); - linkDoc.SetText(KeyStore.LinkDescription, "Brush between " + srcTarg.Title + " and " + dstTarg.Title); - linkDoc.SetData(KeyStore.BrushingDocs, [dstTarg, srcTarg], ListField); + let linkDoc: Doc = new Doc(); + linkDoc.title = "Histogram Brush"; + linkDoc.linkDescription = "Brush between " + StrCast(srcTarg.title) + " and " + StrCast(dstTarg.Title); + linkDoc.brushingDocs = new List([dstTarg, srcTarg]); - brushAction = (field: ListField) => { + brushAction = (field: List) => { if (findBrush(field) === -1) { console.log("ADD BRUSH " + srcTarg.Title + " " + dstTarg.Title); - (findBrush(field) === -1) && field.Data.push(linkDoc); + (findBrush(field) === -1) && field.push(linkDoc); } }; } - dstTarg.GetOrCreateAsync(KeyStore.BrushingDocs, ListField, brushAction); - srcTarg.GetOrCreateAsync(KeyStore.BrushingDocs, ListField, brushAction); + let dstBrushDocs = Cast(dstTarg.brushingDocs, listSpec(Doc)); + if (dstBrushDocs === undefined) { + dstTarg.brushingDocs = dstBrushDocs = new List(); + } + let srcBrushDocs = Cast(srcTarg.brushingDocs, listSpec(Doc)); + if (srcBrushDocs === undefined) { + srcTarg.brushingDocs = srcBrushDocs = new List(); + } + brushAction(dstBrushDocs); + brushAction(srcBrushDocs); } } @@ -70,9 +79,9 @@ export class CollectionFreeFormLinksView extends React.Component sv.props.ContainingCollectionView && sv.props.ContainingCollectionView.props.Document === this.props.Document); } @@ -82,12 +91,12 @@ export class CollectionFreeFormLinksView extends React.Component { let srcViews = this.documentAnchors(connection.a); let targetViews = this.documentAnchors(connection.b); - let possiblePairs: { a: Document, b: Document, }[] = []; + let possiblePairs: { a: Doc, b: Doc, }[] = []; srcViews.map(sv => targetViews.map(tv => possiblePairs.push({ a: sv.props.Document, b: tv.props.Document }))); possiblePairs.map(possiblePair => drawnPairs.reduce((found, drawnPair) => { let match = (possiblePair.a === drawnPair.a && possiblePair.b === drawnPair.b); - if (match && !drawnPair.l.reduce((found, link) => found || link.Id === connection.l.Id, false)) { + if (match && !drawnPair.l.reduce((found, link) => found || link[Id] === connection.l[Id], false)) { drawnPair.l.push(connection.l); } return match || found; @@ -96,7 +105,7 @@ export class CollectionFreeFormLinksView extends React.Component ); } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx index cf0a6de00..036745eca 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx @@ -1,6 +1,5 @@ import { computed } from "mobx"; import { observer } from "mobx-react"; -import { KeyStore } from "../../../../fields/KeyStore"; import { CollectionViewProps, CursorEntry } from "../CollectionSubView"; import "./CollectionFreeFormView.scss"; import React = require("react"); diff --git a/src/client/views/nodes/IconBox.tsx b/src/client/views/nodes/IconBox.tsx index 9c90c0a0e..f7cceb3d4 100644 --- a/src/client/views/nodes/IconBox.tsx +++ b/src/client/views/nodes/IconBox.tsx @@ -4,12 +4,12 @@ import { faCaretUp, faFilePdf, faFilm, faImage, faObjectGroup, faStickyNote } fr import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { action, computed } from "mobx"; import { observer } from "mobx-react"; -import { Document } from '../../../fields/Document'; -import { IconField } from "../../../fields/IconFIeld"; -import { KeyStore } from "../../../fields/KeyStore"; import { SelectionManager } from "../../util/SelectionManager"; import { FieldView, FieldViewProps } from './FieldView'; import "./IconBox.scss"; +import { Cast } from "../../../new_fields/Types"; +import { Doc } from "../../../new_fields/Doc"; +import { IconField } from "../../../new_fields/IconField"; library.add(faCaretUp); @@ -22,8 +22,8 @@ library.add(faFilm); export class IconBox extends React.Component { public static LayoutString() { return FieldView.LayoutString(IconBox); } - @computed get maximized() { return this.props.Document.GetT(KeyStore.MaximizedDoc, Document); } - @computed get layout(): string { return this.props.Document.GetData(this.props.fieldKey, IconField, "

Error loading layout data

" as string); } + @computed get maximized() { return Cast(this.props.Document.maximizedDoc, Doc); } + @computed get layout(): string { const field = Cast(this.props.Document[this.props.fieldKey], IconField); return field ? field.layout : "

Error loading layout data

"; } @computed get minimizedIcon() { return IconBox.DocumentIcon(this.layout); } public static DocumentIcon(layout: string) { @@ -33,7 +33,7 @@ export class IconBox extends React.Component { layout.indexOf("Video") !== -1 ? faFilm : layout.indexOf("Collection") !== -1 ? faObjectGroup : faCaretUp; - return + return ; } render() { -- cgit v1.2.3-70-g09d2 From a5ab5caa244da261814bc10f0ae88b302da93951 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Sun, 28 Apr 2019 22:00:32 -0400 Subject: fixed webbox interactions. got rid of pdf annotation. fixed formatted text menu appearing --- src/client/util/TooltipTextMenu.tsx | 2 +- src/client/views/nodes/FormattedTextBox.tsx | 20 ++++++++++++-------- src/client/views/nodes/PDFBox.tsx | 4 ++-- src/client/views/nodes/WebBox.scss | 17 +++++++++++++++-- src/client/views/nodes/WebBox.tsx | 6 ++++-- 5 files changed, 34 insertions(+), 15 deletions(-) (limited to 'src/client/util/TooltipTextMenu.tsx') diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx index 4f0eb7d63..38267f4f9 100644 --- a/src/client/util/TooltipTextMenu.tsx +++ b/src/client/util/TooltipTextMenu.tsx @@ -24,7 +24,7 @@ const SVG = "http://www.w3.org/2000/svg"; //appears above a selection of text in a RichTextBox to give user options such as Bold, Italics, etc. export class TooltipTextMenu { - private tooltip: HTMLElement; + public tooltip: HTMLElement; private num_icons = 0; private view: EditorView; private fontStyles: MarkType[]; diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index d8cd28b6c..fc8d757f6 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -1,4 +1,4 @@ -import { action, IReactionDisposer, reaction, trace, computed } from "mobx"; +import { action, IReactionDisposer, reaction, trace, computed, _allowStateChangesInsideComputed } from "mobx"; import { baseKeymap } from "prosemirror-commands"; import { history } from "prosemirror-history"; import { keymap } from "prosemirror-keymap"; @@ -22,8 +22,6 @@ import React = require("react"); import { SelectionManager } from "../../util/SelectionManager"; import { observer } from "mobx-react"; import { InkingControl } from "../InkingControl"; -const { buildMenuItems } = require("prosemirror-example-setup"); -const { menuBar } = require("prosemirror-menu"); // FormattedTextBox: Displays an editable plain text node that maps to a specified Key of a Document // @@ -67,9 +65,10 @@ export class FormattedTextBox extends React.Component<(FieldViewProps & Formatte _applyingChange: boolean = false; + _lastState: any = undefined; dispatchTransaction = (tx: Transaction) => { if (this._editorView) { - const state = this._editorView.state.apply(tx); + const state = this._lastState = this._editorView.state.apply(tx); this._editorView.updateState(state); this._applyingChange = true; this.props.Document.SetDataOnPrototype( @@ -88,10 +87,10 @@ export class FormattedTextBox extends React.Component<(FieldViewProps & Formatte schema, inpRules, //these currently don't do anything, but could eventually be helpful plugins: this.props.isOverlay ? [ + this.tooltipTextMenuPlugin(), history(), keymap(buildKeymap(schema)), keymap(baseKeymap), - this.tooltipTextMenuPlugin(), // this.tooltipLinkingMenuPlugin(), new Plugin({ props: { @@ -169,8 +168,10 @@ export class FormattedTextBox extends React.Component<(FieldViewProps & Formatte } @action onPointerDown = (e: React.PointerEvent): void => { - if (e.button === 1 && this.props.isSelected() && !e.altKey && !e.ctrlKey && !e.metaKey) { + if (e.button === 0 && this.props.isSelected() && !e.altKey && !e.ctrlKey && !e.metaKey) { e.stopPropagation(); + if (this._toolTipTextMenu && this._toolTipTextMenu.tooltip) + this._toolTipTextMenu.tooltip.style.opacity = "0"; } if (e.button === 2 || (e.button === 0 && e.ctrlKey)) { this._gotDown = true; @@ -178,7 +179,8 @@ export class FormattedTextBox extends React.Component<(FieldViewProps & Formatte } } onPointerUp = (e: React.PointerEvent): void => { - console.log("pointer up"); + if (this._toolTipTextMenu && this._toolTipTextMenu.tooltip) + this._toolTipTextMenu.tooltip.style.opacity = "1"; if (e.buttons === 1 && this.props.isSelected() && !e.altKey) { e.stopPropagation(); } @@ -235,13 +237,15 @@ export class FormattedTextBox extends React.Component<(FieldViewProps & Formatte tooltipTextMenuPlugin() { let myprops = this.props; + let self = this; return new Plugin({ view(_editorView) { - return new TooltipTextMenu(_editorView, myprops); + return self._toolTipTextMenu = new TooltipTextMenu(_editorView, myprops); } }); } + _toolTipTextMenu: TooltipTextMenu | undefined = undefined; tooltipLinkingMenuPlugin() { let myprops = this.props; return new Plugin({ diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index 3d13c6f23..226dfba11 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -115,7 +115,7 @@ export class PDFBox extends React.Component { child.id = "highlighted"; //@ts-ignore obj.spans.push(child); - child.addEventListener("mouseover", this.onEnter); //adds mouseover annotation handler + // child.addEventListener("mouseover", this.onEnter); //adds mouseover annotation handler } }); } @@ -138,7 +138,7 @@ export class PDFBox extends React.Component { child.id = "highlighted"; //@ts-ignore temp.spans.push(child); - child.addEventListener("mouseover", this.onEnter); //adds mouseover annotation handler + // child.addEventListener("mouseover", this.onEnter); //adds mouseover annotation handler } }); diff --git a/src/client/views/nodes/WebBox.scss b/src/client/views/nodes/WebBox.scss index 2ad1129a4..eb09b0693 100644 --- a/src/client/views/nodes/WebBox.scss +++ b/src/client/views/nodes/WebBox.scss @@ -1,12 +1,19 @@ -.webBox-cont { +.webBox-cont, .webBox-cont-interactive{ padding: 0vw; position: absolute; top: 0; left:0; width: 100%; height: 100%; - overflow: scroll; + overflow: auto; + pointer-events: none ; +} +.webBox-cont-interactive { + pointer-events: all; + span { + user-select: text !important; + } } #webBox-htmlSpan { @@ -15,6 +22,12 @@ left:0; } +.webBox-overlay { + width: 100%; + height: 100%; + position: absolute; +} + .webBox-button { padding : 0vw; border: none; diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index f7f5e31e6..a7c6fda8b 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -7,6 +7,7 @@ import { observer } from "mobx-react"; import { computed, reaction, IReactionDisposer } from 'mobx'; import { KeyStore } from '../../../fields/KeyStore'; import { DocumentDecorations } from "../DocumentDecorations"; +import { InkingControl } from "../InkingControl"; @observer export class WebBox extends React.Component { @@ -45,12 +46,13 @@ export class WebBox extends React.Component { let frozen = !this.props.isSelected() || DocumentDecorations.Instance.Interacting; + let classname = "webBox-cont" + (this.props.isSelected() && !InkingControl.Instance.selectedTool && !DocumentDecorations.Instance.Interacting ? "-interactive" : ""); return ( <> -
+
{content}
- {!frozen ? (null) :
} + {!frozen ? (null) :
} ); } } \ No newline at end of file -- cgit v1.2.3-70-g09d2 From 59c52553a942d327b3cdf7377eb85f4b0b19c2dd Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Wed, 8 May 2019 23:52:13 -0400 Subject: added imageResize handle in text boxes. --- src/client/util/RichTextSchema.tsx | 85 +++++++++++++++++++++- src/client/util/TooltipTextMenu.tsx | 1 + .../collections/collectionFreeForm/MarqueeView.tsx | 6 +- src/client/views/nodes/FormattedTextBox.tsx | 22 ++---- 4 files changed, 91 insertions(+), 23 deletions(-) (limited to 'src/client/util/TooltipTextMenu.tsx') diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx index 9ef71e305..c036bfe97 100644 --- a/src/client/util/RichTextSchema.tsx +++ b/src/client/util/RichTextSchema.tsx @@ -84,6 +84,7 @@ export const nodes: { [index: string]: NodeSpec } = { inline: true, attrs: { src: {}, + width: { default: "100px" }, alt: { default: null }, title: { default: null } }, @@ -94,11 +95,16 @@ export const nodes: { [index: string]: NodeSpec } = { return { src: dom.getAttribute("src"), title: dom.getAttribute("title"), - alt: dom.getAttribute("alt") - }; + alt: dom.getAttribute("alt"), + width: Math.min(100, Number(dom.getAttribute("width"))), + } } }], - toDOM(node: any) { return ["img", node.attrs]; } + // TODO if we don't define toDom, something weird happens: dragging the image will not move it but clone it. Why? + toDOM(node) { + const attrs = { style: `width: ${node.attrs.width}` } + return ["img", { ...node.attrs, ...attrs }] + } }, // :: NodeSpec A hard line break, represented in the DOM as `
`. @@ -290,6 +296,13 @@ export const marks: { [index: string]: MarkSpec } = { }] }, + p14: { + parseDOM: [{ style: 'font-size: 14px;' }], + toDOM: () => ['span', { + style: 'font-size: 14px;' + }] + }, + p16: { parseDOM: [{ style: 'font-size: 16px;' }], toDOM: () => ['span', { @@ -325,7 +338,73 @@ export const marks: { [index: string]: MarkSpec } = { }] }, }; +function getFontSize(element: any) { + return parseFloat((getComputedStyle(element) as any).fontSize); +} + +export class ImageResizeView { + _handle: HTMLElement; + _img: HTMLElement; + _outer: HTMLElement; + constructor(node: any, view: any, getPos: any) { + this._handle = document.createElement("span"); + this._img = document.createElement("img"); + this._outer = document.createElement("span"); + this._outer.style.position = "relative"; + this._outer.style.width = node.attrs.width; + this._outer.style.display = "inline-block"; + this._outer.style.overflow = "hidden"; + + this._img.setAttribute("src", node.attrs.src); + this._img.style.width = "100%"; + this._handle.style.position = "absolute"; + this._handle.style.width = "20px"; + this._handle.style.height = "20px"; + this._handle.style.backgroundColor = "blue"; + this._handle.style.borderRadius = "15px"; + this._handle.style.display = "none"; + this._handle.style.bottom = "-10px"; + this._handle.style.right = "-10px"; + let self = this; + this._handle.onpointerdown = function (e: any) { + e.preventDefault(); + const startX = e.pageX; + const startWidth = parseFloat(node.attrs.width); + const onpointermove = (e: any) => { + const currentX = e.pageX; + const diffInPx = currentX - startX; + self._outer.style.width = `${startWidth + diffInPx}`; + } + + const onpointerup = () => { + document.removeEventListener("pointermove", onpointermove); + document.removeEventListener("pointerup", onpointerup); + view.dispatch( + view.state.tr.setNodeMarkup(getPos(), null, + { src: node.attrs.src, width: self._outer.style.width })); + } + + document.addEventListener("pointermove", onpointermove) + document.addEventListener("pointerup", onpointerup) + } + this._outer.appendChild(this._handle); + this._outer.appendChild(this._img); + (this as any).dom = this._outer; + } + + selectNode() { + this._img.classList.add("ProseMirror-selectednode"); + + this._handle.style.display = ""; + } + + deselectNode() { + this._img.classList.remove("ProseMirror-selectednode"); + + this._handle.style.display = "none"; + } +} // :: Schema // This schema rougly corresponds to the document schema used by // [CommonMark](http://commonmark.org/), minus the list elements, diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx index 68a73375e..e33c53a1a 100644 --- a/src/client/util/TooltipTextMenu.tsx +++ b/src/client/util/TooltipTextMenu.tsx @@ -94,6 +94,7 @@ export class TooltipTextMenu { this.fontSizeToNum = new Map(); this.fontSizeToNum.set(schema.marks.p10, 10); this.fontSizeToNum.set(schema.marks.p12, 12); + this.fontSizeToNum.set(schema.marks.p14, 14); this.fontSizeToNum.set(schema.marks.p16, 16); this.fontSizeToNum.set(schema.marks.p24, 24); this.fontSizeToNum.set(schema.marks.p32, 32); diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 0345d5efd..6057aaeba 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -180,7 +180,7 @@ export class MarqueeView extends React.Component this.cleanupInteractions(false); e.stopPropagation(); } - if (e.key === "c" || e.key === "r" || e.key === "s" || e.key === "e") { + if (e.key === "c" || e.key === "r" || e.key === "s" || e.key === "e" || e.key === "p") { this._commandExecuted = true; e.stopPropagation(); let bounds = this.Bounds; @@ -218,12 +218,12 @@ export class MarqueeView extends React.Component this.marqueeInkDelete(inkData); // SelectionManager.DeselectAll(); - if (e.key === "s" || e.key === "r") { + if (e.key === "s" || e.key === "r" || e.key === "p") { e.preventDefault(); let scrpt = this.props.getTransform().inverse().transformPoint(bounds.left, bounds.top); let summary = Docs.TextDocument({ x: bounds.left, y: bounds.top, width: 300, height: 100, backgroundColor: "yellow", title: "-summary-" }); - if (e.key === "s") { + if (e.key === "s" || e.key === "p") { summary.proto!.maximizeOnRight = true; newCollection.proto!.summaryDoc = summary; selected = [newCollection]; diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 4b3172e82..445a834ee 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -6,7 +6,7 @@ import { EditorState, Plugin, Transaction } from "prosemirror-state"; import { EditorView } from "prosemirror-view"; import buildKeymap from "../../util/ProsemirrorKeymap"; import { inpRules } from "../../util/RichTextRules"; -import { schema } from "../../util/RichTextSchema"; +import { schema, ImageResizeView } from "../../util/RichTextSchema"; import { TooltipLinkingMenu } from "../../util/TooltipLinkingMenu"; import { TooltipTextMenu } from "../../util/TooltipTextMenu"; import { ContextMenu } from "../../views/ContextMenu"; @@ -24,8 +24,6 @@ import { StrCast, Cast, NumCast, BoolCast } from "../../../new_fields/Types"; import { RichTextField } from "../../../new_fields/RichTextField"; import { Id } from "../../../new_fields/RefField"; import { UndoManager } from "../../util/UndoManager"; -import { Transform } from "prosemirror-transform"; -import { Transform as MatrixTransform } from "../../util/Transform"; // FormattedTextBox: Displays an editable plain text node that maps to a specified Key of a Document // @@ -149,7 +147,10 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe if (this._proseRef.current) { this._editorView = new EditorView(this._proseRef.current, { state: field && field.Data ? EditorState.fromJSON(config, JSON.parse(field.Data)) : EditorState.create(config), - dispatchTransaction: this.dispatchTransaction + dispatchTransaction: this.dispatchTransaction, + nodeViews: { + image(node, view, getPos) { return new ImageResizeView(node, view, getPos) } + } }); let text = StrCast(this.props.Document.documentText); if (text.startsWith("@@@")) { @@ -228,19 +229,6 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe description: NumCast(this.props.Document.nativeWidth) ? "Unfreeze" : "Freeze", event: this.textCapability }); - - // ContextMenu.Instance.addItem({ - // description: "Submenu", - // items: [ - // { - // description: "item 1", event: - // }, - // { - // description: "item 2", event: - // } - // ] - // }) - // e.stopPropagation() } onPointerWheel = (e: React.WheelEvent): void => { -- cgit v1.2.3-70-g09d2 From 9015421a227ab58f309906eabf884654d3a31a17 Mon Sep 17 00:00:00 2001 From: bob Date: Thu, 9 May 2019 11:58:36 -0400 Subject: added start of hyperlinks to text boxes --- src/client/util/DragManager.ts | 3 +- src/client/util/TooltipTextMenu.tsx | 101 +++++++++++++++++++++++++++++++- src/client/views/nodes/DocumentView.tsx | 1 + 3 files changed, 102 insertions(+), 3 deletions(-) (limited to 'src/client/util/TooltipTextMenu.tsx') diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index ec192eaff..fbf20e244 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -172,6 +172,7 @@ export namespace DragManager { droppedDocuments: Doc[] = []; linkSourceDocument: Doc; blacklist: Doc[]; + dontClearTextBox?: boolean; [id: string]: any; } @@ -188,7 +189,7 @@ export namespace DragManager { dragDiv.style.pointerEvents = "none"; DragManager.Root().appendChild(dragDiv); } - MainOverlayTextBox.Instance.SetTextDoc(); + if (!dragData.dontClearTextBox) MainOverlayTextBox.Instance.SetTextDoc(); let scaleXs: number[] = []; let scaleYs: number[] = []; diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx index e33c53a1a..15895fd1c 100644 --- a/src/client/util/TooltipTextMenu.tsx +++ b/src/client/util/TooltipTextMenu.tsx @@ -6,19 +6,28 @@ import { keymap } from "prosemirror-keymap"; import { EditorState, Transaction, NodeSelection, TextSelection } from "prosemirror-state"; import { EditorView } from "prosemirror-view"; import { schema } from "./RichTextSchema"; -import { Schema, NodeType, MarkType } from "prosemirror-model"; +import { Schema, NodeType, MarkType, Mark } from "prosemirror-model"; import React = require("react"); import "./TooltipTextMenu.scss"; const { toggleMark, setBlockType, wrapIn } = require("prosemirror-commands"); import { library } from '@fortawesome/fontawesome-svg-core'; import { wrapInList, bulletList, liftListItem, listItem, } from 'prosemirror-schema-list'; -import { liftTarget } from 'prosemirror-transform'; +import { liftTarget, RemoveMarkStep, AddMarkStep } from 'prosemirror-transform'; import { faListUl, } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { FieldViewProps } from "../views/nodes/FieldView"; import { throwStatement } from "babel-types"; +import { View } from "@react-pdf/renderer"; +import { DragManager } from "./DragManager"; +import { Doc, Opt, Field } from "../../new_fields/Doc"; +import { Id } from "../../new_fields/RefField"; +import { Utils } from "../northstar/utils/Utils"; +import { DocServer } from "../DocServer"; +import { CollectionFreeFormDocumentView } from "../views/nodes/CollectionFreeFormDocumentView"; +import { CollectionDockingView } from "../views/collections/CollectionDockingView"; +import { DocumentManager } from "./DocumentManager"; const SVG = "http://www.w3.org/2000/svg"; @@ -37,6 +46,8 @@ export class TooltipTextMenu { private fontStylesToName: Map; private listTypeToIcon: Map; private fontSizeIndicator: HTMLSpanElement = document.createElement("span"); + private linkEditor?: HTMLDivElement; + private linkText?: HTMLDivElement; //dropdown doms private fontSizeDom?: Node; private fontStyleDom?: Node; @@ -150,6 +161,90 @@ export class TooltipTextMenu { this.tooltip.appendChild(this.fontStyleDom); } + updateLinkMenu() { + if (!this.linkEditor || !this.linkText) { + this.linkEditor = document.createElement("div"); + this.linkEditor.style.color = "white"; + this.linkText = document.createElement("div"); + this.linkText.style.cssFloat = "left"; + this.linkText.style.marginRight = "5px"; + this.linkText.setAttribute("contenteditable", "true"); + this.linkText.style.color = "white"; + let linkBtn = document.createElement("div"); + linkBtn.textContent = ">>"; + linkBtn.style.width = "20px"; + linkBtn.style.height = "20px"; + linkBtn.style.color = "white"; + linkBtn.style.cssFloat = "left"; + linkBtn.onpointerdown = (e: PointerEvent) => { + let node = this.view.state.selection.$from.nodeAfter; + let link = node && node.marks.find(m => m.type.name === "link"); + if (link) { + console.log("Link to : " + link.attrs.href); + let href: string = link.attrs.href; + if (href.indexOf(DocServer.prepend("/doc/")) === 0) { + let docid = href.replace(DocServer.prepend("/doc/"), ""); + DocServer.GetRefField(docid).then(action((f: Opt) => { + if (f instanceof Doc) { + if (DocumentManager.Instance.getDocumentView(f)) + DocumentManager.Instance.getDocumentView(f)!.props.focus(f); + else CollectionDockingView.Instance.AddRightSplit(f); + } + })); + } + e.stopPropagation(); + e.preventDefault(); + } + } + let linkDrag = document.createElement("div"); + linkDrag.textContent = "O"; + linkDrag.style.width = "20px"; + linkDrag.style.height = "20px"; + linkDrag.style.color = "white"; + linkDrag.style.cssFloat = "left"; + linkDrag.onpointerdown = (e: PointerEvent) => { + let dragData = new DragManager.LinkDragData(this.editorProps.Document); + dragData.dontClearTextBox = true; + DragManager.StartLinkDrag(this.linkEditor!, dragData, e.clientX, e.clientY, + { + handlers: { + dragComplete: action(() => { + let m = dragData.droppedDocuments as Doc[]; + this.makeLink(DocServer.prepend("/doc/" + m[0][Id])); + }), + }, + hideSource: false + }) + }; + this.linkEditor.appendChild(this.linkText); + this.linkEditor.appendChild(linkBtn); + this.linkEditor.appendChild(linkDrag) + this.tooltip.appendChild(this.linkEditor); + } + + let node = this.view.state.selection.$from.nodeAfter; + let link = node && node.marks.find(m => m.type.name === "link"); + this.linkText.textContent = link ? link.attrs.href : "-empty-"; + + this.linkText.onkeydown = (e: KeyboardEvent) => { + if (e.key === "Enter") { + this.makeLink(this.linkText!.textContent!); + e.stopPropagation(); + e.preventDefault(); + } + } + this.tooltip.appendChild(this.linkEditor); + } + + makeLink = (target: string) => { + let node = this.view.state.selection.$from.nodeAfter; + let link = this.view.state.schema.mark(this.view.state.schema.marks.link, { href: target }); + this.view.dispatch(this.view.state.tr.removeMark(this.view.state.selection.from, this.view.state.selection.to, this.view.state.schema.marks.link)); + this.view.dispatch(this.view.state.tr.addMark(this.view.state.selection.from, this.view.state.selection.to, link)); + node = this.view.state.selection.$from.nodeAfter; + link = node && node.marks.find(m => m.type.name === "link"); + } + //will display a remove-list-type button if selection is in list, otherwise will show list type dropdown updateListItemDropdown(label: string, listTypeBtn: Node) { //remove old btn @@ -348,6 +443,8 @@ export class TooltipTextMenu { } else { //multiple font sizes selected this.updateFontSizeDropdown("Various"); } + + this.updateLinkMenu(); } //finds all active marks on selection in given group diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 38efeeba5..c3bf36553 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -238,6 +238,7 @@ export class DocumentView extends DocComponent(Docu const protoDest = destDoc.proto; const protoSrc = sourceDoc.proto; Doc.MakeLink(protoSrc ? protoSrc : sourceDoc, protoDest ? protoDest : destDoc); + de.data.droppedDocuments.push(destDoc); e.stopPropagation(); } } -- cgit v1.2.3-70-g09d2 From 244d4d127e7e1a0faadbc5a8baed7922ef03522c Mon Sep 17 00:00:00 2001 From: bob Date: Thu, 9 May 2019 14:11:35 -0400 Subject: cleaned up textlinking a little. --- src/client/util/DragManager.ts | 13 ++-- src/client/util/SelectionManager.ts | 4 +- src/client/util/TooltipTextMenu.tsx | 25 +++--- src/client/views/DocumentDecorations.tsx | 8 +- src/client/views/MainOverlayTextBox.tsx | 30 ++++--- .../views/collections/CollectionSchemaView.tsx | 3 +- src/client/views/collections/CollectionSubView.tsx | 2 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 8 +- src/client/views/nodes/FieldView.tsx | 2 +- src/client/views/nodes/FormattedTextBox.tsx | 91 ++++++++++++++++++---- 10 files changed, 122 insertions(+), 64 deletions(-) (limited to 'src/client/util/TooltipTextMenu.tsx') diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index fbf20e244..eaf851a75 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -1,11 +1,9 @@ -import { action } from "mobx"; +import { action, runInAction } from "mobx"; +import { Doc, DocListCast } from "../../new_fields/Doc"; +import { Cast } from "../../new_fields/Types"; import { emptyFunction } from "../../Utils"; import { CollectionDockingView } from "../views/collections/CollectionDockingView"; import * as globalCssVariables from "../views/globalCssVariables.scss"; -import { MainOverlayTextBox } from "../views/MainOverlayTextBox"; -import { Doc, DocListCast } from "../../new_fields/Doc"; -import { Cast } from "../../new_fields/Types"; -import { listSpec } from "../../new_fields/Schema"; export type dropActionType = "alias" | "copy" | undefined; export function SetupDrag(_reference: React.RefObject, docFunc: () => Doc, moveFunc?: DragManager.MoveFunction, dropAction?: dropActionType) { @@ -154,7 +152,10 @@ export namespace DragManager { [id: string]: any; } + export let StartDragFunctions: (() => void)[] = []; + export function StartDocumentDrag(eles: HTMLElement[], dragData: DocumentDragData, downX: number, downY: number, options?: DragOptions) { + runInAction(() => StartDragFunctions.map(func => func())); StartDrag(eles, dragData, downX, downY, options, (dropData: { [id: string]: any }) => (dropData.droppedDocuments = dragData.userDropAction == "alias" || (!dragData.userDropAction && dragData.dropAction == "alias") ? @@ -189,7 +190,6 @@ export namespace DragManager { dragDiv.style.pointerEvents = "none"; DragManager.Root().appendChild(dragDiv); } - if (!dragData.dontClearTextBox) MainOverlayTextBox.Instance.SetTextDoc(); let scaleXs: number[] = []; let scaleYs: number[] = []; @@ -217,6 +217,7 @@ export namespace DragManager { dragElement.style.top = "0"; dragElement.style.bottom = ""; dragElement.style.left = "0"; + dragElement.style.color = "black"; dragElement.style.transformOrigin = "0 0"; dragElement.style.zIndex = globalCssVariables.contextMenuZindex;// "1000"; dragElement.style.transform = `translate(${x}px, ${y}px) scale(${scaleX}, ${scaleY})`; diff --git a/src/client/util/SelectionManager.ts b/src/client/util/SelectionManager.ts index fe5acf4b4..a3a8172c7 100644 --- a/src/client/util/SelectionManager.ts +++ b/src/client/util/SelectionManager.ts @@ -1,7 +1,7 @@ import { observable, action } from "mobx"; import { Doc } from "../../new_fields/Doc"; -import { MainOverlayTextBox } from "../views/MainOverlayTextBox"; import { DocumentView } from "../views/nodes/DocumentView"; +import { FormattedTextBox } from "../views/nodes/FormattedTextBox"; export namespace SelectionManager { class Manager { @@ -25,7 +25,7 @@ export namespace SelectionManager { DeselectAll(): void { manager.SelectedDocuments.map(dv => dv.props.whenActiveChanged(false)); manager.SelectedDocuments = []; - MainOverlayTextBox.Instance.SetTextDoc(); + FormattedTextBox.InputBoxOverlay = undefined; } @action ReselectAll() { diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx index 15895fd1c..6eb654319 100644 --- a/src/client/util/TooltipTextMenu.tsx +++ b/src/client/util/TooltipTextMenu.tsx @@ -48,6 +48,7 @@ export class TooltipTextMenu { private fontSizeIndicator: HTMLSpanElement = document.createElement("span"); private linkEditor?: HTMLDivElement; private linkText?: HTMLDivElement; + private linkDrag?: HTMLImageElement; //dropdown doms private fontSizeDom?: Node; private fontStyleDom?: Node; @@ -168,8 +169,13 @@ export class TooltipTextMenu { this.linkText = document.createElement("div"); this.linkText.style.cssFloat = "left"; this.linkText.style.marginRight = "5px"; + this.linkText.style.marginLeft = "5px"; this.linkText.setAttribute("contenteditable", "true"); + this.linkText.style.whiteSpace = "nowrap"; + this.linkText.style.width = "150px"; + this.linkText.style.overflow = "hidden"; this.linkText.style.color = "white"; + this.linkText.onpointerdown = (e: PointerEvent) => { e.stopPropagation(); } let linkBtn = document.createElement("div"); linkBtn.textContent = ">>"; linkBtn.style.width = "20px"; @@ -196,16 +202,17 @@ export class TooltipTextMenu { e.preventDefault(); } } - let linkDrag = document.createElement("div"); - linkDrag.textContent = "O"; - linkDrag.style.width = "20px"; - linkDrag.style.height = "20px"; - linkDrag.style.color = "white"; - linkDrag.style.cssFloat = "left"; - linkDrag.onpointerdown = (e: PointerEvent) => { + this.linkDrag = document.createElement("img"); + this.linkDrag.src = "https://seogurusnyc.com/wp-content/uploads/2016/12/link-1.png"; + this.linkDrag.style.width = "20px"; + this.linkDrag.style.height = "20px"; + this.linkDrag.style.color = "white"; + this.linkDrag.style.background = "black"; + this.linkDrag.style.cssFloat = "left"; + this.linkDrag.onpointerdown = (e: PointerEvent) => { let dragData = new DragManager.LinkDragData(this.editorProps.Document); dragData.dontClearTextBox = true; - DragManager.StartLinkDrag(this.linkEditor!, dragData, e.clientX, e.clientY, + DragManager.StartLinkDrag(this.linkDrag!, dragData, e.clientX, e.clientY, { handlers: { dragComplete: action(() => { @@ -216,9 +223,9 @@ export class TooltipTextMenu { hideSource: false }) }; + this.linkEditor.appendChild(this.linkDrag); this.linkEditor.appendChild(this.linkText); this.linkEditor.appendChild(linkBtn); - this.linkEditor.appendChild(linkDrag) this.tooltip.appendChild(this.linkEditor); } diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index e3eb034fa..85ddadd64 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -5,7 +5,6 @@ import { DragLinksAsDocuments, DragManager } from "../util/DragManager"; import { SelectionManager } from "../util/SelectionManager"; import { undoBatch } from "../util/UndoManager"; import './DocumentDecorations.scss'; -import { MainOverlayTextBox } from "./MainOverlayTextBox"; import { DocumentView, PositionDocument } from "./nodes/DocumentView"; import { LinkMenu } from "./nodes/LinkMenu"; import { TemplateMenu } from "./TemplateMenu"; @@ -25,11 +24,9 @@ import { faLink } from '@fortawesome/free-solid-svg-icons'; import { library } from '@fortawesome/fontawesome-svg-core'; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { MINIMIZED_ICON_SIZE } from "../views/globalCssVariables.scss"; -import { CollectionFreeFormView } from "./collections/collectionFreeForm/CollectionFreeFormView"; import { CollectionView } from "./collections/CollectionView"; -import { createCipher } from "crypto"; -import { FieldView } from "./nodes/FieldView"; import { DocumentManager } from "../util/DocumentManager"; +import { FormattedTextBox } from "./nodes/FormattedTextBox"; library.add(faLink); @@ -328,6 +325,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> let selDoc = SelectionManager.SelectedDocuments()[0]; let container = selDoc.props.ContainingCollectionView ? selDoc.props.ContainingCollectionView.props.Document.proto : undefined; let dragData = new DragManager.LinkDragData(selDoc.props.Document, container ? [container] : []); + FormattedTextBox.InputBoxOverlay = undefined; DragManager.StartLinkDrag(this._linkerButton.current, dragData, e.pageX, e.pageY, { handlers: { dragComplete: action(emptyFunction), @@ -410,7 +408,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> break; } - MainOverlayTextBox.Instance.SetTextDoc(); + FormattedTextBox.InputBoxOverlay = undefined; SelectionManager.SelectedDocuments().forEach(element => { const rect = element.ContentDiv ? element.ContentDiv.getBoundingClientRect() : new DOMRect(); diff --git a/src/client/views/MainOverlayTextBox.tsx b/src/client/views/MainOverlayTextBox.tsx index 3b75c248a..91f626737 100644 --- a/src/client/views/MainOverlayTextBox.tsx +++ b/src/client/views/MainOverlayTextBox.tsx @@ -1,16 +1,12 @@ -import { action, observable, trace } from 'mobx'; +import { action, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; -import "normalize.css"; import * as React from 'react'; import { emptyFunction, returnTrue, returnZero } from '../../Utils'; -import '../northstar/model/ModelExtensions'; -import '../northstar/utils/Extensions'; import { DragManager } from '../util/DragManager'; import { Transform } from '../util/Transform'; +import "normalize.css"; import "./MainOverlayTextBox.scss"; import { FormattedTextBox } from './nodes/FormattedTextBox'; -import { Doc } from '../../new_fields/Doc'; -import { NumCast } from '../../new_fields/Types'; interface MainOverlayTextBoxProps { } @@ -18,8 +14,6 @@ interface MainOverlayTextBoxProps { @observer export class MainOverlayTextBox extends React.Component { public static Instance: MainOverlayTextBox; - @observable public TextDoc?: Doc = undefined; - public TextScroll: number = 0; @observable _textXf: () => Transform = () => Transform.Identity(); private _textFieldKey: string = "data"; private _textColor: string | null = null; @@ -30,15 +24,18 @@ export class MainOverlayTextBox extends React.Component super(props); this._textProxyDiv = React.createRef(); MainOverlayTextBox.Instance = this; + reaction(() => FormattedTextBox.InputBoxOverlay, + (box?: FormattedTextBox) => { + if (box) this.setTextDoc(box.props.fieldKey, box.CurrentDiv, box.props.ScreenToLocalTransform); + else this.setTextDoc(); + }); } @action - SetTextDoc(textDoc?: Doc, textFieldKey?: string, div?: HTMLDivElement, tx?: () => Transform) { + private setTextDoc(textFieldKey?: string, div?: HTMLDivElement, tx?: () => Transform) { if (this._textTargetDiv) { this._textTargetDiv.style.color = this._textColor; } - - this.TextDoc = textDoc; this._textFieldKey = textFieldKey!; this._textXf = tx ? tx : () => Transform.Identity(); this._textTargetDiv = div; @@ -46,15 +43,13 @@ export class MainOverlayTextBox extends React.Component if (div.parentElement && div.parentElement instanceof HTMLDivElement && div.parentElement.id === "screenSpace") this._textXf = () => Transform.Identity(); this._textColor = div.style.color; div.style.color = "transparent"; - this.TextScroll = div.scrollTop; } } @action textScroll = (e: React.UIEvent) => { if (this._textProxyDiv.current && this._textTargetDiv) { - this.TextScroll = (e as any)._targetInst.stateNode.scrollTop;// this._textProxyDiv.current.children[0].scrollTop; - this._textTargetDiv.scrollTop = this.TextScroll; + this._textTargetDiv.scrollTop = (e as any)._targetInst.stateNode.scrollTop; } } @@ -64,11 +59,12 @@ export class MainOverlayTextBox extends React.Component document.addEventListener('pointerup', this.textBoxUp); } } + @action textBoxMove = (e: PointerEvent) => { if (e.movementX > 1 || e.movementY > 1) { document.removeEventListener("pointermove", this.textBoxMove); document.removeEventListener('pointerup', this.textBoxUp); - let dragData = new DragManager.DocumentDragData([this.TextDoc!]); + let dragData = new DragManager.DocumentDragData(FormattedTextBox.InputBoxOverlay ? [FormattedTextBox.InputBoxOverlay.props.Document] : []); const [left, top] = this._textXf().inverse().transformPoint(0, 0); dragData.xOffset = e.clientX - left; dragData.yOffset = e.clientY - top; @@ -86,13 +82,13 @@ export class MainOverlayTextBox extends React.Component } render() { - if (this.TextDoc && this._textTargetDiv) { + if (FormattedTextBox.InputBoxOverlay && this._textTargetDiv) { let textRect = this._textTargetDiv.getBoundingClientRect(); let s = this._textXf().Scale; return
-
diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx index 16818affd..6dd0e5935 100644 --- a/src/client/views/collections/CollectionSchemaView.tsx +++ b/src/client/views/collections/CollectionSchemaView.tsx @@ -322,8 +322,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) { render() { library.add(faCog); library.add(faPlus); - //This can't just pass FieldValue to filter because filter passes other arguments to the passed in function, which end up as default values in FieldValue - const children = (this.children || []).filter(doc => FieldValue(doc)); + const children = this.children; return (
this.onDrop(e, {})} ref={this.createTarget}> diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 828ac880a..082692d8d 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -50,7 +50,7 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T) { get children() { //TODO tfs: This might not be what we want? //This linter error can't be fixed because of how js arguments work, so don't switch this to filter(FieldValue) - return Cast(this.props.Document[this.props.fieldKey], listSpec(Doc), []).filter(doc => FieldValue(doc)); + return Cast(this.props.Document[this.props.fieldKey], listSpec(Doc), []).filter(doc => FieldValue(doc)).map(doc => doc as Doc); } @action diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 797f94d5f..c1d149098 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -70,7 +70,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { } public getActiveDocuments = () => { const curPage = FieldValue(this.Document.curPage, -1); - return FieldValue(this.children, [] as Doc[]).filter(doc => { + return this.children.filter(doc => { var page = NumCast(doc.page, -1); return page === curPage || page === -1; }); @@ -169,7 +169,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { // if (!this.props.active()) { // return; // } - let childSelected = (this.children || []).filter(doc => doc).some(doc => { + let childSelected = this.children.some(doc => { var dv = DocumentManager.Instance.getDocumentView(doc); return dv && SelectionManager.IsSelected(dv) ? true : false; }); @@ -222,7 +222,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { } bringToFront = (doc: Doc) => { - const docs = (this.children || []); + const docs = this.children; docs.slice().sort((doc1, doc2) => { if (doc1 === doc) return 1; if (doc2 === doc) return -1; @@ -268,7 +268,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { @computed.struct get views() { let curPage = FieldValue(this.Document.curPage, -1); - let docviews = (this.children || []).filter(doc => doc).reduce((prev, doc) => { + let docviews = this.children.reduce((prev, doc) => { if (!(doc instanceof Doc)) return prev; var page = NumCast(doc.page, -1); if (page === curPage || page === -1) { diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx index 613c24fa4..cdc1bdc85 100644 --- a/src/client/views/nodes/FieldView.tsx +++ b/src/client/views/nodes/FieldView.tsx @@ -1,6 +1,6 @@ import React = require("react"); import { observer } from "mobx-react"; -import { computed } from "mobx"; +import { computed, observable } from "mobx"; import { FormattedTextBox } from "./FormattedTextBox"; import { ImageBox } from "./ImageBox"; import { VideoBox } from "./VideoBox"; diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 445a834ee..e7fb94777 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -1,29 +1,31 @@ -import { action, IReactionDisposer, reaction, trace, computed, _allowStateChangesInsideComputed } from "mobx"; +import { action, IReactionDisposer, observable, reaction } from "mobx"; +import { observer } from "mobx-react"; import { baseKeymap } from "prosemirror-commands"; import { history } from "prosemirror-history"; import { keymap } from "prosemirror-keymap"; import { EditorState, Plugin, Transaction } from "prosemirror-state"; import { EditorView } from "prosemirror-view"; +import { Doc, Field, HeightSym, Opt, WidthSym } from "../../../new_fields/Doc"; +import { RichTextField } from "../../../new_fields/RichTextField"; +import { createSchema, makeInterface } from "../../../new_fields/Schema"; +import { Cast, NumCast, StrCast } from "../../../new_fields/Types"; +import { DocServer } from "../../DocServer"; +import { DocumentManager } from "../../util/DocumentManager"; +import { DragManager } from "../../util/DragManager"; import buildKeymap from "../../util/ProsemirrorKeymap"; import { inpRules } from "../../util/RichTextRules"; -import { schema, ImageResizeView } from "../../util/RichTextSchema"; +import { ImageResizeView, schema } from "../../util/RichTextSchema"; +import { SelectionManager } from "../../util/SelectionManager"; import { TooltipLinkingMenu } from "../../util/TooltipLinkingMenu"; import { TooltipTextMenu } from "../../util/TooltipTextMenu"; +import { undoBatch, UndoManager } from "../../util/UndoManager"; import { ContextMenu } from "../../views/ContextMenu"; -import { MainOverlayTextBox } from "../MainOverlayTextBox"; +import { CollectionDockingView } from "../collections/CollectionDockingView"; +import { DocComponent } from "../DocComponent"; +import { InkingControl } from "../InkingControl"; import { FieldView, FieldViewProps } from "./FieldView"; import "./FormattedTextBox.scss"; import React = require("react"); -import { SelectionManager } from "../../util/SelectionManager"; -import { DocComponent } from "../DocComponent"; -import { createSchema, makeInterface } from "../../../new_fields/Schema"; -import { Opt, Doc, WidthSym, HeightSym } from "../../../new_fields/Doc"; -import { observer } from "mobx-react"; -import { InkingControl } from "../InkingControl"; -import { StrCast, Cast, NumCast, BoolCast } from "../../../new_fields/Types"; -import { RichTextField } from "../../../new_fields/RichTextField"; -import { Id } from "../../../new_fields/RefField"; -import { UndoManager } from "../../util/UndoManager"; // FormattedTextBox: Displays an editable plain text node that maps to a specified Key of a Document // @@ -62,15 +64,23 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe private _proseRef: React.RefObject; private _editorView: Opt; private _gotDown: boolean = false; + private _dropDisposer?: DragManager.DragDropDisposer; private _reactionDisposer: Opt; private _inputReactionDisposer: Opt; private _proxyReactionDisposer: Opt; + public get CurrentDiv(): HTMLDivElement { return this._ref.current!; } + + @observable public static InputBoxOverlay?: FormattedTextBox = undefined; + public static InputBoxOverlayScroll: number = 0; constructor(props: FieldViewProps) { super(props); this._ref = React.createRef(); this._proseRef = React.createRef(); + if (this.props.isOverlay) { + DragManager.StartDragFunctions.push(() => FormattedTextBox.InputBoxOverlay = undefined); + } } _applyingChange: boolean = false; @@ -94,7 +104,27 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe } } + @undoBatch + @action + drop = async (e: Event, de: DragManager.DropEvent) => { + if (de.data instanceof DragManager.LinkDragData) { + let sourceDoc = de.data.linkSourceDocument; + let destDoc = this.props.Document; + + const protoDest = destDoc.proto; + const protoSrc = sourceDoc.proto; + Doc.MakeLink(protoSrc ? protoSrc : sourceDoc, protoDest ? protoDest : destDoc); + de.data.droppedDocuments.push(destDoc); + e.stopPropagation(); + } + } + componentDidMount() { + if (this._ref.current) { + this._dropDisposer = DragManager.MakeDropTarget(this._ref.current, { + handlers: { drop: this.drop.bind(this) } + }); + } const config = { schema, inpRules, //these currently don't do anything, but could eventually be helpful @@ -117,7 +147,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe }; if (this.props.isOverlay) { - this._inputReactionDisposer = reaction(() => MainOverlayTextBox.Instance.TextDoc && MainOverlayTextBox.Instance.TextDoc[Id], + this._inputReactionDisposer = reaction(() => FormattedTextBox.InputBoxOverlay, () => { if (this._editorView) { this._editorView.destroy(); @@ -127,7 +157,12 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe ); } else { this._proxyReactionDisposer = reaction(() => this.props.isSelected(), - () => this.props.isSelected() && MainOverlayTextBox.Instance.SetTextDoc(this.props.Document, this.props.fieldKey, this._ref.current!, this.props.ScreenToLocalTransform)); + () => { + if (this.props.isSelected()) { + FormattedTextBox.InputBoxOverlay = this; + FormattedTextBox.InputBoxOverlayScroll = this._ref.current!.scrollTop; + } + }); } @@ -178,6 +213,9 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe if (this._proxyReactionDisposer) { this._proxyReactionDisposer(); } + if (this._dropDisposer) { + this._dropDisposer(); + } } onPointerDown = (e: React.PointerEvent): void => { @@ -186,6 +224,24 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe if (this._toolTipTextMenu && this._toolTipTextMenu.tooltip) this._toolTipTextMenu.tooltip.style.opacity = "0"; } + if (e.button === 0 && ((!this.props.isSelected() && !e.ctrlKey) || (this.props.isSelected() && e.ctrlKey)) && !e.metaKey) { + if (e.target && (e.target as any).href) { + let href = (e.target as any).href; + if (href.indexOf(DocServer.prepend("/doc/")) === 0) { + let docid = href.replace(DocServer.prepend("/doc/"), ""); + DocServer.GetRefField(docid).then(action((f: Opt) => { + if (f instanceof Doc) { + if (DocumentManager.Instance.getDocumentView(f)) + DocumentManager.Instance.getDocumentView(f)!.props.focus(f); + else CollectionDockingView.Instance.AddRightSplit(f); + } + })); + } + e.stopPropagation(); + e.preventDefault(); + } + + } if (e.button === 2 || (e.button === 0 && e.ctrlKey)) { this._gotDown = true; e.preventDefault(); @@ -199,12 +255,13 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe } } + @action onFocused = (e: React.FocusEvent): void => { if (!this.props.isOverlay) { - MainOverlayTextBox.Instance.SetTextDoc(this.props.Document, this.props.fieldKey, this._ref.current!, this.props.ScreenToLocalTransform); + FormattedTextBox.InputBoxOverlay = this; } else { if (this._proseRef.current) { - this._proseRef.current.scrollTop = MainOverlayTextBox.Instance.TextScroll; + this._proseRef.current.scrollTop = FormattedTextBox.InputBoxOverlayScroll; } } } -- cgit v1.2.3-70-g09d2 From b29a0d1cef60b55f609fcd94ad38232ae557e681 Mon Sep 17 00:00:00 2001 From: Tyler Schicke Date: Thu, 16 May 2019 18:32:57 -0400 Subject: Fixed linter errors --- src/client/goldenLayout.d.ts | 3 +++ src/client/northstar/dash-fields/HistogramField.ts | 2 +- src/client/northstar/model/ModelHelpers.ts | 9 +++---- src/client/util/DragManager.ts | 2 +- src/client/util/RichTextSchema.tsx | 16 +++++------ src/client/util/TooltipTextMenu.tsx | 13 ++++----- src/client/views/DocumentDecorations.tsx | 31 +++++++++++----------- src/client/views/PresentationView.tsx | 4 +-- src/client/views/TemplateMenu.tsx | 4 +-- .../views/collections/CollectionDockingView.tsx | 5 ++-- .../views/collections/CollectionSchemaView.tsx | 10 +++---- .../views/collections/CollectionTreeView.tsx | 9 ++++--- .../collections/collectionFreeForm/MarqueeView.tsx | 13 ++++----- .../views/nodes/CollectionFreeFormDocumentView.tsx | 2 +- src/client/views/nodes/DocumentView.tsx | 2 +- src/client/views/nodes/FormattedTextBox.tsx | 8 +++--- src/client/views/nodes/ImageBox.tsx | 2 +- src/client/views/nodes/KeyValueBox.tsx | 2 +- src/client/views/nodes/KeyValuePair.tsx | 3 ++- src/client/views/nodes/VideoBox.tsx | 22 +++++++-------- src/new_fields/CursorField.ts | 6 ++--- src/new_fields/Doc.ts | 4 +-- src/new_fields/ObjectField.ts | 2 +- .../authentication/models/current_user_utils.ts | 2 +- 24 files changed, 91 insertions(+), 85 deletions(-) create mode 100644 src/client/goldenLayout.d.ts (limited to 'src/client/util/TooltipTextMenu.tsx') diff --git a/src/client/goldenLayout.d.ts b/src/client/goldenLayout.d.ts new file mode 100644 index 000000000..b50240563 --- /dev/null +++ b/src/client/goldenLayout.d.ts @@ -0,0 +1,3 @@ + +declare const GoldenLayout: any; +export = GoldenLayout; \ No newline at end of file diff --git a/src/client/northstar/dash-fields/HistogramField.ts b/src/client/northstar/dash-fields/HistogramField.ts index aabc77bb2..1ee2189b9 100644 --- a/src/client/northstar/dash-fields/HistogramField.ts +++ b/src/client/northstar/dash-fields/HistogramField.ts @@ -52,7 +52,7 @@ export class HistogramField extends ObjectField { [Copy]() { let y = this.HistoOp; - let z = this.HistoOp["Copy"]; + let z = this.HistoOp.Copy; return new HistogramField(HistogramOperation.Duplicate(this.HistoOp)); } } \ No newline at end of file diff --git a/src/client/northstar/model/ModelHelpers.ts b/src/client/northstar/model/ModelHelpers.ts index 80bb71224..88e6e72b8 100644 --- a/src/client/northstar/model/ModelHelpers.ts +++ b/src/client/northstar/model/ModelHelpers.ts @@ -32,12 +32,9 @@ export class ModelHelpers { public static GetAggregateParametersIndex(histogramResult: HistogramResult, aggParameters?: AggregateParameters): number { return Array.from(histogramResult.aggregateParameters!).findIndex((value, i, set) => { - if (set[i] instanceof CountAggregateParameters && value instanceof CountAggregateParameters) - return true; - if (set[i] instanceof MarginAggregateParameters && value instanceof MarginAggregateParameters) - return true; - if (set[i] instanceof SumAggregateParameters && value instanceof SumAggregateParameters) - return true; + if (set[i] instanceof CountAggregateParameters && value instanceof CountAggregateParameters) return true; + if (set[i] instanceof MarginAggregateParameters && value instanceof MarginAggregateParameters) return true; + if (set[i] instanceof SumAggregateParameters && value instanceof SumAggregateParameters) return true; return false; }); } diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index 26da34e67..05eb5c38a 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -41,7 +41,7 @@ export function SetupDrag(_reference: React.RefObject, docFunc: () export async function DragLinksAsDocuments(dragEle: HTMLElement, x: number, y: number, sourceDoc: Doc) { let srcTarg = sourceDoc.proto; let draggedDocs: Doc[] = []; - let draggedFromDocs: Doc[] = [] + let draggedFromDocs: Doc[] = []; if (srcTarg) { let linkToDocs = await DocListCastAsync(srcTarg.linkedToDocs); let linkFromDocs = await DocListCastAsync(srcTarg.linkedFromDocs); diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx index c0e6f7899..3e3e98206 100644 --- a/src/client/util/RichTextSchema.tsx +++ b/src/client/util/RichTextSchema.tsx @@ -97,13 +97,13 @@ export const nodes: { [index: string]: NodeSpec } = { title: dom.getAttribute("title"), alt: dom.getAttribute("alt"), width: Math.min(100, Number(dom.getAttribute("width"))), - } + }; } }], // TODO if we don't define toDom, something weird happens: dragging the image will not move it but clone it. Why? toDOM(node) { - const attrs = { style: `width: ${node.attrs.width}` } - return ["img", { ...node.attrs, ...attrs }] + const attrs = { style: `width: ${node.attrs.width}` }; + return ["img", { ...node.attrs, ...attrs }]; } }, @@ -375,7 +375,7 @@ export class ImageResizeView { const currentX = e.pageX; const diffInPx = currentX - startX; self._outer.style.width = `${startWidth + diffInPx}`; - } + }; const onpointerup = () => { document.removeEventListener("pointermove", onpointermove); @@ -384,11 +384,11 @@ export class ImageResizeView { view.state.tr.setNodeMarkup(getPos(), null, { src: node.attrs.src, width: self._outer.style.width }) .setSelection(view.state.selection)); - } + }; - document.addEventListener("pointermove", onpointermove) - document.addEventListener("pointerup", onpointerup) - } + document.addEventListener("pointermove", onpointermove); + document.addEventListener("pointerup", onpointerup); + }; this._outer.appendChild(this._handle); this._outer.appendChild(this._img); diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx index 6eb654319..223921428 100644 --- a/src/client/util/TooltipTextMenu.tsx +++ b/src/client/util/TooltipTextMenu.tsx @@ -175,7 +175,7 @@ export class TooltipTextMenu { this.linkText.style.width = "150px"; this.linkText.style.overflow = "hidden"; this.linkText.style.color = "white"; - this.linkText.onpointerdown = (e: PointerEvent) => { e.stopPropagation(); } + this.linkText.onpointerdown = (e: PointerEvent) => { e.stopPropagation(); }; let linkBtn = document.createElement("div"); linkBtn.textContent = ">>"; linkBtn.style.width = "20px"; @@ -192,8 +192,9 @@ export class TooltipTextMenu { let docid = href.replace(DocServer.prepend("/doc/"), ""); DocServer.GetRefField(docid).then(action((f: Opt) => { if (f instanceof Doc) { - if (DocumentManager.Instance.getDocumentView(f)) + if (DocumentManager.Instance.getDocumentView(f)) { DocumentManager.Instance.getDocumentView(f)!.props.focus(f); + } else CollectionDockingView.Instance.AddRightSplit(f); } })); @@ -201,7 +202,7 @@ export class TooltipTextMenu { e.stopPropagation(); e.preventDefault(); } - } + }; this.linkDrag = document.createElement("img"); this.linkDrag.src = "https://seogurusnyc.com/wp-content/uploads/2016/12/link-1.png"; this.linkDrag.style.width = "20px"; @@ -216,12 +217,12 @@ export class TooltipTextMenu { { handlers: { dragComplete: action(() => { - let m = dragData.droppedDocuments as Doc[]; + let m = dragData.droppedDocuments; this.makeLink(DocServer.prepend("/doc/" + m[0][Id])); }), }, hideSource: false - }) + }); }; this.linkEditor.appendChild(this.linkDrag); this.linkEditor.appendChild(this.linkText); @@ -239,7 +240,7 @@ export class TooltipTextMenu { e.stopPropagation(); e.preventDefault(); } - } + }; this.tooltip.appendChild(this.linkEditor); } diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index b2c65a31f..7083b1003 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -250,22 +250,21 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> selectedDocs[0].props.removeDocument && selectedDocs[0].props.removeDocument(this._iconDoc); } if (!this._removeIcon) { - if (selectedDocs.length === 1) + if (selectedDocs.length === 1) { this.getIconDoc(selectedDocs[0]).then(icon => selectedDocs[0].props.toggleMinimized()); - else - if (Math.abs(e.pageX - this._downX) < Utils.DRAG_THRESHOLD && - Math.abs(e.pageY - this._downY) < Utils.DRAG_THRESHOLD) { - let docViews = SelectionManager.ViewsSortedVertically(); - let topDocView = docViews[0]; - let ind = topDocView.templates.indexOf(Templates.Bullet.Layout); - if (ind !== -1) { - topDocView.templates.splice(ind, 1); - topDocView.props.Document.subBulletDocs = undefined; - } else { - topDocView.addTemplate(Templates.Bullet); - topDocView.props.Document.subBulletDocs = new List(docViews.filter(v => v !== topDocView).map(v => v.props.Document.proto!)); - } + } else if (Math.abs(e.pageX - this._downX) < Utils.DRAG_THRESHOLD && + Math.abs(e.pageY - this._downY) < Utils.DRAG_THRESHOLD) { + let docViews = SelectionManager.ViewsSortedVertically(); + let topDocView = docViews[0]; + let ind = topDocView.templates.indexOf(Templates.Bullet.Layout); + if (ind !== -1) { + topDocView.templates.splice(ind, 1); + topDocView.props.Document.subBulletDocs = undefined; + } else { + topDocView.addTemplate(Templates.Bullet); + topDocView.props.Document.subBulletDocs = new List(docViews.filter(v => v !== topDocView).map(v => v.props.Document.proto!)); } + } } this._removeIcon = false; } @@ -537,9 +536,9 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> if (temp !== Templates.Bullet.Layout || i === 0) { res.push(temp); } - }) + }); } - return res + return res; }, [] as string[]); let checked = false; docTemps.forEach(temp => { diff --git a/src/client/views/PresentationView.tsx b/src/client/views/PresentationView.tsx index 098e725c7..7d0dc2913 100644 --- a/src/client/views/PresentationView.tsx +++ b/src/client/views/PresentationView.tsx @@ -1,7 +1,7 @@ import { observer } from "mobx-react"; -import React = require("react") +import React = require("react"); import { observable, action, runInAction, reaction } from "mobx"; -import "./PresentationView.scss" +import "./PresentationView.scss"; import "./Main.tsx"; import { DocumentManager } from "../util/DocumentManager"; import { Utils } from "../../Utils"; diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx index cfe1b0663..e5b679e24 100644 --- a/src/client/views/TemplateMenu.tsx +++ b/src/client/views/TemplateMenu.tsx @@ -43,7 +43,7 @@ export class TemplateMenu extends React.Component { @action toggleTemplate = (event: React.ChangeEvent, template: Template): void => { if (event.target.checked) { - if (template.Name == "Bullet") { + if (template.Name === "Bullet") { let topDocView = this.props.docs[0]; topDocView.addTemplate(template); topDocView.props.Document.subBulletDocs = new List(this.props.docs.filter(v => v !== topDocView).map(v => v.props.Document.proto!)); @@ -52,7 +52,7 @@ export class TemplateMenu extends React.Component { } this.props.templates.set(template, true); } else { - if (template.Name == "Bullet") { + if (template.Name === "Bullet") { let topDocView = this.props.docs[0]; topDocView.removeTemplate(template); topDocView.props.Document.subBulletDocs = undefined; diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 58f1e33a1..deec64225 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -83,7 +83,7 @@ export class CollectionDockingView extends React.Component tab.config.component === "DocumentFrameRenderer").some((tab: any, j: number) => { if (Doc.AreProtosEqual(DocumentManager.Instance.getDocumentViewById(tab.config.props.documentId)!.Document, document)) { child.contentItems[j].remove(); @@ -94,8 +94,9 @@ export class CollectionDockingView extends React.Component doc) { let fieldContentView = ; let reference = React.createRef(); let onItemDown = (e: React.PointerEvent) => - (this.props.CollectionView!.props.isSelected() ? + (this.props.CollectionView.props.isSelected() ? SetupDrag(reference, () => props.Document, this.props.moveDocument)(e) : undefined); let applyToDoc = (doc: Doc, run: (args?: { [name: string]: any }) => any) => { const res = run({ this: doc }); @@ -127,7 +127,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) { } const run = script.run; //TODO This should be able to be refactored to compile the script once - const val = await DocListCastAsync(this.props.Document[this.props.fieldKey]) + const val = await DocListCastAsync(this.props.Document[this.props.fieldKey]); val && val.forEach(doc => applyToDoc(doc, run)); }}> @@ -230,14 +230,14 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) { DocListCast(this.props.Document.data).map(doc => { csv += self.columns.reduce((val, col) => val + (doc[col] ? doc[col]!.toString() : "") + ",", ""); csv = csv.substr(0, csv.length - 1) + "\n"; - }) + }); csv.substring(0, csv.length - 1); let dbName = StrCast(this.props.Document.title); let res = await Gateway.Instance.PostSchema(csv, dbName); if (self.props.CollectionView.props.addDocument) { let schemaDoc = await Docs.DBDocument("https://www.cs.brown.edu/" + dbName, { title: dbName }); if (schemaDoc) { - self.props.CollectionView.props.addDocument(schemaDoc, false); + self.props.CollectionView.props.addDocument(schemaDoc, false); } } } @@ -263,7 +263,7 @@ export class CollectionSchemaView extends CollectionSubView(doc => doc) { get previewDocument(): Doc | undefined { const children = DocListCast(this.props.Document[this.props.fieldKey]); const selected = children.length > this._selectedIndex ? FieldValue(children[this._selectedIndex]) : undefined; - return selected ? (this.previewScript && this.previewScript != "this" ? FieldValue(Cast(selected[this.previewScript], Doc)) : selected) : undefined; + return selected ? (this.previewScript && this.previewScript !== "this" ? FieldValue(Cast(selected[this.previewScript], Doc)) : selected) : undefined; } get tableWidth() { return (this.props.PanelWidth() - 2 * this.borderWidth - this.DIVIDER_WIDTH) * (1 - this.splitPercentage / 100); } get previewRegionHeight() { return this.props.PanelHeight() - 2 * this.borderWidth; } diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 70c09d97c..6acef434e 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -56,7 +56,7 @@ class TreeView extends React.Component { } else { CollectionDockingView.Instance.AddRightSplit(this.props.document); } - }; + } get children() { return Cast(this.props.document.data, listSpec(Doc), []); // bcz: needed? .filter(doc => FieldValue(doc)); @@ -184,8 +184,9 @@ class TreeView extends React.Component { {TreeView.GetChildElements(doc instanceof Doc ? [doc] : docList, key !== "data", (doc: Doc) => this.remove(doc, key), this.move, this.props.dropAction)}
); - } else + } else { bulletType = BulletType.Collapsed; + } } }); return
{
; } public static GetChildElements(docs: Doc[], allowMinimized: boolean, remove: ((doc: Doc) => void), move: DragManager.MoveFunction, dropAction: dropActionType) { - return docs.filter(child => child instanceof Doc && !child.excludeFromLibrary && (allowMinimized || !child.isMinimized)).filter(doc => FieldValue(doc)).map(child => - ); + return docs.filter(child => !child.excludeFromLibrary && (allowMinimized || !child.isMinimized)).map(child => + ); } } diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 12edb2c2a..c3c4115b8 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -63,7 +63,7 @@ export class MarqueeView extends React.Component e.preventDefault(); (async () => { let text: string = await navigator.clipboard.readText(); - let ns = text.split("\n").filter(t => t.trim() != "\r" && t.trim() != ""); + let ns = text.split("\n").filter(t => t.trim() !== "\r" && t.trim() !== ""); for (let i = 0; i < ns.length - 1; i++) { while (!(ns[i].trim() === "" || ns[i].endsWith("-\r") || ns[i].endsWith("-") || ns[i].endsWith(";\r") || ns[i].endsWith(";") || @@ -80,7 +80,7 @@ export class MarqueeView extends React.Component let newBox = Docs.TextDocument({ width: 200, height: 35, x: x + indent / 3 * 10, y: y, documentText: "@@@" + line, title: line }); this.props.addDocument(newBox, false); y += 40 * this.props.getTransform().Scale; - }) + }); })(); } else if (e.key === "b" && e.ctrlKey) { //heuristically converts pasted text into a table. @@ -93,9 +93,10 @@ export class MarqueeView extends React.Component e.preventDefault(); (async () => { let text: string = await navigator.clipboard.readText(); - let ns = text.split("\n").filter(t => t.trim() != "\r" && t.trim() != ""); - while (ns.length > 0 && ns[0].split("\t").length < 2) + let ns = text.split("\n").filter(t => t.trim() !== "\r" && t.trim() !== ""); + while (ns.length > 0 && ns[0].split("\t").length < 2) { ns.splice(0, 1); + } if (ns.length > 0) { let columns = ns[0].split("\t"); let docList: Doc[] = []; @@ -109,7 +110,7 @@ export class MarqueeView extends React.Component let doc = new Doc(); columns.forEach((col, i) => doc[columns[i]] = (values.length > i ? ((values[i].indexOf(Number(values[i]).toString()) !== -1) ? Number(values[i]) : values[i]) : undefined)); if (groupAttr) { - doc["_group"] = groupAttr; + doc._group = groupAttr; } doc.title = i.toString(); docList.push(doc); @@ -284,7 +285,7 @@ export class MarqueeView extends React.Component // summarizedDoc.isIconAnimating = new List([scrpt[0], scrpt[1], maxx, maxy, maxw, maxh, Date.now(), 0]); // }); this.props.addLiveTextDocument(summary); - }) + }); } else { this.props.addDocument(newCollection, false); diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 7c7ca9e25..d4f660b3f 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -149,7 +149,7 @@ export class CollectionFreeFormDocumentView extends DocComponent([scrpt[0], scrpt[1], Date.now(), isMinimized ? 1 : 0]) + maximizedDoc.isIconAnimating = new List([scrpt[0], scrpt[1], Date.now(), isMinimized ? 1 : 0]); } } }); diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index cf8bcbb42..428dd9b36 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -244,7 +244,7 @@ export class DocumentView extends DocComponent(Docu const protoDest = destDoc.proto; const protoSrc = sourceDoc.proto; - if (de.mods == "Control") { + if (de.mods === "Control") { let src = protoSrc ? protoSrc : sourceDoc; let dst = protoDest ? protoDest : destDoc; dst.data = src; diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index f24d4ae88..f30022508 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -184,7 +184,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe 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); } } }); let text = StrCast(this.props.Document.documentText); @@ -232,9 +232,11 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe let docid = href.replace(DocServer.prepend("/doc/"), "").split("?")[0]; DocServer.GetRefField(docid).then(action((f: Opt) => { if (f instanceof Doc) { - if (DocumentManager.Instance.getDocumentView(f)) + if (DocumentManager.Instance.getDocumentView(f)) { DocumentManager.Instance.getDocumentView(f)!.props.focus(f); - else CollectionDockingView.Instance.AddRightSplit(f); + } else { + CollectionDockingView.Instance.AddRightSplit(f); + } } })); } diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 6472ae711..3cc60a6c5 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -165,7 +165,7 @@ export class ImageBox extends DocComponent(ImageD else if (field instanceof List) paths = field.filter(val => val instanceof ImageField).map(p => (p as ImageField).url.href); let nativeWidth = FieldValue(this.Document.nativeWidth, (this.props.PanelWidth as any) as string ? Number((this.props.PanelWidth as any) as string) : 50); let interactive = InkingControl.Instance.selectedTool ? "" : "-interactive"; - let id = this.props.id; // bcz: used to set id = "isExpander" in templates.tsx + let id = (this.props as any).id; // bcz: used to set id = "isExpander" in templates.tsx return (
{ @observable private _keyInput: string = ""; @observable private _valueInput: string = ""; @computed get splitPercentage() { return NumCast(this.props.Document.schemaSplitPercentage, 50); } - get fieldDocToLayout() { return this.props.fieldKey ? FieldValue(Cast(this.props.Document[this.props.fieldKey], Doc)) : this.props.Document } + get fieldDocToLayout() { return this.props.fieldKey ? FieldValue(Cast(this.props.Document[this.props.fieldKey], Doc)) : this.props.Document; } constructor(props: FieldViewProps) { super(props); diff --git a/src/client/views/nodes/KeyValuePair.tsx b/src/client/views/nodes/KeyValuePair.tsx index 5de660d57..4f7919f50 100644 --- a/src/client/views/nodes/KeyValuePair.tsx +++ b/src/client/views/nodes/KeyValuePair.tsx @@ -46,8 +46,9 @@ export class KeyValuePair extends React.Component {
, + ,
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index d4f660b3f..001ce3095 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -205,11 +205,12 @@ export class CollectionFreeFormDocumentView extends DocComponent(Docu let sourceDoc = de.data.linkSourceDocument; let destDoc = this.props.Document; - const protoDest = destDoc.proto; - const protoSrc = sourceDoc.proto; - if (de.mods === "Control") { + if (de.mods === "AltKey") { + const protoDest = destDoc.proto; + const protoSrc = sourceDoc.proto; let src = protoSrc ? protoSrc : sourceDoc; let dst = protoDest ? protoDest : destDoc; - dst.data = src; + dst.data = (src.data! as ObjectField)[Copy](); dst.nativeWidth = src.nativeWidth; dst.nativeHeight = src.nativeHeight; } else { - Doc.MakeLink(protoSrc ? protoSrc : sourceDoc, protoDest ? protoDest : destDoc); + Doc.MakeLink(sourceDoc, destDoc); de.data.droppedDocuments.push(destDoc); } e.stopPropagation(); diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index f30022508..bf98fb40b 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -111,9 +111,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe let sourceDoc = de.data.linkSourceDocument; let destDoc = this.props.Document; - const protoDest = destDoc.proto; - const protoSrc = sourceDoc.proto; - Doc.MakeLink(protoSrc ? protoSrc : sourceDoc, protoDest ? protoDest : destDoc); + Doc.MakeLink(sourceDoc, destDoc); de.data.droppedDocuments.push(destDoc); e.stopPropagation(); } diff --git a/src/client/views/nodes/LinkBox.tsx b/src/client/views/nodes/LinkBox.tsx index 611cb66b6..68b692aad 100644 --- a/src/client/views/nodes/LinkBox.tsx +++ b/src/client/views/nodes/LinkBox.tsx @@ -31,7 +31,7 @@ export class LinkBox extends React.Component { @undoBatch onViewButtonPressed = async (e: React.PointerEvent): Promise => { e.stopPropagation(); - DocumentManager.Instance.jumpToDocument(this.props.pairedDoc); + DocumentManager.Instance.jumpToDocument(this.props.pairedDoc, e.altKey); } onEditButtonPressed = (e: React.PointerEvent): void => { diff --git a/src/client/views/nodes/LinkMenu.tsx b/src/client/views/nodes/LinkMenu.tsx index 11117122d..4cf798249 100644 --- a/src/client/views/nodes/LinkMenu.tsx +++ b/src/client/views/nodes/LinkMenu.tsx @@ -6,8 +6,7 @@ import { LinkEditor } from "./LinkEditor"; import './LinkMenu.scss'; import React = require("react"); import { Doc, DocListCast } from "../../../new_fields/Doc"; -import { Cast, FieldValue } from "../../../new_fields/Types"; -import { listSpec } from "../../../new_fields/Schema"; +import { Cast, FieldValue, StrCast } from "../../../new_fields/Types"; import { Id } from "../../../new_fields/RefField"; interface Props { @@ -24,7 +23,7 @@ export class LinkMenu extends React.Component { return links.map(link => { let doc = FieldValue(Cast(link[key], Doc)); if (doc) { - return this._editingLink = link)} type={type} />; + return this._editingLink = link)} type={type} />; } }); } diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index c898f697b..ad3b880cd 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -216,6 +216,8 @@ export namespace Doc { } export function MakeLink(source: Doc, target: Doc) { + let protoSrc = source.proto ? source.proto : source; + let protoTarg = target.proto ? target.proto : target; UndoManager.RunInBatch(() => { let linkDoc = Docs.TextDocument({ width: 100, height: 30, borderRounding: -1 }); //let linkDoc = new Doc; @@ -226,15 +228,15 @@ export namespace Doc { linkDoc.proto!.linkedTo = target; linkDoc.proto!.linkedFrom = source; - let linkedFrom = Cast(target.linkedFromDocs, listSpec(Doc)); + let linkedFrom = Cast(protoTarg.linkedFromDocs, listSpec(Doc)); if (!linkedFrom) { - target.linkedFromDocs = linkedFrom = new List(); + protoTarg.linkedFromDocs = linkedFrom = new List(); } linkedFrom.push(linkDoc); - let linkedTo = Cast(source.linkedToDocs, listSpec(Doc)); + let linkedTo = Cast(protoSrc.linkedToDocs, listSpec(Doc)); if (!linkedTo) { - source.linkedToDocs = linkedTo = new List(); + protoSrc.linkedToDocs = linkedTo = new List(); } linkedTo.push(linkDoc); return linkDoc; -- cgit v1.2.3-70-g09d2