diff options
author | Tyler Schicke <tyler_schicke@brown.edu> | 2019-04-05 22:12:11 -0400 |
---|---|---|
committer | Tyler Schicke <tyler_schicke@brown.edu> | 2019-04-05 22:12:11 -0400 |
commit | 4bc7e87cf1de3a9e80765bed6c547dc9cd8c4ba5 (patch) | |
tree | 9d99a05680845e0a41c3a3d77d4d41b99455cca9 /src | |
parent | 0403ee1f31d3f127a44aaabdfd21785d7efa6430 (diff) | |
parent | 1dd49a9659df6d4f449193eb7dbffeb56e5063b8 (diff) |
Merge branch 'master' of github-tsch-brown:browngraphicslab/Dash-Web into propsRefactor
Diffstat (limited to 'src')
-rw-r--r-- | src/client/northstar/dash-nodes/HistogramBox.scss | 5 | ||||
-rw-r--r-- | src/client/northstar/dash-nodes/HistogramBox.tsx | 2 | ||||
-rw-r--r-- | src/client/northstar/dash-nodes/HistogramBoxPrimitives.scss | 16 | ||||
-rw-r--r-- | src/client/northstar/dash-nodes/HistogramBoxPrimitives.tsx | 81 | ||||
-rw-r--r-- | src/client/util/DragManager.ts | 95 | ||||
-rw-r--r-- | src/client/util/TooltipTextMenu.tsx | 228 | ||||
-rw-r--r-- | src/client/views/DocumentDecorations.scss | 1 | ||||
-rw-r--r-- | src/client/views/DocumentDecorations.tsx | 6 | ||||
-rw-r--r-- | src/client/views/Main.tsx | 3 | ||||
-rw-r--r-- | src/client/views/collections/CollectionDockingView.tsx | 2 | ||||
-rw-r--r-- | src/client/views/collections/CollectionViewBase.tsx | 6 | ||||
-rw-r--r-- | src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx | 55 | ||||
-rw-r--r-- | src/client/views/nodes/DocumentView.tsx | 4 | ||||
-rw-r--r-- | src/client/views/nodes/PDFBox.tsx | 4 | ||||
-rw-r--r-- | src/server/public/files/upload_e72669595eae4384a2a32196496f4f05.pdf | bin | 548616 -> 0 bytes |
15 files changed, 252 insertions, 256 deletions
diff --git a/src/client/northstar/dash-nodes/HistogramBox.scss b/src/client/northstar/dash-nodes/HistogramBox.scss index 94da36e29..e899cf15e 100644 --- a/src/client/northstar/dash-nodes/HistogramBox.scss +++ b/src/client/northstar/dash-nodes/HistogramBox.scss @@ -29,9 +29,10 @@ .histogrambox-yaxislabel-text { position:absolute; left:0; - transform-origin: left; + width: 1000px; + transform-origin: 10px 10px; transform: rotate(-90deg); - text-align: center; + text-align: left; font-size: 14; font-weight: bold; bottom: calc(50% - 25px); diff --git a/src/client/northstar/dash-nodes/HistogramBox.tsx b/src/client/northstar/dash-nodes/HistogramBox.tsx index c9658d741..ec9413649 100644 --- a/src/client/northstar/dash-nodes/HistogramBox.tsx +++ b/src/client/northstar/dash-nodes/HistogramBox.tsx @@ -148,7 +148,7 @@ export class HistogramBox extends React.Component<FieldViewProps> { return ( <Measure onResize={(r: any) => runInAction(() => { this.PanelWidth = r.entry.width; this.PanelHeight = r.entry.height })}> {({ measureRef }) => - <div className="histogrambox-container" ref={measureRef} style={{ transform: `translate(${-w / 2}px, ${-h / 2}px)` }}> + <div className="histogrambox-container" ref={measureRef} style={{ transform: `translate(-50%, -50%)` }}> <div className="histogrambox-yaxislabel" onPointerDown={this.yLabelPointerDown} ref={this._dropYRef} > <span className="histogrambox-yaxislabel-text"> {labelY} diff --git a/src/client/northstar/dash-nodes/HistogramBoxPrimitives.scss b/src/client/northstar/dash-nodes/HistogramBoxPrimitives.scss index ce9edd65e..26203612a 100644 --- a/src/client/northstar/dash-nodes/HistogramBoxPrimitives.scss +++ b/src/client/northstar/dash-nodes/HistogramBoxPrimitives.scss @@ -4,10 +4,11 @@ } .histogramboxprimitives-border { border: 3px; - border-style: solid; - border-color: white; pointer-events: none; position: absolute; + fill:"transparent"; + stroke: white; + stroke-width: 1px; } .histogramboxprimitives-bar { position: absolute; @@ -23,8 +24,19 @@ width: 100%; height: 100%; } +.histogramboxprimitives-svgContainer { + position: absolute; + top:0; + left:0; + width:100%; + height: 100%; +} .histogramboxprimitives-line { position: absolute; background: darkGray; + stroke: darkGray; + stroke-width: 1px; + width:100%; + height:100%; opacity: 0.4; }
\ No newline at end of file diff --git a/src/client/northstar/dash-nodes/HistogramBoxPrimitives.tsx b/src/client/northstar/dash-nodes/HistogramBoxPrimitives.tsx index 66d31846c..a78703247 100644 --- a/src/client/northstar/dash-nodes/HistogramBoxPrimitives.tsx +++ b/src/client/northstar/dash-nodes/HistogramBoxPrimitives.tsx @@ -1,5 +1,5 @@ import React = require("react") -import { computed, observable, reaction, runInAction, trace } from "mobx"; +import { computed, observable, reaction, runInAction, trace, action } from "mobx"; import { observer } from "mobx-react"; import { Utils as DashUtils } from '../../../Utils'; import { FilterModel } from "../../northstar/core/filter/FilterModel"; @@ -11,6 +11,9 @@ import { StyleConstants } from "../../northstar/utils/StyleContants"; import { HistogramBinPrimitiveCollection, HistogramBinPrimitive } from "./HistogramBinPrimitiveCollection"; import { HistogramBox } from "./HistogramBox"; import "./HistogramBoxPrimitives.scss"; +import { JSXElement } from "babel-types"; +import { Utils } from "../utils/Utils"; +import { all } from "bluebird"; export interface HistogramPrimitivesProps { HistoBox: HistogramBox; @@ -23,20 +26,19 @@ export class HistogramBoxPrimitives extends React.Component<HistogramPrimitivesP @computed get xaxislines() { return this.renderGridLinesAndLabels(0); } @computed get yaxislines() { return this.renderGridLinesAndLabels(1); } @computed get selectedPrimitives() { return this._selectedPrims.map(bp => this.drawRect(bp.Rect, bp.BarAxis, undefined, "border")); } - @computed get binPrimitives() { + @computed get barPrimitives() { let histoResult = this.props.HistoBox.HistogramResult; if (!histoResult || !histoResult.bins || !this.props.HistoBox.VisualBinRanges.length) return (null); - trace(); let allBrushIndex = ModelHelpers.AllBrushIndex(histoResult); - return Object.keys(histoResult.bins).reduce((prims, key) => { + return Object.keys(histoResult.bins).reduce((prims: JSX.Element[], key: string) => { let drawPrims = new HistogramBinPrimitiveCollection(histoResult!.bins![key], this.props.HistoBox); let toggle = this.getSelectionToggle(drawPrims.BinPrimitives, allBrushIndex, ModelHelpers.GetBinFilterModel(histoResult!.bins![key], allBrushIndex, histoResult!, this.histoOp.X, this.histoOp.Y)); drawPrims.BinPrimitives.filter(bp => bp.DataValue && bp.BrushIndex !== allBrushIndex).map(bp => prims.push(...[{ r: bp.Rect, c: bp.Color }, { r: bp.MarginRect, c: StyleConstants.MARGIN_BARS_COLOR }].map(pair => this.drawRect(pair.r, bp.BarAxis, pair.c, "bar", toggle)))); return prims; - }, [] as JSX.Element[]); + }, [] as JSX.Element[]) } componentDidMount() { @@ -44,39 +46,38 @@ export class HistogramBoxPrimitives extends React.Component<HistogramPrimitivesP } private getSelectionToggle(binPrimitives: HistogramBinPrimitive[], allBrushIndex: number, filterModel: FilterModel) { - let allBrushPrim = ArrayUtil.FirstOrDefault(binPrimitives, bp => bp.BrushIndex === allBrushIndex); - return !allBrushPrim ? () => { } : () => runInAction(() => { + let rawAllBrushPrim = ArrayUtil.FirstOrDefault(binPrimitives, bp => bp.BrushIndex === allBrushIndex); + if (!rawAllBrushPrim) + return () => { } + let allBrushPrim = rawAllBrushPrim; + return () => runInAction(() => { if (ArrayUtil.Contains(this.histoOp.FilterModels, filterModel)) { - this._selectedPrims.splice(this._selectedPrims.indexOf(allBrushPrim!), 1); + this._selectedPrims.splice(this._selectedPrims.indexOf(allBrushPrim), 1); this.histoOp.RemoveFilterModels([filterModel]); } else { - this._selectedPrims.push(allBrushPrim!); + this._selectedPrims.push(allBrushPrim); this.histoOp.AddFilterModels([filterModel]); } }) } private renderGridLinesAndLabels(axis: number) { + trace(); if (!this.props.HistoBox.SizeConverter.Initialized) return (null); let labels = this.props.HistoBox.VisualBinRanges[axis].GetLabels(); - return labels.reduce((prims, binLabel, i) => { - let r = this.props.HistoBox.SizeConverter.DataToScreenRange(binLabel.minValue!, binLabel.maxValue!, axis); - prims.push(this.drawLine(r.xFrom, r.yFrom, axis === 0 ? 0 : r.xTo - r.xFrom, axis === 0 ? r.yTo - r.yFrom : 0)); - if (i === labels.length - 1) - prims.push(this.drawLine(axis === 0 ? r.xTo : r.xFrom, axis === 0 ? r.yFrom : r.yTo, axis === 0 ? 0 : r.xTo - r.xFrom, axis === 0 ? r.yTo - r.yFrom : 0)); - return prims; - }, [] as JSX.Element[]); + return <svg className="histogramboxprimitives-svgContainer"> + {labels.reduce((prims, binLabel, i) => { + let r = this.props.HistoBox.SizeConverter.DataToScreenRange(binLabel.minValue!, binLabel.maxValue!, axis); + prims.push(this.drawLine(r.xFrom, r.yFrom, axis === 0 ? 0 : r.xTo - r.xFrom, axis === 0 ? r.yTo - r.yFrom : 0)); + if (i === labels.length - 1) + prims.push(this.drawLine(axis === 0 ? r.xTo : r.xFrom, axis === 0 ? r.yFrom : r.yTo, axis === 0 ? 0 : r.xTo - r.xFrom, axis === 0 ? r.yTo - r.yFrom : 0)); + return prims; + }, [] as JSX.Element[])} + </svg> } - drawEntity(xFrom: number, yFrom: number, entity: JSX.Element) { - let transXpercent = xFrom / this.renderDimension * 100; - let transYpercent = yFrom / this.renderDimension * 100; - return (<div key={DashUtils.GenerateGuid()} className={`histogramboxprimitives-placer`} style={{ transform: `translate(${transXpercent}%, ${transYpercent}%)` }}> - {entity} - </div>); - } drawLine(xFrom: number, yFrom: number, width: number, height: number) { if (height < 0) { yFrom += height; @@ -86,10 +87,11 @@ export class HistogramBoxPrimitives extends React.Component<HistogramPrimitivesP xFrom += width; width = -width; } - let trans2Xpercent = width === 0 ? `1px` : `${(xFrom + width) / this.renderDimension * 100}%`; - let trans2Ypercent = height === 0 ? `1px` : `${(yFrom + height) / this.renderDimension * 100}%`; - let line = (<div className="histogramboxprimitives-line" style={{ width: trans2Xpercent, height: trans2Ypercent, }} />); - return this.drawEntity(xFrom, yFrom, line); + let trans2Xpercent = `${(xFrom + width) / this.renderDimension * 100}%`; + let trans2Ypercent = `${(yFrom + height) / this.renderDimension * 100}%`; + let trans1Xpercent = `${xFrom / this.renderDimension * 100}%` + let trans1Ypercent = `${yFrom / this.renderDimension * 100}%` + return <line className="histogramboxprimitives-line" key={DashUtils.GenerateGuid()} x1={trans1Xpercent} x2={`${trans2Xpercent}`} y1={trans1Ypercent} y2={`${trans2Ypercent}`} /> } drawRect(r: PIXIRectangle, barAxis: number, color: number | undefined, classExt: string, tapHandler: () => void = () => { }) { if (r.height < 0) { @@ -100,25 +102,22 @@ export class HistogramBoxPrimitives extends React.Component<HistogramPrimitivesP r.x += r.width; r.width = -r.width; } - let widthPercent = r.width / this.renderDimension * 100; - let heightPercent = r.height / this.renderDimension * 100; - let rect = (<div className={`histogramboxprimitives-${classExt}`} onPointerDown={(e: React.PointerEvent) => { if (e.button === 0) tapHandler() }} - style={{ - borderBottomStyle: barAxis === 1 ? "none" : "solid", - borderLeftStyle: barAxis === 0 ? "none" : "solid", - width: `${widthPercent}%`, - height: `${heightPercent}%`, - background: color ? `${LABColor.RGBtoHexString(color)}` : "" - }} - />); - return this.drawEntity(r.x, r.y, rect); + let transXpercent = `${r.x / this.renderDimension * 100}%` + let transYpercent = `${r.y / this.renderDimension * 100}%` + let widthXpercent = `${r.width / this.renderDimension * 100}%`; + let heightYpercent = `${r.height / this.renderDimension * 100}%`; + return (<rect className={`histogramboxprimitives-${classExt}`} key={DashUtils.GenerateGuid()} onPointerDown={(e: React.PointerEvent) => { if (e.button === 0) tapHandler() }} + x={transXpercent} width={`${widthXpercent}`} y={transYpercent} height={`${heightYpercent}`} fill={color ? `${LABColor.RGBtoHexString(color)}` : "transparent"} />); } render() { + trace(); return <div className="histogramboxprimitives-container"> {this.xaxislines} {this.yaxislines} - {this.binPrimitives} - {this.selectedPrimitives} + <svg className="histogramboxprimitives-svgContainer"> + {this.barPrimitives} + {this.selectedPrimitives} + </svg> </div> } }
\ No newline at end of file diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index 02e0a18df..80ddd1878 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -1,10 +1,10 @@ -import { DocumentDecorations } from "../views/DocumentDecorations"; -import { CollectionDockingView } from "../views/collections/CollectionDockingView"; -import { Document } from "../../fields/Document"; import { action } from "mobx"; +import { Document } from "../../fields/Document"; import { ImageField } from "../../fields/ImageField"; import { KeyStore } from "../../fields/KeyStore"; +import { CollectionDockingView } from "../views/collections/CollectionDockingView"; import { CollectionView } from "../views/collections/CollectionView"; +import { DocumentDecorations } from "../views/DocumentDecorations"; import { DocumentView } from "../views/nodes/DocumentView"; import { returnFalse } from "../../Utils"; @@ -17,7 +17,7 @@ export function setupDrag(_reference: React.RefObject<HTMLDivElement>, docFunc: document.removeEventListener('pointerup', onRowUp); var dragData = new DragManager.DocumentDragData([docFunc()]); dragData.moveDocument = moveFunc; - DragManager.StartDocumentDrag([_reference.current!], dragData); + DragManager.StartDocumentDrag([_reference.current!], dragData, e.x, e.y); }); let onRowUp = action((e: PointerEvent): void => { document.removeEventListener("pointermove", onRowMove); @@ -123,20 +123,9 @@ export namespace DragManager { [id: string]: any; } - export function StartDocumentDrag( - eles: HTMLElement[], - dragData: DocumentDragData, - options?: DragOptions - ) { - StartDrag( - eles, - dragData, - options, - (dropData: { [id: string]: any }) => - (dropData.droppedDocuments = dragData.aliasOnDrop - ? dragData.draggedDocuments.map(d => d.CreateAlias()) - : dragData.draggedDocuments) - ); + export function StartDocumentDrag(eles: HTMLElement[], dragData: DocumentDragData, downX: number, downY: number, options?: DragOptions) { + StartDrag(eles, dragData, downX, downY, options, + (dropData: { [id: string]: any }) => (dropData.droppedDocuments = dragData.aliasOnDrop ? dragData.draggedDocuments.map(d => d.CreateAlias()) : dragData.draggedDocuments)); } export class LinkDragData { @@ -147,19 +136,12 @@ export namespace DragManager { linkSourceDocumentView: DocumentView; [id: string]: any; } - export function StartLinkDrag( - ele: HTMLElement, - dragData: LinkDragData, - options?: DragOptions - ) { - StartDrag([ele], dragData, options); + + export function StartLinkDrag(ele: HTMLElement, dragData: LinkDragData, downX: number, downY: number, options?: DragOptions) { + StartDrag([ele], dragData, downX, downY, options); } - function StartDrag( - eles: HTMLElement[], - dragData: { [id: string]: any }, - options?: DragOptions, - finishDrag?: (dropData: { [id: string]: any }) => void - ) { + + function StartDrag(eles: HTMLElement[], dragData: { [id: string]: any }, downX: number, downY: number, options?: DragOptions, finishDrag?: (dropData: { [id: string]: any }) => void) { if (!dragDiv) { dragDiv = document.createElement("div"); dragDiv.className = "dragManager-dragDiv"; @@ -198,23 +180,22 @@ export namespace DragManager { dragElement.style.width = `${rect.width / scaleX}px`; dragElement.style.height = `${rect.height / scaleY}px`; - // bcz: PDFs don't show up if you clone them because they contain a canvas. + // bcz: if PDFs are rendered with svg's, then this code isn't needed + // bcz: PDFs don't show up if you clone them when rendered using a canvas. // however, PDF's have a thumbnail field that contains an image of their canvas. // So we replace the pdf's canvas with the image thumbnail - if (docs.length) { - var pdfBox = dragElement.getElementsByClassName( - "pdfBox-cont" - )[0] as HTMLElement; - let thumbnail = docs[0].GetT(KeyStore.Thumbnail, ImageField); - if (pdfBox && pdfBox.childElementCount && thumbnail) { - let img = new Image(); - img.src = thumbnail.toString(); - img.style.position = "absolute"; - img.style.width = `${rect.width / scaleX}px`; - img.style.height = `${rect.height / scaleY}px`; - pdfBox.replaceChild(img, pdfBox.children[0]) - } - } + // if (docs.length) { + // var pdfBox = dragElement.getElementsByClassName("pdfBox-cont")[0] as HTMLElement; + // let thumbnail = docs[0].GetT(KeyStore.Thumbnail, ImageField); + // if (pdfBox && pdfBox.childElementCount && thumbnail) { + // let img = new Image(); + // img.src = thumbnail.toString(); + // img.style.position = "absolute"; + // img.style.width = `${rect.width / scaleX}px`; + // img.style.height = `${rect.height / scaleY}px`; + // pdfBox.replaceChild(img, pdfBox.children[0]) + // } + // } dragDiv.appendChild(dragElement); return dragElement; @@ -230,6 +211,8 @@ export namespace DragManager { } eles.map(ele => (ele.hidden = hideSource)); + let lastX = downX; + let lastY = downY; const moveHandler = (e: PointerEvent) => { e.stopPropagation(); e.preventDefault(); @@ -244,12 +227,14 @@ export namespace DragManager { button: 0 }); } - dragElements.map( - (dragElement, i) => - (dragElement.style.transform = `translate(${(xs[i] += - e.movementX)}px, ${(ys[i] += e.movementY)}px) scale(${ - scaleXs[i] - }, ${scaleYs[i]})`) + //TODO: Why can't we use e.movementX and e.movementY? + let moveX = e.pageX - lastX; + let moveY = e.pageY - lastY; + lastX = e.pageX; + lastY = e.pageY; + dragElements.map((dragElement, i) => (dragElement.style.transform = + `translate(${(xs[i] += moveX)}px, ${(ys[i] += moveY)}px) + scale(${scaleXs[i]}, ${scaleYs[i]})`) ); }; @@ -267,13 +252,7 @@ export namespace DragManager { document.addEventListener("pointerup", upHandler); } - function FinishDrag( - dragEles: HTMLElement[], - e: PointerEvent, - dragData: { [index: string]: any }, - options?: DragOptions, - finishDrag?: (dragData: { [index: string]: any }) => void - ) { + function FinishDrag(dragEles: HTMLElement[], e: PointerEvent, dragData: { [index: string]: any }, options?: DragOptions, finishDrag?: (dragData: { [index: string]: any }) => void) { let removed = dragEles.map(dragEle => { let parent = dragEle.parentElement; if (parent) parent.removeChild(dragEle); diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx index 2a613ba8b..913472aa0 100644 --- a/src/client/util/TooltipTextMenu.tsx +++ b/src/client/util/TooltipTextMenu.tsx @@ -11,129 +11,127 @@ import "./TooltipTextMenu.scss"; 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 { faListUl } from '@fortawesome/free-solid-svg-icons'; //appears above a selection of text in a RichTextBox to give user options such as Bold, Italics, etc. export class TooltipTextMenu { - private tooltip: HTMLElement; - - constructor(view: EditorView) { - this.tooltip = document.createElement("div"); - this.tooltip.className = "tooltipMenu"; - - //add the div which is the tooltip - view.dom.parentNode!.appendChild(this.tooltip); - - //add additional icons - library.add(faListUl); - - //add the buttons to the tooltip - let items = [ - { command: toggleMark(schema.marks.strong), dom: this.icon("B", "strong") }, - { command: toggleMark(schema.marks.em), dom: this.icon("i", "em") }, - { command: toggleMark(schema.marks.underline), dom: this.icon("U", "underline") }, - { 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") }, - //this doesn't work currently - look into notion of active block - { command: wrapInList(schema.nodes.bullet_list), dom: this.icon(":", "bullets") }, - ] - items.forEach(({ dom }) => this.tooltip.appendChild(dom)); - - //pointer down handler to activate button effects - this.tooltip.addEventListener("pointerdown", e => { - e.preventDefault(); - view.focus(); - items.forEach(({ command, dom }) => { - if (dom.contains(e.srcElement)) { - 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" + private tooltip: HTMLElement; + + constructor(view: EditorView) { + this.tooltip = document.createElement("div"); + this.tooltip.className = "tooltipMenu"; + + //add the div which is the tooltip + view.dom.parentNode!.appendChild(this.tooltip); + + //add additional icons + library.add(faListUl); + + //add the buttons to the tooltip + let items = [ + { command: toggleMark(schema.marks.strong), dom: this.icon("B", "strong") }, + { command: toggleMark(schema.marks.em), dom: this.icon("i", "em") }, + { command: toggleMark(schema.marks.underline), dom: this.icon("U", "underline") }, + { 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") }, + //this doesn't work currently - look into notion of active block + { command: wrapInList(schema.nodes.bullet_list), dom: this.icon(":", "bullets") }, + ] + items.forEach(({ dom }) => this.tooltip.appendChild(dom)); + + //pointer down handler to activate button effects + this.tooltip.addEventListener("pointerdown", e => { + e.preventDefault(); + view.focus(); + items.forEach(({ command, dom }) => { + if (dom.contains(e.target as Node)) { + 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" + } + }) + }) + + this.update(view, undefined); + } + + // 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; + return span; + } + + //adapted this method - use it to check if block has a tag (ie bulleting) + blockActive(type: NodeType<Schema<string, string>>, state: EditorState) { + let attrs = {}; + + 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); } - }) - }) - - this.update(view, undefined); - } - - // 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; - return span; - } - - //adapted this method - use it to check if block has a tag (ie bulleting) - blockActive(type: NodeType<Schema<string, string>>, state: EditorState) { - let attrs = {}; - - 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); } - } - - //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 fa fa-smile-o"; - span.appendChild(icon); - return span; - } - - // Create an icon for a heading at the given level - heading(level: number) { - return { - command: setBlockType(schema.nodes.heading, { level }), - dom: this.icon("H" + level, "heading") + + //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 fa fa-smile-o"; + span.appendChild(icon); + return span; + } + + // Create an icon for a heading at the given level + heading(level: number) { + return { + command: setBlockType(schema.nodes.heading, { level }), + dom: this.icon("H" + level, "heading") + } } - } - - //updates the tooltip menu when the selection changes - update(view: EditorView, lastState: EditorState | undefined) { - let state = view.state - // Don't do anything if the document/selection didn't change - if (lastState && lastState.doc.eq(state.doc) && - lastState.selection.eq(state.selection)) return - - // Hide the tooltip if the selection is empty - if (state.selection.empty) { - this.tooltip.style.display = "none" - return + + //updates the tooltip menu when the selection changes + update(view: EditorView, lastState: EditorState | undefined) { + let state = view.state + // Don't do anything if the document/selection didn't change + if (lastState && lastState.doc.eq(state.doc) && + lastState.selection.eq(state.selection)) return + + // Hide the tooltip if the selection is empty + if (state.selection.empty) { + this.tooltip.style.display = "none" + return + } + + // Otherwise, reposition it and update its content + this.tooltip.style.display = "" + let { from, to } = state.selection + let start = view.coordsAtPos(from), end = view.coordsAtPos(to) + // The box in which the tooltip is positioned, to use as base + let box = this.tooltip.offsetParent!.getBoundingClientRect() + // 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; + 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"; } - // Otherwise, reposition it and update its content - this.tooltip.style.display = "" - let { from, to } = state.selection - let start = view.coordsAtPos(from), end = view.coordsAtPos(to) - // The box in which the tooltip is positioned, to use as base - let box = this.tooltip.offsetParent!.getBoundingClientRect() - // 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; - 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"; - } - - destroy() { this.tooltip.remove() } + destroy() { this.tooltip.remove() } }
\ No newline at end of file diff --git a/src/client/views/DocumentDecorations.scss b/src/client/views/DocumentDecorations.scss index d7137d7a2..c4e4aed8e 100644 --- a/src/client/views/DocumentDecorations.scss +++ b/src/client/views/DocumentDecorations.scss @@ -60,6 +60,7 @@ cursor: ew-resize; } .title{ + width:100%; background: lightblue; grid-column-start:3; grid-column-end: 4; diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 1bb00a3fc..deed0fa7c 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -122,7 +122,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> this._dragging = true; document.removeEventListener("pointermove", this.onBackgroundMove); document.removeEventListener("pointerup", this.onBackgroundUp); - DragManager.StartDocumentDrag(SelectionManager.SelectedDocuments().map(docView => docView.ContentRef.current!), dragData, { + DragManager.StartDocumentDrag(SelectionManager.SelectedDocuments().map(docView => docView.ContentRef.current!), dragData, e.x, e.y, { handlers: { dragComplete: action(() => this._dragging = false), }, @@ -215,7 +215,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> document.removeEventListener("pointermove", this.onLinkerButtonMoved) document.removeEventListener("pointerup", this.onLinkerButtonUp) let dragData = new DragManager.LinkDragData(SelectionManager.SelectedDocuments()[0]); - DragManager.StartLinkDrag(this._linkerButton.current, dragData, { + DragManager.StartLinkDrag(this._linkerButton.current, dragData, e.pageX, e.pageY, { handlers: { dragComplete: action(() => { }), }, @@ -260,7 +260,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> if (doc) moddrag.push(doc); } let dragData = new DragManager.DocumentDragData(moddrag); - DragManager.StartDocumentDrag([this._linkButton.current], dragData, { + DragManager.StartDocumentDrag([this._linkButton.current], dragData, e.x, e.y, { handlers: { dragComplete: action(() => { }), }, diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx index 74f868c11..bffe4fb11 100644 --- a/src/client/views/Main.tsx +++ b/src/client/views/Main.tsx @@ -13,7 +13,7 @@ import { Documents } from '../documents/Documents'; import { Server } from '../Server'; import { setupDrag } from '../util/DragManager'; import { Transform } from '../util/Transform'; -import { UndoManager } from '../util/UndoManager'; +import { UndoManager, undoBatch } from '../util/UndoManager'; import { WorkspacesMenu } from '../../server/authentication/controllers/WorkspacesMenu'; import { CollectionDockingView } from './collections/CollectionDockingView'; import { ContextMenu } from './ContextMenu'; @@ -51,6 +51,7 @@ import '../northstar/utils/Extensions' import { HistogramOperation } from '../northstar/operations/HistogramOperation'; import { AttributeTransformationModel } from '../northstar/core/attribute/AttributeTransformationModel'; import { ColumnAttributeModel } from '../northstar/core/attribute/AttributeModel'; +import { CollectionView } from './collections/CollectionView'; @observer export class Main extends React.Component { diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 2380709d2..6640c843e 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -200,7 +200,7 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp let tab = (e.target as any).parentElement as HTMLElement; Server.GetField(docid, action((f: Opt<Field>) => { if (f instanceof Document) - DragManager.StartDocumentDrag([tab], new DragManager.DocumentDragData([f as Document]), + DragManager.StartDocumentDrag([tab], new DragManager.DocumentDragData([f as Document]), e.pageX, e.pageY, { handlers: { dragComplete: action(() => { }), diff --git a/src/client/views/collections/CollectionViewBase.tsx b/src/client/views/collections/CollectionViewBase.tsx index 3af3c5d63..446b1c240 100644 --- a/src/client/views/collections/CollectionViewBase.tsx +++ b/src/client/views/collections/CollectionViewBase.tsx @@ -77,12 +77,12 @@ export class CollectionViewBase extends React.Component<SubCollectionViewProps> } let added = false; if (de.data.aliasOnDrop) { - added = de.data.droppedDocuments.reduce((added, d) => added || this.props.addDocument(d), false); + 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, 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, 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; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx index b682ab303..39cc816f3 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx @@ -12,6 +12,7 @@ import "./CollectionFreeFormLinksView.scss"; import { CollectionFreeFormLinkView } from "./CollectionFreeFormLinkView"; import React = require("react"); import v5 = require("uuid/v5"); +import { find } from "async"; @observer export class CollectionFreeFormLinksView extends React.Component<CollectionViewProps> { @@ -22,40 +23,44 @@ export class CollectionFreeFormLinksView extends React.Component<CollectionViewP }, () => { let views = DocumentManager.Instance.getAllDocumentViews(this.props.Document); for (let i = 0; i < views.length; i++) { - for (let j = i + 1; j < views.length; j++) { + for (let j = 0; j < views.length; j++) { let srcDoc = views[j].props.Document; let dstDoc = views[i].props.Document; 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); - if (x1w < 0 || x2w < 0) + if (x1w < 0 || x2w < 0 || i === j) continue; - dstDoc.GetTAsync(KeyStore.Prototype, Document).then((protoDest) => - srcDoc.GetTAsync(KeyStore.Prototype, Document).then((protoSrc) => runInAction(() => { - let dstTarg = (protoDest ? protoDest : dstDoc); - let srcTarg = (protoSrc ? protoSrc : srcDoc); - let findBrush = (field: ListField<Document>) => field.Data.findIndex(brush => { - let bdocs = brush.GetList(KeyStore.BrushingDocs, [] as Document[]); - return (bdocs.length === 0 || (bdocs[0] === dstTarg && bdocs[1] === srcTarg) || (bdocs[0] === srcTarg && bdocs[1] === dstTarg)) - }); - let brushAction = (field: ListField<Document>) => { - let found = findBrush(field); - if (found !== -1) - field.Data.splice(found, 1); - }; - if (Math.abs(x1 + x1w - x2) < 20 || Math.abs(x2 + x2w - x1) < 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 dstTarg = dstDoc; + let srcTarg = srcDoc; + let findBrush = (field: ListField<Document>) => field.Data.findIndex(brush => { + let bdocs = brush ? brush.GetList(KeyStore.BrushingDocs, [] as Document[]) : []; + return (bdocs.length && ((bdocs[0] === dstTarg && bdocs[1] === srcTarg)) ? true : false) + }); + let brushAction = (field: ListField<Document>) => { + let found = findBrush(field); + if (found !== -1) { + console.log("REMOVE BRUSH " + srcTarg.Title + " " + dstTarg.Title); + field.Data.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); - brushAction = brushAction = (field: ListField<Document>) => (findBrush(field) === -1) && field.Data.push(linkDoc); + brushAction = brushAction = (field: ListField<Document>) => { + if (findBrush(field) === -1) { + console.log("ADD BRUSH " + srcTarg.Title + " " + dstTarg.Title); + (findBrush(field) === -1) && field.Data.push(linkDoc); } - dstTarg.GetOrCreateAsync(KeyStore.BrushingDocs, ListField, brushAction); - srcTarg.GetOrCreateAsync(KeyStore.BrushingDocs, ListField, brushAction); - } - ))) + }; + } + dstTarg.GetOrCreateAsync(KeyStore.BrushingDocs, ListField, brushAction); + srcTarg.GetOrCreateAsync(KeyStore.BrushingDocs, ListField, brushAction); + } } }) diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 31adec0d7..ab9cd2d53 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -154,7 +154,7 @@ export class DocumentView extends React.Component<DocumentViewProps> { dragData.xOffset = x - left; dragData.yOffset = y - top; dragData.moveDocument = this.props.moveDocument; - DragManager.StartDocumentDrag([this._mainCont.current], dragData, { + DragManager.StartDocumentDrag([this._mainCont.current], dragData, x, y, { handlers: { dragComplete: action(() => { }) }, @@ -174,7 +174,7 @@ export class DocumentView extends React.Component<DocumentViewProps> { document.removeEventListener("pointermove", this.onPointerMove); document.removeEventListener("pointerup", this.onPointerUp); if (!this.topMost || e.buttons === 2 || e.altKey) { - this.startDragging(e.x, e.y, e.ctrlKey || e.altKey); + this.startDragging(this._downX, this._downY, e.ctrlKey || e.altKey); } } e.stopPropagation(); diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index d1fb06153..774d9be3e 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -153,7 +153,7 @@ export class PDFBox extends React.Component<FieldViewProps> { */ makeEditableAndHighlight = (colour: string) => { var range, sel = window.getSelection(); - if (sel.rangeCount && sel.getRangeAt) { + if (sel && sel.rangeCount && sel.getRangeAt) { range = sel.getRangeAt(0); } document.designMode = "on"; @@ -161,7 +161,7 @@ export class PDFBox extends React.Component<FieldViewProps> { document.execCommand("HiliteColor", false, colour); } - if (range) { + if (range && sel) { sel.removeAllRanges(); sel.addRange(range); diff --git a/src/server/public/files/upload_e72669595eae4384a2a32196496f4f05.pdf b/src/server/public/files/upload_e72669595eae4384a2a32196496f4f05.pdf Binary files differdeleted file mode 100644 index 8e58bfddd..000000000 --- a/src/server/public/files/upload_e72669595eae4384a2a32196496f4f05.pdf +++ /dev/null |