diff options
32 files changed, 346 insertions, 935 deletions
diff --git a/deploy/assets/downarrow.png b/deploy/assets/downarrow.png Binary files differnew file mode 100644 index 000000000..3c59ff5b1 --- /dev/null +++ b/deploy/assets/downarrow.png diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index f9492f452..6c2340d04 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -321,6 +321,7 @@ export namespace DragManager { dragElement.style.top = "0"; dragElement.style.bottom = ""; dragElement.style.left = "0"; + dragElement.style.transition = "none"; dragElement.style.color = "black"; dragElement.style.transformOrigin = "0 0"; dragElement.style.zIndex = globalCssVariables.contextMenuZindex;// "1000"; diff --git a/src/client/util/LinkManager.ts b/src/client/util/LinkManager.ts index f2f3e51dd..944bc532f 100644 --- a/src/client/util/LinkManager.ts +++ b/src/client/util/LinkManager.ts @@ -68,8 +68,8 @@ export class LinkManager { // finds all links that contain the given anchor public getAllRelatedLinks(anchor: Doc): Doc[] {//List<Doc> { let related = LinkManager.Instance.getAllLinks().filter(link => { - let protomatch1 = Doc.AreProtosEqual(anchor, Cast(link.anchor1, Doc, new Doc)); - let protomatch2 = Doc.AreProtosEqual(anchor, Cast(link.anchor2, Doc, new Doc)); + let protomatch1 = Doc.AreProtosEqual(anchor, Cast(link.anchor1, Doc, null)); + let protomatch2 = Doc.AreProtosEqual(anchor, Cast(link.anchor2, Doc, null)); return protomatch1 || protomatch2; }); return related; @@ -100,9 +100,11 @@ export class LinkManager { if (index > -1) groupTypes.splice(index, 1); LinkManager.Instance.LinkManagerDoc.allGroupTypes = new List<string>(groupTypes); LinkManager.Instance.LinkManagerDoc[groupType] = undefined; - LinkManager.Instance.getAllLinks().forEach(linkDoc => { - LinkManager.Instance.removeGroupFromAnchor(linkDoc, Cast(linkDoc.anchor1, Doc, new Doc), groupType); - LinkManager.Instance.removeGroupFromAnchor(linkDoc, Cast(linkDoc.anchor2, Doc, new Doc), groupType); + LinkManager.Instance.getAllLinks().forEach(async linkDoc => { + const anchor1 = await Cast(linkDoc.anchor1, Doc); + const anchor2 = await Cast(linkDoc.anchor2, Doc); + anchor1 && LinkManager.Instance.removeGroupFromAnchor(linkDoc, anchor1, groupType); + anchor2 && LinkManager.Instance.removeGroupFromAnchor(linkDoc, anchor2, groupType); }); } return true; @@ -122,8 +124,8 @@ export class LinkManager { } // gets the groups associates with an anchor in a link - public getAnchorGroups(linkDoc: Doc, anchor: Doc): Array<Doc> { - if (Doc.AreProtosEqual(anchor, Cast(linkDoc.anchor1, Doc, new Doc))) { + public getAnchorGroups(linkDoc: Doc, anchor?: Doc): Array<Doc> { + if (Doc.AreProtosEqual(anchor, Cast(linkDoc.anchor1, Doc, null))) { return DocListCast(linkDoc.anchor1Groups); } else { return DocListCast(linkDoc.anchor2Groups); @@ -132,7 +134,7 @@ export class LinkManager { // sets the groups of the given anchor in the given link public setAnchorGroups(linkDoc: Doc, anchor: Doc, groups: Doc[]) { - if (Doc.AreProtosEqual(anchor, Cast(linkDoc.anchor1, Doc, new Doc))) { + if (Doc.AreProtosEqual(anchor, Cast(linkDoc.anchor1, Doc, null))) { linkDoc.anchor1Groups = new List<Doc>(groups); } else { linkDoc.anchor2Groups = new List<Doc>(groups); @@ -209,10 +211,10 @@ export class LinkManager { let md: Doc[] = []; let allLinks = LinkManager.Instance.getAllLinks(); allLinks.forEach(linkDoc => { - let anchor1Groups = LinkManager.Instance.getAnchorGroups(linkDoc, Cast(linkDoc.anchor1, Doc, new Doc)); - let anchor2Groups = LinkManager.Instance.getAnchorGroups(linkDoc, Cast(linkDoc.anchor2, Doc, new Doc)); - anchor1Groups.forEach(groupDoc => { if (StrCast(groupDoc.type).toUpperCase() === groupType.toUpperCase()) md.push(Cast(groupDoc.metadata, Doc, new Doc)); }); - anchor2Groups.forEach(groupDoc => { if (StrCast(groupDoc.type).toUpperCase() === groupType.toUpperCase()) md.push(Cast(groupDoc.metadata, Doc, new Doc)); }); + let anchor1Groups = LinkManager.Instance.getAnchorGroups(linkDoc, Cast(linkDoc.anchor1, Doc, null)); + let anchor2Groups = LinkManager.Instance.getAnchorGroups(linkDoc, Cast(linkDoc.anchor2, Doc, null)); + anchor1Groups.forEach(groupDoc => { if (StrCast(groupDoc.type).toUpperCase() === groupType.toUpperCase()) { const meta = Cast(groupDoc.metadata, Doc, null); meta && md.push(meta); } }); + anchor2Groups.forEach(groupDoc => { if (StrCast(groupDoc.type).toUpperCase() === groupType.toUpperCase()) { const meta = Cast(groupDoc.metadata, Doc, null); meta && md.push(meta); } }); }); return md; } @@ -221,18 +223,20 @@ export class LinkManager { public doesLinkExist(anchor1: Doc, anchor2: Doc): boolean { let allLinks = LinkManager.Instance.getAllLinks(); let index = allLinks.findIndex(linkDoc => { - return (Doc.AreProtosEqual(Cast(linkDoc.anchor1, Doc, new Doc), anchor1) && Doc.AreProtosEqual(Cast(linkDoc.anchor2, Doc, new Doc), anchor2)) || - (Doc.AreProtosEqual(Cast(linkDoc.anchor1, Doc, new Doc), anchor2) && Doc.AreProtosEqual(Cast(linkDoc.anchor2, Doc, new Doc), anchor1)); + return (Doc.AreProtosEqual(Cast(linkDoc.anchor1, Doc, null), anchor1) && Doc.AreProtosEqual(Cast(linkDoc.anchor2, Doc, null), anchor2)) || + (Doc.AreProtosEqual(Cast(linkDoc.anchor1, Doc, null), anchor2) && Doc.AreProtosEqual(Cast(linkDoc.anchor2, Doc, null), anchor1)); }); return index !== -1; } // finds the opposite anchor of a given anchor in a link + //TODO This should probably return undefined if there isn't an opposite anchor + //TODO This should also await the return value of the anchor so we don't filter out promises public getOppositeAnchor(linkDoc: Doc, anchor: Doc): Doc { - if (Doc.AreProtosEqual(anchor, Cast(linkDoc.anchor1, Doc, new Doc))) { - return Cast(linkDoc.anchor2, Doc, new Doc); + if (Doc.AreProtosEqual(anchor, Cast(linkDoc.anchor1, Doc, null))) { + return Cast(linkDoc.anchor2, Doc, null)!; } else { - return Cast(linkDoc.anchor1, Doc, new Doc); + return Cast(linkDoc.anchor1, Doc, null)!; } } }
\ No newline at end of file diff --git a/src/client/util/SearchUtil.ts b/src/client/util/SearchUtil.ts index ac2eb72e7..338628960 100644 --- a/src/client/util/SearchUtil.ts +++ b/src/client/util/SearchUtil.ts @@ -29,11 +29,16 @@ export namespace SearchUtil { return { docs, numFound }; } - export async function GetAliasesOfDocument(doc: Doc): Promise<Doc[]> { - const proto = await Doc.GetT(doc, "proto", Doc, true); - const protoId = (proto || doc)[Id]; - const result = await Search(`proto_i:"${protoId}"`, true); - return result.docs; + export async function GetAliasesOfDocument(doc: Doc): Promise<Doc[]>; + export async function GetAliasesOfDocument(doc: Doc, returnDocs: false): Promise<string[]>; + export async function GetAliasesOfDocument(doc: Doc, returnDocs = true): Promise<Doc[] | string[]> { + const proto = Doc.GetProto(doc); + const protoId = proto[Id]; + if (returnDocs) { + return (await Search(`proto_i:"${protoId}"`, returnDocs)).docs; + } else { + return (await Search(`proto_i:"${protoId}"`, returnDocs)).ids; + } // return Search(`{!join from=id to=proto_i}id:${protoId}`, true); } @@ -41,4 +46,22 @@ export namespace SearchUtil { const results = await Search(`proto_i:"${doc[Id]}"`, true); return results.docs; } + + export async function GetContextsOfDocument(doc: Doc): Promise<{ contexts: Doc[], aliasContexts: Doc[] }> { + const docContexts = (await Search(`data_l:"${doc[Id]}"`, true)).docs; + const aliases = await GetAliasesOfDocument(doc, false); + const aliasContexts = (await Promise.all(aliases.map(doc => Search(`data_l:"${doc}"`, true)))); + const contexts = { contexts: docContexts, aliasContexts: [] as Doc[] }; + aliasContexts.forEach(result => contexts.aliasContexts.push(...result.docs)); + return contexts; + } + + export async function GetContextIdsOfDocument(doc: Doc): Promise<{ contexts: string[], aliasContexts: string[] }> { + const docContexts = (await Search(`data_l:"${doc[Id]}"`, false)).ids; + const aliases = await GetAliasesOfDocument(doc, false); + const aliasContexts = (await Promise.all(aliases.map(doc => Search(`data_l:"${doc}"`, false)))); + const contexts = { contexts: docContexts, aliasContexts: [] as string[] }; + aliasContexts.forEach(result => contexts.aliasContexts.push(...result.ids)); + return contexts; + } }
\ No newline at end of file diff --git a/src/client/util/TooltipTextMenu.scss b/src/client/util/TooltipTextMenu.scss index b10573b3e..40ac3abb9 100644 --- a/src/client/util/TooltipTextMenu.scss +++ b/src/client/util/TooltipTextMenu.scss @@ -248,7 +248,7 @@ transform: translateY(-85px); pointer-events: all; height: 30px; - width:500px; + width:550px; .ProseMirror-example-setup-style hr { padding: 2px 10px; border: none; diff --git a/src/client/util/TooltipTextMenu.tsx b/src/client/util/TooltipTextMenu.tsx index e3e26d1f4..cb7ed976a 100644 --- a/src/client/util/TooltipTextMenu.tsx +++ b/src/client/util/TooltipTextMenu.tsx @@ -32,7 +32,6 @@ export class TooltipTextMenu { private fontSizeToNum: Map<MarkType, number>; private fontStylesToName: Map<MarkType, string>; private listTypeToIcon: Map<NodeType, string>; - private link: HTMLAnchorElement; private linkEditor?: HTMLDivElement; private linkText?: HTMLDivElement; @@ -89,6 +88,7 @@ export class TooltipTextMenu { }); }); + this.updateLinkMenu(); //list of font styles this.fontStylesToName = new Map(); @@ -121,11 +121,6 @@ export class TooltipTextMenu { this.listTypeToIcon.set(schema.nodes.ordered_list, "1)"); this.listTypes = Array.from(this.listTypeToIcon.keys()); - this.link = document.createElement("a"); - this.link.target = "_blank"; - this.link.style.color = "white"; - //this.tooltip.appendChild(this.link); - this.tooltip.appendChild(this.createLink().render(this.view).dom); this.tooltip.appendChild(this.createStar().render(this.view).dom); @@ -191,6 +186,7 @@ export class TooltipTextMenu { updateLinkMenu() { if (!this.linkEditor || !this.linkText) { this.linkEditor = document.createElement("div"); + this.linkEditor.className = "ProseMirror-icon menuicon"; this.linkEditor.style.color = "black"; this.linkText = document.createElement("div"); this.linkText.style.cssFloat = "left"; @@ -231,8 +227,9 @@ export class TooltipTextMenu { }; 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.width = "15px"; + this.linkDrag.style.height = "15px"; + this.linkDrag.title = "Drag to create link"; this.linkDrag.style.color = "black"; this.linkDrag.style.background = "black"; this.linkDrag.style.cssFloat = "left"; @@ -250,10 +247,10 @@ export class TooltipTextMenu { hideSource: false }); }; - // this.linkEditor.appendChild(this.linkDrag); + this.linkEditor.appendChild(this.linkDrag); // this.linkEditor.appendChild(this.linkText); // this.linkEditor.appendChild(linkBtn); - //this.tooltip.appendChild(this.linkEditor); + this.tooltip.appendChild(this.linkEditor); } let node = this.view.state.selection.$from.nodeAfter; @@ -444,16 +441,24 @@ export class TooltipTextMenu { enable(state) { return !state.selection.empty; }, run: (state, dispatch, view) => { // to remove link + let curLink = ""; if (this.markActive(state, markType)) { - toggleMark(markType)(state, dispatch); - return true; + + let { from, $from, to, empty } = state.selection; + let node = state.doc.nodeAt(from); + node && node.marks.map(m => { + m.type === markType && (curLink = m.attrs.href); + }) + //toggleMark(markType)(state, dispatch); + //return true; } // to create link openPrompt({ title: "Create a link", fields: { href: new TextField({ - label: "Link target", + value: curLink, + label: "Link Target", required: true }), title: new TextField({ label: "Title" }) @@ -603,7 +608,6 @@ export class TooltipTextMenu { } } this.view.dispatch(this.view.state.tr.setStoredMarks(this._activeMarks)); - this.updateLinkMenu(); } //finds all active marks on selection in given group diff --git a/src/client/views/Main.scss b/src/client/views/Main.scss index b85a8040a..f52e3b658 100644 --- a/src/client/views/Main.scss +++ b/src/client/views/Main.scss @@ -230,6 +230,8 @@ ul#add-options-list { .mainView-libraryFlyout { height: 100%; position: absolute; + display: flex; + flex-direction:column; } .mainView-libraryHandle { @@ -241,4 +243,20 @@ ul#add-options-list { position: absolute; z-index: 1; background: gray; +} + +.mainView-workspace { + height:200px; + position:relative; + display:flex; +} +.mainView-library { + height:75%; + position:relative; + display:flex; +} +.mainView-recentlyClosed { + height:25%; + position:relative; + display:flex; }
\ No newline at end of file diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 61ccf4c1d..fe59f52c8 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -1,19 +1,19 @@ import { IconName, library } from '@fortawesome/fontawesome-svg-core'; -import { faArrowDown, faArrowUp, faBell, faCheck, faCommentAlt, faCut, faExclamation, faFilePdf, faFilm, faFont, faGlobeAsia, faImage, faMusic, faObjectGroup, faPenNib, faRedoAlt, faTable, faThumbtack, faTree, faUndoAlt } from '@fortawesome/free-solid-svg-icons'; +import { faArrowDown, faArrowUp, faCheck, faCommentAlt, faCut, faExclamation, faFilePdf, faFilm, faFont, faGlobeAsia, faImage, faMusic, faObjectGroup, faPenNib, faRedoAlt, faTable, faThumbtack, faTree, faUndoAlt } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { action, computed, configure, observable, runInAction } from 'mobx'; +import { action, computed, configure, observable, runInAction, reaction, trace } from 'mobx'; import { observer } from 'mobx-react'; import "normalize.css"; import * as React from 'react'; import { SketchPicker } from 'react-color'; import Measure from 'react-measure'; import * as request from 'request'; -import { Doc, DocListCast, Opt } from '../../new_fields/Doc'; +import { Doc, DocListCast, Opt, HeightSym } from '../../new_fields/Doc'; import { Id } from '../../new_fields/FieldSymbols'; import { InkTool } from '../../new_fields/InkField'; import { List } from '../../new_fields/List'; import { listSpec } from '../../new_fields/Schema'; -import { Cast, FieldValue } from '../../new_fields/Types'; +import { Cast, FieldValue, NumCast } from '../../new_fields/Types'; import { CurrentUserUtils } from '../../server/authentication/models/current_user_utils'; import { RouteStore } from '../../server/RouteStore'; import { emptyFunction, returnOne, returnTrue } from '../../Utils'; @@ -72,6 +72,22 @@ export class MainView extends React.Component { window.removeEventListener("pointerup", this.pointerUp); window.addEventListener("pointerup", this.pointerUp); + + reaction(() => { + let workspaces = CurrentUserUtils.UserDocument.workspaces; + let recent = CurrentUserUtils.UserDocument.recentlyClosed; + if (!(recent instanceof Doc)) return 0; + if (!(workspaces instanceof Doc)) return 0; + let workspacesDoc = workspaces; + let recentDoc = recent; + let libraryHeight = this.getPHeight() - workspacesDoc[HeightSym]() - recentDoc[HeightSym]() - 20 + CurrentUserUtils.UserDocument[HeightSym]() * 0.00001; + return libraryHeight; + }, (libraryHeight: number) => { + if (libraryHeight && Math.abs(CurrentUserUtils.UserDocument[HeightSym]() - libraryHeight) > 5) { + CurrentUserUtils.UserDocument.height = libraryHeight; + } + (Cast(CurrentUserUtils.UserDocument.recentlyClosed, Doc) as Doc)!.allowClear = true; + }, { fireImmediately: true }); } pointerDown = (e: PointerEvent) => this.isPointerDown = true; @@ -163,7 +179,9 @@ export class MainView extends React.Component { @action createNewWorkspace = async (id?: string) => { - const list = Cast(CurrentUserUtils.UserDocument.data, listSpec(Doc)); + let workspaces = Cast(CurrentUserUtils.UserDocument.workspaces, Doc); + if (!(workspaces instanceof Doc)) return; + const list = Cast((CurrentUserUtils.UserDocument.workspaces as Doc).data, listSpec(Doc)); if (list) { let freeformDoc = Docs.FreeformDocument([], { x: 0, y: 400, width: this.pwidth * .7, height: this.pheight, title: `WS collection ${list.length + 1}` }); var dockingLayout = { content: [{ type: 'row', content: [CollectionDockingView.makeDocumentConfig(freeformDoc, freeformDoc, 600)] }] }; @@ -285,8 +303,11 @@ export class MainView extends React.Component { }; @computed get flyout() { + let sidebar = CurrentUserUtils.UserDocument.sidebar; + if (!(sidebar instanceof Doc)) return (null); + let sidebarDoc = sidebar; return <DocumentView - Document={CurrentUserUtils.UserDocument} + Document={sidebarDoc} DataDoc={undefined} addDocument={undefined} addDocTab={this.addDocTabFunc} @@ -304,7 +325,7 @@ export class MainView extends React.Component { ContainingCollectionView={undefined} zoomToScale={emptyFunction} getScale={returnOne}> - </DocumentView>; + </DocumentView> } @computed get mainContent() { diff --git a/src/client/views/Templates.tsx b/src/client/views/Templates.tsx index 4843a70a6..236704fa2 100644 --- a/src/client/views/Templates.tsx +++ b/src/client/views/Templates.tsx @@ -69,8 +69,7 @@ export namespace Templates { `< div > <div style="height:100%; width:100%;position:absolute;">{layout}</div> <div id="isExpander" style="height:15px; width:15px; margin-left:-16px; pointer-events:all; position:absolute; top: 0; background-color: rgba(0, 0, 0, .4); color: white;"> - <img id="isExpander" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAOEAAADhCAMAAAAJbSJIAAAAZlBMVEX///8AAABmZmb7+/tYWFhgYGBFRUVSUlL4+Pg/Pz9jY2N5eXmcnJyioqKBgYFzc3NtbW1LS0s3NzfW1taWlpaOjo6IiIgvLy9WVlampqZcXFw5OTlvb28mJiYxMTHe3t7l5eUjIyMY8kIZAAAD2UlEQVR4nO2d61biMBRGW1FBEVHxfp15/5ecOVa5lHxtArmck/Xtn1BotjtNoXQtm4YQQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEFIrX6UHEA1gsmrneceRjHm7cj28attKFOf/TRyKIliH4vzbZE+xE2zbZYkxRWX5Y9JT/BW0X3G+NtlR3Ahar7jcMtlS3Ba0XXG+Y7JW3BW0XHHZM/lR7AvaVewL/ijuC1pV3Bf8VnQJ2lR0CYriq/Nxg4puwfa1aZ7dz9yUHnEgN26NZ3luWkPFd7fEtHsWVDwpO+YgTgYKCuYn6tAU7TBecaygcGpZEQie7m5luKJPQQFUvCwx5iAuvQoK4KShvSIoOHVtCz7dnOUecxBn7kG/urc2eCz6T9EOcxXDCgpAUetyAwoOCBqrGF5QMKR4mCA8L+pTBIJwkRl95eifJjPHTDYTFQ8vePyrs3BsBfXLzfFHkvKKMY4j1ctNnCmmuGKslfCQT0RZiPdFVmnFmOcy36sDWYn7DU9hxdifRkKuEGQh/pWW0K/QiUlxtUxVxTTXyhQtN6kuI6mpmO5qpxJFIBjl1yMVimmvV4PfrnIq3iYsKICTRj7F9L84gIq38fYwCCj4HnMfRY/FPL8ZFayYo6BQbLlJeZrYpVDFXAUFcMtKWkUgmOhmnwKKOQsK4NaxdIp5CwqZj8X8gv27jNecJ9nZuXtnie/SzjhRQcHkt6Fnq1imoAAUY1csVVDIUrFcQSGDIhC8jriLQZIrli0oXKdVLF1QSFqxfEEBVLyI8NYXCgoKySaqhinakajimxrBRBX1FBQSVNRyDP4SXVGbYHRFfYJN8xhTESwyj5HHHEjEihoLCqDiXfAb3aksKESqCAoqEIxUUW9BAS03E+93mOhcZDYcXVF3QeHBPcI3v4qo4EPiUQcBKr75vHaiv6AAKt6NV0SCqgoKqOKYovpFZgOo+DmsOHkyUlA4ZKKamaIdQPEJK5oqKKCKM7D9zFZBIayiuYICWm5cFWef7o3vs486CP8VdQIEVRcU7sFE7VecgSmqvKDgVxEJqi8ogIof2xVnH2YLCuMT1fAU7RirOPtrXHCsovmCwlDFCgoKWNH4IrMBTdQ/NUzRjiu3CeCq9HAPAVSspaDgX9FkQcG3ollB34qGBf0UTQv6KBoXHFc0LzimWIFg0ywGBBelBxcHXLGKggKqWElBwV2xIkF3xaoEXYqVCe4rVifYV3wpPZwULOouKLzUXVBY1F1QeKm7oLCoXVAqVi7YNM7/F0YIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBCCCG+/ANh4i1CHdc63QAAAABJRU5ErkJggg==" - width="15px" height="15px" /> + <img id="isExpander" src="/assets/downarrow.png" width="15px" height="15px" /> </div> </div > ` ); diff --git a/src/client/views/collections/CollectionBaseView.tsx b/src/client/views/collections/CollectionBaseView.tsx index 879898018..e4f9b5058 100644 --- a/src/client/views/collections/CollectionBaseView.tsx +++ b/src/client/views/collections/CollectionBaseView.tsx @@ -64,7 +64,7 @@ export class CollectionBaseView extends React.Component<CollectionViewProps> { active = (): boolean => { var isSelected = this.props.isSelected(); - return isSelected || this._isChildActive || this.props.renderDepth === 0; + return isSelected || this._isChildActive || this.props.renderDepth === 0 || BoolCast(this.props.Document.excludeFromLibrary); } //TODO should this be observable? diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 19d07ecdc..d477f96f0 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -27,6 +27,7 @@ import { MainView } from '../MainView'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { library } from '@fortawesome/fontawesome-svg-core'; import { faFile } from '@fortawesome/free-solid-svg-icons'; +import { CurrentUserUtils } from '../../../server/authentication/models/current_user_utils'; library.add(faFile); @observer @@ -405,6 +406,9 @@ export class CollectionDockingView extends React.Component<SubCollectionViewProp if (doc instanceof Doc) { let theDoc = doc; CollectionDockingView.Instance._removedDocs.push(theDoc); + if (CurrentUserUtils.UserDocument.recentlyClosed instanceof Doc) { + Doc.AddDocToList(CurrentUserUtils.UserDocument.recentlyClosed, "data", doc, undefined, true, true); + } SelectionManager.DeselectAll(); } tab.contentItem.remove(); diff --git a/src/client/views/collections/CollectionStackingView.scss b/src/client/views/collections/CollectionStackingView.scss index 034a09eaa..bc733f152 100644 --- a/src/client/views/collections/CollectionStackingView.scss +++ b/src/client/views/collections/CollectionStackingView.scss @@ -16,7 +16,7 @@ align-items: center; } - .collectionStackingView-masonrySingle, .collectionStackingView-masonryGrid{ + .collectionStackingView-masonrySingle, .collectionStackingView-masonryGrid { width:100%; height:100%; position: absolute; @@ -25,7 +25,17 @@ left: 0; width: 100%; position: absolute; - + } + .collectionStackingView-masonrySingle { + width:100%; + height:100%; + position: absolute; + display:flex; + flex-direction: column; + top: 0; + left: 0; + width: 100%; + position: absolute; } .collectionStackingView-description { diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index 6b4eddec9..aea74321e 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -1,6 +1,6 @@ import React = require("react"); import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { action, computed, IReactionDisposer, reaction } from "mobx"; +import { action, computed, IReactionDisposer, reaction, untracked } from "mobx"; import { observer } from "mobx-react"; import { Doc, HeightSym, WidthSym } from "../../../new_fields/Doc"; import { Id } from "../../../new_fields/FieldSymbols"; @@ -10,7 +10,6 @@ import { ContextMenu } from "../ContextMenu"; import { CollectionSchemaPreview } from "./CollectionSchemaView"; import "./CollectionStackingView.scss"; import { CollectionSubView } from "./CollectionSubView"; -import { resolve } from "bluebird"; import { undoBatch } from "../../util/UndoManager"; import { DragManager } from "../../util/DragManager"; @@ -25,6 +24,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { @computed get gridGap() { return NumCast(this.props.Document.gridGap, 10); } @computed get singleColumn() { return BoolCast(this.props.Document.singleColumn, true); } @computed get columnWidth() { return this.singleColumn ? (this.props.PanelWidth() / (this.props as any).ContentScaling() - 2 * this.xMargin) : Math.min(this.props.PanelWidth() - 2 * this.xMargin, NumCast(this.props.Document.columnWidth, 250)); } + @computed get filteredChildren() { return this.childDocs.filter(d => !d.isMinimized); } singleColDocHeight(d: Doc) { let nw = NumCast(d.nativeWidth); @@ -35,14 +35,10 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { } componentDidMount() { this._heightDisposer = reaction(() => [this.yMargin, this.gridGap, this.columnWidth, this.childDocs.map(d => [d.height, d.width, d.zoomBasis, d.nativeHeight, d.nativeWidth, d.isMinimized])], - () => { - if (this.singleColumn) { - let children = this.childDocs.filter(d => !d.isMinimized); - this.props.Document.height = children.reduce((height, d, i) => - height + this.singleColDocHeight(d) + (i === children.length - 1 ? this.yMargin : this.gridGap) - , this.yMargin); - } - }, { fireImmediately: true }); + () => this.singleColumn && + (this.props.Document.height = this.filteredChildren.reduce((height, d, i) => + height + this.singleColDocHeight(d) + (i === this.filteredChildren.length - 1 ? this.yMargin : this.gridGap), this.yMargin)) + , { fireImmediately: true }); } componentWillUnmount() { if (this._heightDisposer) this._heightDisposer(); @@ -50,14 +46,14 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { @action moveDocument = (doc: Doc, targetCollection: Doc, addDocument: (document: Doc) => boolean): boolean => { - this.props.removeDocument(doc); - addDocument(doc); - return true; + return this.props.removeDocument(doc) && addDocument(doc); } - getDocTransform(doc: Doc, dref: HTMLDivElement) { - let { scale, translateX, translateY } = Utils.GetScreenTransform(dref); + getSingleDocTransform(doc: Doc, ind: number, width: number) { + let localY = this.filteredChildren.reduce((height, d, i) => + height + (i < ind ? this.singleColDocHeight(d) + this.gridGap : 0), this.yMargin); + let translate = this.props.ScreenToLocalTransform().inverse().transformPoint((this.props.PanelWidth() - width) / 2, localY); let outerXf = Utils.GetScreenTransform(this._masonryGridRef!); - let offset = this.props.ScreenToLocalTransform().transformDirection(outerXf.translateX - translateX, outerXf.translateY - translateY); + let offset = this.props.ScreenToLocalTransform().transformDirection(outerXf.translateX - translate[0], outerXf.translateY - translate[1]); return this.props.ScreenToLocalTransform().translate(offset[0], offset[1]).scale(NumCast(doc.width, 1) / this.columnWidth); } createRef = (ele: HTMLDivElement | null) => { @@ -67,17 +63,15 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { @computed get singleColumnChildren() { - let children = this.childDocs.filter(d => !d.isMinimized); - return children.map((d, i) => { + return this.filteredChildren.map((d, i) => { let layoutDoc = Doc.expandTemplateLayout(d, this.props.DataDoc); - let dref = React.createRef<HTMLDivElement>(); - let dxf = () => this.getDocTransform(layoutDoc, dref.current!).scale(this.columnWidth / d[WidthSym]()); let width = () => d.nativeWidth ? Math.min(d[WidthSym](), this.columnWidth) : this.columnWidth; let height = () => this.singleColDocHeight(layoutDoc); + let dxf = () => this.getSingleDocTransform(layoutDoc, i, width()).scale(this.columnWidth / d[WidthSym]()); + let gap = i === 0 ? 0 : this.gridGap; return <div className="collectionStackingView-columnDoc" key={d[Id]} - ref={dref} - style={{ width: width(), height: height() }} > + style={{ width: width(), display: "inline-block", marginTop: gap, height: `${height() / (this.props.Document[HeightSym]() - 2 * this.yMargin) * 100}%` }} > <CollectionSchemaPreview Document={layoutDoc} DataDocument={d !== this.props.DataDoc ? this.props.DataDoc : undefined} @@ -98,11 +92,17 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { </div>; }); } + getDocTransform(doc: Doc, dref: HTMLDivElement) { + let { scale, translateX, translateY } = Utils.GetScreenTransform(dref); + let outerXf = Utils.GetScreenTransform(this._masonryGridRef!); + let offset = this.props.ScreenToLocalTransform().transformDirection(outerXf.translateX - translateX, outerXf.translateY - translateY); + return this.props.ScreenToLocalTransform().translate(offset[0], offset[1]).scale(NumCast(doc.width, 1) / this.columnWidth); + } docXfs: any[] = [] @computed get children() { this.docXfs.length = 0; - return this.childDocs.filter(d => !d.isMinimized).map((d, i) => { + return this.filteredChildren.map((d, i) => { let aspect = d.nativeHeight ? NumCast(d.nativeWidth) / NumCast(d.nativeHeight) : undefined; let dref = React.createRef<HTMLDivElement>(); let dxf = () => this.getDocTransform(d, dref.current!).scale(this.columnWidth / d[WidthSym]()); @@ -187,14 +187,14 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { }) } if (super.drop(e, de)) { - if (targInd !== -1) { - let newDoc = de.data.droppedDocuments[0]; - let docs = this.childDocList; - if (docs) { - let srcInd = docs.indexOf(newDoc); - docs.splice(srcInd, 1); - docs.splice(targInd > srcInd ? targInd - 1 : targInd, 0, newDoc); - } + let newDoc = de.data.droppedDocuments[0]; + let docs = this.childDocList; + if (docs) { + if (targInd === -1) targInd = docs.length; + else targInd = docs.indexOf(this.filteredChildren[targInd]); + let srcInd = docs.indexOf(newDoc); + docs.splice(srcInd, 1); + docs.splice(targInd > srcInd ? targInd - 1 : targInd, 0, newDoc); } } return false; @@ -223,7 +223,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { }); } render() { - let cols = this.singleColumn ? 1 : Math.max(1, Math.min(this.childDocs.filter(d => !d.isMinimized).length, + let cols = this.singleColumn ? 1 : Math.max(1, Math.min(this.filteredChildren.length, Math.floor((this.props.PanelWidth() - 2 * this.xMargin) / (this.columnWidth + this.gridGap)))); let templatecols = ""; for (let i = 0; i < cols; i++) templatecols += `${this.columnWidth}px `; diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 79c23d71a..5287d3c13 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -102,6 +102,7 @@ export function CollectionSubView<T>(schemaCtor: (doc: Doc) => T) { return added; } else if (de.data instanceof DragManager.AnnotationDragData) { + e.stopPropagation(); return this.props.addDocument(de.data.dropDocument); } return false; diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 93a1ec1eb..d7725f444 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -1,5 +1,5 @@ import { library } from '@fortawesome/fontawesome-svg-core'; -import { faAngleRight, faCamera, faExpand, faBell, faCaretDown, faCaretRight, faCaretSquareDown, faCaretSquareRight, faTrashAlt } from '@fortawesome/free-solid-svg-icons'; +import { faAngleRight, faCamera, faExpand, faTrash, faBell, faCaretDown, faCaretRight, faCaretSquareDown, faCaretSquareRight, faTrashAlt } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, computed, observable, trace } from "mobx"; import { observer } from "mobx-react"; @@ -51,6 +51,7 @@ export interface TreeViewProps { library.add(faTrashAlt); library.add(faAngleRight); library.add(faBell); +library.add(faTrash); library.add(faCamera); library.add(faExpand); library.add(faCaretDown); @@ -471,9 +472,12 @@ export class CollectionTreeView extends CollectionSubView(Document) { } onContextMenu = (e: React.MouseEvent): void => { // need to test if propagation has stopped because GoldenLayout forces a parallel react hierarchy to be created for its top-level layout - if (!e.isPropagationStopped() && this.props.Document.excludeFromLibrary) { // excludeFromLibrary means this is the user document + if (!e.isPropagationStopped() && this.props.Document.workspaceLibrary) { // excludeFromLibrary means this is the user document ContextMenu.Instance.addItem({ description: "Create Workspace", event: undoBatch(() => MainView.Instance.createNewWorkspace()) }); ContextMenu.Instance.addItem({ description: "Delete Workspace", event: undoBatch(() => this.remove(this.props.Document)) }); + e.stopPropagation(); + e.preventDefault(); + ContextMenu.Instance.displayMenu(e.pageX - 15, e.pageY - 15); } } @@ -506,6 +510,17 @@ export class CollectionTreeView extends CollectionSubView(Document) { </div> </div >; } + @computed get clearButton() { + return <div id="toolbar" key="toolbar"> + <div > + <button className="toolbar-button round-button" title="Notifs" + onClick={undoBatch(action(() => Doc.GetProto(this.props.Document)[this.props.fieldKey] = undefined))}> + <FontAwesomeIcon icon={faTrash} size="sm" /> + </button> + </div> + </div >; + } + render() { let dropAction = StrCast(this.props.Document.dropAction) as dropActionType; @@ -531,7 +546,8 @@ export class CollectionTreeView extends CollectionSubView(Document) { TreeView.loadId = doc[Id]; Doc.AddDocToList(this.props.Document, this.props.fieldKey, doc, this.childDocs.length ? this.childDocs[0] : undefined, true); }} /> - {this.props.Document.excludeFromLibrary ? this.notifsButton : (null)} + {this.props.Document.workspaceLibrary ? this.notifsButton : (null)} + {this.props.Document.allowClear ? this.clearButton : (null)} <ul className="no-indent" style={{ width: "max-content" }} > { TreeView.GetChildElements(this.childDocs, this.props.Document[Id], this.props.Document, this.props.DataDoc, this.props.fieldKey, addDoc, this.remove, diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 4b7d462e5..7a22b7ec3 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -249,16 +249,12 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { var scale = this.getLocalTransform().inverse().Scale; const newPanX = Math.min((1 - 1 / scale) * this.nativeWidth, Math.max(0, panX)); const newPanY = Math.min((1 - 1 / scale) * this.nativeHeight, Math.max(0, panY)); - // this.props.Document.panX = this.isAnnotationOverlay ? newPanX : panX; - // this.props.Document.panY = this.isAnnotationOverlay ? newPanY : panY; - this.props.Document.panX = panX; + this.props.Document.panX = this.isAnnotationOverlay ? newPanX : panX; + this.props.Document.panY = this.isAnnotationOverlay ? newPanY : panY; + // this.props.Document.panX = panX; + // this.props.Document.panY = panY; if (this.props.Document.scrollY) { this.props.Document.scrollY = panY; - this.props.Document.panY = panY; - } - else { - - this.props.Document.panY = panY; } } @@ -468,8 +464,6 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { description: "Add freeform arrangement", event: () => { let addOverlay = (key: "arrangeScript" | "arrangeInit", options: OverlayElementOptions, params?: Record<string, string>, requiredType?: string) => { - const docs = DocListCast(this.Document[this.props.fieldKey]); - docs.map(d => d.transition = "transform 1s"); let overlayDisposer: () => void; const script = this.Document[key]; let originalText: string | undefined = undefined; @@ -484,6 +478,8 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { onError(script.errors.map(error => error.messageText).join("\n")); return; } + const docs = DocListCast(this.Document[this.props.fieldKey]); + docs.map(d => d.transition = "transform 1s"); this.Document[key] = new ScriptField(script); overlayDisposer(); setTimeout(() => docs.map(d => d.transition = undefined), 1200); diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx index 0da4888a1..56a14e26e 100644 --- a/src/client/views/nodes/DocumentContentsView.tsx +++ b/src/client/views/nodes/DocumentContentsView.tsx @@ -24,6 +24,7 @@ import { Without, OmitKeys } from "../../../Utils"; import { Cast, StrCast, NumCast } from "../../../new_fields/Types"; import { List } from "../../../new_fields/List"; import { Doc } from "../../../new_fields/Doc"; +import { CollectionViewType } from "../collections/CollectionBaseView"; const JsxParser = require('react-jsx-parser').default; //TODO Why does this need to be imported like this? type BindingProps = Without<FieldViewProps, 'fieldKey'>; @@ -82,7 +83,8 @@ export class DocumentContentsView extends React.Component<DocumentViewProps & { // by checking the layoutKey. This should probably be moved into // a prop so that the overlay can explicitly turn off templates. if ((this.props.layoutKey === "overlayLayout" && StrCast(this.props.Document.layout).indexOf("CollectionView") !== -1) || - (this.props.layoutKey === "layout" && StrCast(this.props.Document.layout).indexOf("CollectionView") === -1)) { + (this.props.layoutKey === "layout" && StrCast(this.props.Document.layout).indexOf("CollectionView") === -1) || + (this.props.layoutKey === "layout" && NumCast(this.props.Document.viewType)) !== CollectionViewType.Freeform) { this.templates.forEach(template => { let self = this; // this scales constants in the markup by the scaling applied to the document, but caps the constants to be smaller diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 2610d0e6d..c75ff51e2 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -375,7 +375,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu } onPointerMove = (e: PointerEvent): void => { if (!e.cancelBubble && this.active) { - if (Math.abs(this._downX - e.clientX) > 3 || Math.abs(this._downY - e.clientY) > 3) { + if (!this.props.Document.excludeFromLibrary && (Math.abs(this._downX - e.clientX) > 3 || Math.abs(this._downY - e.clientY) > 3)) { document.removeEventListener("pointermove", this.onPointerMove); document.removeEventListener("pointerup", this.onPointerUp); if (!e.altKey && !this.topMost && e.buttons === 1 && !BoolCast(this.props.Document.lockedPosition)) { diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 5da52f4c2..b9cecdd24 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -182,7 +182,8 @@ export class ImageBox extends DocComponent<FieldViewProps, ImageDocument>(ImageD return url.href; } let ext = path.extname(url.href); - return url.href.replace(ext, this._curSuffix + ext); + const suffix = this.props.renderDepth <= 1 ? "_o" : this._curSuffix; + return url.href.replace(ext, suffix + ext); } @observable _smallRetryCount = 1; diff --git a/src/client/views/nodes/LinkEditor.tsx b/src/client/views/nodes/LinkEditor.tsx index e6cc50620..a97ec8831 100644 --- a/src/client/views/nodes/LinkEditor.tsx +++ b/src/client/views/nodes/LinkEditor.tsx @@ -177,9 +177,10 @@ export class LinkGroupEditor extends React.Component<LinkGroupEditorProps> { LinkManager.Instance.deleteGroupType(groupType); } - copyGroup = (groupType: string): void => { + copyGroup = async (groupType: string): Promise<void> => { let sourceGroupDoc = this.props.groupDoc; - let sourceMdDoc = Cast(sourceGroupDoc.metadata, Doc, new Doc); + const sourceMdDoc = await Cast(sourceGroupDoc.metadata, Doc); + if (!sourceMdDoc) return; let destDoc = LinkManager.Instance.getOppositeAnchor(this.props.linkDoc, this.props.sourceDoc); // let destGroupList = LinkManager.Instance.getAnchorGroups(this.props.linkDoc, destDoc); diff --git a/src/client/views/nodes/LinkMenuItem.tsx b/src/client/views/nodes/LinkMenuItem.tsx index 4dee6741f..9728671c0 100644 --- a/src/client/views/nodes/LinkMenuItem.tsx +++ b/src/client/views/nodes/LinkMenuItem.tsx @@ -56,11 +56,13 @@ export class LinkMenuItem extends React.Component<LinkMenuItemProps> { let mdRows: Array<JSX.Element> = []; if (groupDoc) { - let mdDoc = Cast(groupDoc.metadata, Doc, new Doc); - let keys = LinkManager.Instance.getMetadataKeysInGroup(this.props.groupType);//groupMetadataKeys.get(this.props.groupType); - mdRows = keys.map(key => { - return (<div key={key} className="link-metadata-row"><b>{key}</b>: {StrCast(mdDoc[key])}</div>); - }); + let mdDoc = Cast(groupDoc.metadata, Doc, null); + if (mdDoc) { + let keys = LinkManager.Instance.getMetadataKeysInGroup(this.props.groupType);//groupMetadataKeys.get(this.props.groupType); + mdRows = keys.map(key => { + return (<div key={key} className="link-metadata-row"><b>{key}</b>: {StrCast(mdDoc[key])}</div>); + }); + } } return (<div className="link-metadata">{mdRows}</div>); diff --git a/src/client/views/pdf/PDFMenu.tsx b/src/client/views/pdf/PDFMenu.tsx index f93b2e59f..d6970e7f4 100644 --- a/src/client/views/pdf/PDFMenu.tsx +++ b/src/client/views/pdf/PDFMenu.tsx @@ -3,11 +3,8 @@ import "./PDFMenu.scss"; import { observable, action, runInAction } from "mobx"; import { observer } from "mobx-react"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { emptyFunction, returnZero, returnTrue, returnFalse } from "../../../Utils"; +import { emptyFunction, returnFalse } from "../../../Utils"; import { Doc } from "../../../new_fields/Doc"; -import { DragManager } from "../../util/DragManager"; -import { DocUtils } from "../../documents/Documents"; -import { PresentationView } from "../presentationview/PresentationView"; @observer export default class PDFMenu extends React.Component { @@ -20,7 +17,7 @@ export default class PDFMenu extends React.Component { @observable private _transitionDelay: string = ""; - StartDrag: (e: PointerEvent) => void = emptyFunction; + StartDrag: (e: PointerEvent, ele: HTMLDivElement) => void = emptyFunction; Highlight: (d: Doc | undefined, color: string | undefined) => void = emptyFunction; Delete: () => void = emptyFunction; Snippet: (marquee: { left: number, top: number, width: number, height: number }) => void = emptyFunction; @@ -35,9 +32,10 @@ export default class PDFMenu extends React.Component { private _offsetY: number = 0; private _offsetX: number = 0; - private _mainCont: React.RefObject<HTMLDivElement>; + private _mainCont: React.RefObject<HTMLDivElement> = React.createRef(); + private _commentCont: React.RefObject<HTMLDivElement> = React.createRef(); + private _snippetButton: React.RefObject<HTMLButtonElement> = React.createRef(); private _dragging: boolean = false; - private _snippetButton: React.RefObject<HTMLButtonElement>; @observable private _keyValue: string = ""; @observable private _valueValue: string = ""; @observable private _added: boolean = false; @@ -46,9 +44,6 @@ export default class PDFMenu extends React.Component { super(props); PDFMenu.Instance = this; - - this._mainCont = React.createRef(); - this._snippetButton = React.createRef(); } pointerDown = (e: React.PointerEvent) => { @@ -69,7 +64,7 @@ export default class PDFMenu extends React.Component { return; } - this.StartDrag(e); + this.StartDrag(e, this._commentCont.current!); this._dragging = true; } @@ -246,7 +241,7 @@ export default class PDFMenu extends React.Component { style={this.Highlighting ? { backgroundColor: "#121212" } : {}}> <FontAwesomeIcon icon="highlighter" size="lg" style={{ transition: "transform 0.1s", transform: this.Highlighting ? "" : "rotate(-45deg)" }} /> </button>, - <button className="pdfMenu-button" title="Drag to Annotate" onPointerDown={this.pointerDown}><FontAwesomeIcon icon="comment-alt" size="lg" key="2" /></button>, + <button className="pdfMenu-button" title="Drag to Annotate" ref={this._commentCont} onPointerDown={this.pointerDown}><FontAwesomeIcon icon="comment-alt" size="lg" key="2" /></button>, this.Status === "snippet" ? <button className="pdfMenu-button" title="Drag to Snippetize Selection" onPointerDown={this.snippetStart} ref={this._snippetButton}><FontAwesomeIcon icon="cut" size="lg" /></button> : undefined, <button className="pdfMenu-button" title="Pin Menu" onClick={this.togglePin} key="3" style={this.Pinned ? { backgroundColor: "#121212" } : {}}> diff --git a/src/client/views/pdf/Page.tsx b/src/client/views/pdf/Page.tsx index 92f5390ae..49eac71c4 100644 --- a/src/client/views/pdf/Page.tsx +++ b/src/client/views/pdf/Page.tsx @@ -152,7 +152,7 @@ export default class Page extends React.Component<IPageProps> { * start a drag event and create or put the necessary info into the drag event. */ @action - startDrag = (e: PointerEvent): void => { + startDrag = (e: PointerEvent, ele: HTMLDivElement): void => { e.preventDefault(); e.stopPropagation(); let thisDoc = this.props.parent.Document; @@ -163,7 +163,7 @@ export default class Page extends React.Component<IPageProps> { // create dragData and star tdrag let dragData = new DragManager.AnnotationDragData(thisDoc, annotationDoc, targetDoc); if (this._textLayer.current) { - DragManager.StartAnnotationDrag([this._textLayer.current], dragData, e.pageX, e.pageY, { + DragManager.StartAnnotationDrag([ele], dragData, e.pageX, e.pageY, { handlers: { dragComplete: emptyFunction, }, diff --git a/src/client/views/search/SearchItem.tsx b/src/client/views/search/SearchItem.tsx index 51f0ed607..804ffa7f5 100644 --- a/src/client/views/search/SearchItem.tsx +++ b/src/client/views/search/SearchItem.tsx @@ -187,10 +187,10 @@ export class SearchItem extends React.Component<SearchItemProps> { if (this.props.doc.type === DocTypes.LINK) { if (this.props.doc.anchor1 && this.props.doc.anchor2) { - let doc1 = Cast(this.props.doc.anchor1, Doc, new Doc()); - let doc2 = Cast(this.props.doc.anchor2, Doc, new Doc()); - doc1.libraryBrush = true; - doc2.libraryBrush = true; + let doc1 = Cast(this.props.doc.anchor1, Doc, null); + let doc2 = Cast(this.props.doc.anchor2, Doc, null); + doc1 && (doc1.libraryBrush = true); + doc2 && (doc2.libraryBrush = true); } } else { let docViews: DocumentView[] = DocumentManager.Instance.getAllDocumentViews(this.props.doc); @@ -204,10 +204,10 @@ export class SearchItem extends React.Component<SearchItemProps> { if (this.props.doc.type === DocTypes.LINK) { if (this.props.doc.anchor1 && this.props.doc.anchor2) { - let doc1 = Cast(this.props.doc.anchor1, Doc, new Doc()); - let doc2 = Cast(this.props.doc.anchor2, Doc, new Doc()); - doc1.libraryBrush = false; - doc2.libraryBrush = false; + let doc1 = Cast(this.props.doc.anchor1, Doc, null); + let doc2 = Cast(this.props.doc.anchor2, Doc, null); + doc1 && (doc1.libraryBrush = false); + doc2 && (doc2.libraryBrush = false); } } else { let docViews: DocumentView[] = DocumentManager.Instance.getAllDocumentViews(this.props.doc); @@ -241,7 +241,7 @@ export class SearchItem extends React.Component<SearchItemProps> { render() { return ( <div className="search-overview" onPointerDown={this.pointerDown} onContextMenu={this.onContextMenu}> - <div className="search-item" onPointerEnter={this.highlightDoc} onPointerLeave={this.unHighlightDoc} ref={this.collectionRef} id="result" + <div className="search-item" onPointerEnter={this.highlightDoc} onPointerLeave={this.unHighlightDoc} id="result" onClick={this.onClick} onPointerDown={this.pointerDown} > <div className="main-search-info"> <div title="Drag as document" onPointerDown={this.onPointerDown}> <FontAwesomeIcon icon="file" size="lg" /> </div> diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index c361e3032..aa13b1d7a 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -9,6 +9,7 @@ import { ObjectField } from "./ObjectField"; import { RefField, FieldId } from "./RefField"; import { ToScriptString, SelfProxy, Parent, OnUpdate, Self, HandleUpdate, Update, Id } from "./FieldSymbols"; import { scriptingGlobal } from "../client/util/Scripting"; +import { List } from "./List"; export namespace Field { export function toScriptString(field: Field): string { @@ -241,12 +242,24 @@ export namespace Doc { return Array.from(results); } - export function AddDocToList(target: Doc, key: string, doc: Doc, relativeTo?: Doc, before?: boolean) { + export function AddDocToList(target: Doc, key: string, doc: Doc, relativeTo?: Doc, before?: boolean, first?: boolean, allowDuplicates?: boolean) { + if (target[key] === undefined) { + Doc.GetProto(target)[key] = new List<Doc>(); + } let list = Cast(target[key], listSpec(Doc)); if (list) { - let ind = relativeTo ? list.indexOf(relativeTo) : -1; - if (ind === -1) list.push(doc); - else list.splice(before ? ind : ind + 1, 0, doc); + if (allowDuplicates !== true) { + let pind = list.reduce((l, d, i) => d instanceof Doc && Doc.AreProtosEqual(d, doc) ? i : l, -1); + if (pind !== -1) { + list.splice(pind, 1); + } + } + if (first) list.splice(0, 0, doc); + else { + let ind = relativeTo ? list.indexOf(relativeTo) : -1; + if (ind === -1) list.push(doc); + else list.splice(before ? ind : ind + 1, 0, doc); + } } return true; } diff --git a/src/new_fields/Types.ts b/src/new_fields/Types.ts index 8dd893aa4..39d384d64 100644 --- a/src/new_fields/Types.ts +++ b/src/new_fields/Types.ts @@ -45,9 +45,10 @@ export interface Interface { [key: string]: InterfaceValue; // [key: string]: ToConstructor<Field> | ListSpec<Field[]>; } +export type WithoutRefField<T extends Field> = T extends RefField ? never : T; export function Cast<T extends ToConstructor<Field> | ListSpec<Field>>(field: FieldResult, ctor: T): FieldResult<ToType<T>>; -export function Cast<T extends ToConstructor<Field> | ListSpec<Field>>(field: FieldResult, ctor: T, defaultVal: WithoutList<ToType<T>> | null): WithoutList<ToType<T>>; +export function Cast<T extends ToConstructor<Field> | ListSpec<Field>>(field: FieldResult, ctor: T, defaultVal: WithoutList<WithoutRefField<ToType<T>>> | null): WithoutList<ToType<T>>; export function Cast<T extends ToConstructor<Field> | ListSpec<Field>>(field: FieldResult, ctor: T, defaultVal?: ToType<T> | null): FieldResult<ToType<T>> | undefined { if (field instanceof Promise) { return defaultVal === undefined ? field.then(f => Cast(f, ctor) as any) as any : defaultVal === null ? undefined : defaultVal; diff --git a/src/new_fields/util.ts b/src/new_fields/util.ts index abb777adf..b5e50d501 100644 --- a/src/new_fields/util.ts +++ b/src/new_fields/util.ts @@ -2,7 +2,6 @@ import { UndoManager } from "../client/util/UndoManager"; import { Doc, Field } from "./Doc"; import { SerializationHelper } from "../client/util/SerializationHelper"; import { ProxyField } from "./Proxy"; -import { FieldValue } from "./Types"; import { RefField } from "./RefField"; import { ObjectField } from "./ObjectField"; import { action } from "mobx"; @@ -13,6 +12,7 @@ function _readOnlySetter(): never { throw new Error("Documents can't be modified in read-only mode"); } const _setterImpl = action(function (target: any, prop: string | symbol | number, value: any, receiver: any): boolean { + //console.log("-set " + target[SelfProxy].title + "(" + target[SelfProxy][prop] + ")." + prop.toString() + " = " + value); if (SerializationHelper.IsSerializing()) { target[prop] = value; return true; diff --git a/src/server/GarbageColletor.ts b/src/server/GarbageColletor.ts new file mode 100644 index 000000000..f26b0cec6 --- /dev/null +++ b/src/server/GarbageColletor.ts @@ -0,0 +1,51 @@ +import { Database } from './database'; + +function addDoc(doc: any, ids: string[]) { + for (const key in doc) { + if (!doc.hasOwnProperty(key)) { + continue; + } + const field = doc[key]; + if (!(field instanceof Object)) { + continue; + } + if (field.__type === "proxy") { + ids.push(field.fieldId); + } else if (field.__type === "list") { + addDoc(field.fields, ids); + } + } +} + +async function GarbageCollect() { + // await new Promise(res => setTimeout(res, 3000)); + const cursor = await Database.Instance.query({}, 'users'); + const users = await cursor.toArray(); + const ids: string[] = users.map(user => user.userDocumentId); + const visited = new Set<string>(); + + while (ids.length) { + const id = ids.pop()!; + if (visited.has(id)) continue; + const doc = await new Promise<{ [key: string]: any }>(res => Database.Instance.getDocument(id, res, "newDocuments")); + if (doc === undefined) { + console.log(`Couldn't find field with Id ${id}`); + continue; + } + visited.add(id); + addDoc(doc.fields, ids); + console.log(`To Go: ${ids.length}, visited: ${visited.size}`); + } + + console.log(`Done: ${visited.size}`); + + cursor.close(); + + const toDeleteCursor = await Database.Instance.query({ _id: { $nin: Array.from(visited) } }); + const toDelete = (await toDeleteCursor.toArray()).map(doc => doc._id); + toDeleteCursor.close(); + const result = await Database.Instance.delete({ _id: { $in: toDelete } }, "newDocuments"); + console.log(`${result.deletedCount} documents deleted`); +} + +GarbageCollect(); diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts index 816c5f269..e328d6e5c 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -10,7 +10,7 @@ import { CollectionView } from "../../../client/views/collections/CollectionView import { Doc } from "../../../new_fields/Doc"; import { List } from "../../../new_fields/List"; import { listSpec } from "../../../new_fields/Schema"; -import { Cast } from "../../../new_fields/Types"; +import { Cast, FieldValue } from "../../../new_fields/Types"; import { RouteStore } from "../../RouteStore"; export class CurrentUserUtils { @@ -32,7 +32,11 @@ export class CurrentUserUtils { doc.dropAction = "alias"; doc.layout = CollectionView.LayoutString(); doc.title = this.email; + this.updateUserDocument(doc); doc.data = new List<Doc>(); + doc.gridGap = 5; + doc.xMargin = 5; + doc.yMargin = 5; doc.excludeFromLibrary = true; doc.optionalRightCollection = Docs.StackingDocument([], { title: "New mobile uploads" }); // doc.library = Docs.TreeDocument([doc], { title: `Library: ${CurrentUserUtils.email}` }); @@ -40,6 +44,29 @@ export class CurrentUserUtils { return doc; } + static updateUserDocument(doc: Doc) { + if (doc.workspaces === undefined) { + const workspaces = Docs.TreeDocument([], { title: "Workspaces", height: 100 }); + workspaces.excludeFromLibrary = true; + workspaces.workspaceLibrary = true; + doc.workspaces = workspaces; + } + if (doc.recentlyClosed === undefined) { + const recentlyClosed = Docs.TreeDocument([], { title: "Recently Closed", height: 75 }); + recentlyClosed.excludeFromLibrary = true; + doc.recentlyClosed = recentlyClosed; + } + if (doc.sidebar === undefined) { + const sidebar = Docs.StackingDocument([doc.workspaces as Doc, doc, doc.recentlyClosed as Doc], { title: "Sidebar" }); + sidebar.excludeFromLibrary = true; + sidebar.gridGap = 5; + sidebar.xMargin = 5; + sidebar.yMargin = 5; + doc.sidebar = sidebar; + } + + } + public static async loadCurrentUser(): Promise<any> { let userPromise = rp.get(DocServer.prepend(RouteStore.getCurrUser)).then(response => { if (response) { @@ -52,8 +79,14 @@ export class CurrentUserUtils { }); let userDocPromise = await rp.get(DocServer.prepend(RouteStore.getUserDocumentId)).then(id => { if (id) { - return DocServer.GetRefField(id).then(field => - runInAction(() => this.user_document = field instanceof Doc ? field : this.createUserDocument(id))); + return DocServer.GetRefField(id).then(async field => { + if (field instanceof Doc) { + await this.updateUserDocument(field); + runInAction(() => this.user_document = field); + } else { + runInAction(() => this.user_document = this.createUserDocument(id)); + } + }); } else { throw new Error("There should be a user id! Why does Dash think there isn't one?"); } diff --git a/src/server/database.ts b/src/server/database.ts index d240bd909..a17447629 100644 --- a/src/server/database.ts +++ b/src/server/database.ts @@ -41,11 +41,17 @@ export class Database { } } - public delete(id: string, collectionName = Database.DocumentsCollection) { + public delete(query: any, collectionName?: string): Promise<mongodb.DeleteWriteOpResultObject>; + public delete(id: string, collectionName?: string): Promise<mongodb.DeleteWriteOpResultObject>; + public delete(id: any, collectionName = Database.DocumentsCollection) { + if (typeof id === "string") { + id = { _id: id }; + } if (this.db) { - this.db.collection(collectionName).remove({ id: id }); + const db = this.db; + return new Promise(res => db.collection(collectionName).deleteMany(id, (err, result) => res(result))); } else { - this.onConnect.push(() => this.delete(id, collectionName)); + return new Promise(res => this.onConnect.push(() => res(this.delete(id, collectionName)))); } } @@ -125,7 +131,7 @@ export class Database { return Promise.resolve<mongodb.Cursor>(this.db.collection(collectionName).find(query)); } else { return new Promise<mongodb.Cursor>(res => { - this.onConnect.push(() => res(this.query(query))); + this.onConnect.push(() => res(this.query(query, collectionName))); }); } } diff --git a/src/server/index.ts b/src/server/index.ts index a93940907..bf946fc9f 100644 --- a/src/server/index.ts +++ b/src/server/index.ts @@ -295,9 +295,10 @@ app.post( const file = path.basename(files[name].path); const ext = path.extname(file); let resizers = [ - { resizer: sharp().resize(100, undefined, { withoutEnlargement: true }), suffix: "_s" }, - { resizer: sharp().resize(400, undefined, { withoutEnlargement: true }), suffix: "_m" }, - { resizer: sharp().resize(900, undefined, { withoutEnlargement: true }), suffix: "_l" }, + { resizer: sharp().rotate(), suffix: "_o" }, + { resizer: sharp().resize(100, undefined, { withoutEnlargement: true }).rotate(), suffix: "_s" }, + { resizer: sharp().resize(400, undefined, { withoutEnlargement: true }).rotate(), suffix: "_m" }, + { resizer: sharp().resize(900, undefined, { withoutEnlargement: true }).rotate(), suffix: "_l" }, ]; let isImage = false; if (pngTypes.includes(ext)) { diff --git a/tance.jumpToDocument(linkedFwdDocs[altKey 1 0], ctrlKey, false, document = this.props.addDocTab(document, maxLocation), linkedFwdPage[altKey 1 0], targetContext); b/tance.jumpToDocument(linkedFwdDocs[altKey 1 0], ctrlKey, false, document = this.props.addDocTab(document, maxLocation), linkedFwdPage[altKey 1 0], targetContext); deleted file mode 100644 index 0aa3ad47b..000000000 --- a/tance.jumpToDocument(linkedFwdDocs[altKey 1 0], ctrlKey, false, document = this.props.addDocTab(document, maxLocation), linkedFwdPage[altKey 1 0], targetContext); +++ /dev/null @@ -1,792 +0,0 @@ -[33mcommit cc1f3b32d60786b56280a8b3c00059aa7823af89[m -Merge: a81677c deb8576 -Author: Fawn <fangrui_tong@brown.edu> -Date: Wed Jun 26 14:54:46 2019 -0400 - - merge - -[33mcommit a81677c7dffafa5134d4c5cbe893f7a886eaab63[m -Author: Fawn <fangrui_tong@brown.edu> -Date: Wed Jun 26 14:48:16 2019 -0400 - - can clear links on a doc - -[33mcommit 69e37491908b5c189b94f780994c1f142c69be2e[m -Author: Fawn <fangrui_tong@brown.edu> -Date: Wed Jun 26 14:15:40 2019 -0400 - - minor changes - -[33mcommit deb85766ac5648cc8e3ab4bf9d182ac5bbbbe144[m -Merge: 219cabb 5e47775 -Author: Sam Wilkins <35748010+samwilkins333@users.noreply.github.com> -Date: Wed Jun 26 12:51:18 2019 -0400 - - Merge pull request #170 from browngraphicslab/presentation-selection-mohammad - - Presentation selection mohammad - -[33mcommit 5e477755b392128ab8b39c082f16dd67708be0d2[m -Merge: 444f970 6d1f161 -Author: Sam Wilkins <samuel_wilkins@brown.edu> -Date: Wed Jun 26 12:48:45 2019 -0400 - - Merge branch 'presentation-selection-mohammad' of https://github.com/browngraphicslab/Dash-Web into presentation-selection-mohammad - -[33mcommit 444f970365a4280376e929e78c16090f6ae92739[m -Merge: 64ffa0a 219cabb -Author: Sam Wilkins <samuel_wilkins@brown.edu> -Date: Wed Jun 26 12:48:40 2019 -0400 - - merged with master - -[33mcommit 6d1f161de3c27ec07673b5e48a915961177b57b6[m -Author: Sam Wilkins <35748010+samwilkins333@users.noreply.github.com> -Date: Wed Jun 26 12:39:54 2019 -0400 - - long line wrap - -[33mcommit f0632e4f6b608d05ef6d9f77d93da259c58c1e8d[m -Author: Sam Wilkins <35748010+samwilkins333@users.noreply.github.com> -Date: Wed Jun 26 12:33:16 2019 -0400 - - long line wrap - -[33mcommit 0d5e2537520ca1e6a6b52f4d0f03aa2bcfc6c5c6[m -Author: Sam Wilkins <35748010+samwilkins333@users.noreply.github.com> -Date: Wed Jun 26 12:30:16 2019 -0400 - - cleanup - -[33mcommit 8954bac59b50aa3618625379a17dbefe9aceca72[m -Author: Sam Wilkins <35748010+samwilkins333@users.noreply.github.com> -Date: Wed Jun 26 12:29:07 2019 -0400 - - removed console.logs - -[33mcommit d0ff42632f8a155303e11945a1a974a15052f0db[m -Author: Fawn <fangrui_tong@brown.edu> -Date: Wed Jun 26 11:40:36 2019 -0400 - - link menu styling - -[33mcommit a3c4aa24a9e9074da8f2421954f610c8178e10b1[m -Author: Fawn <fangrui_tong@brown.edu> -Date: Tue Jun 25 21:28:15 2019 -0400 - - link metadata values appear on first load - -[33mcommit ca8a78de9957ad27d345ad51fdaee9dae3f096bd[m -Author: Fawn <fangrui_tong@brown.edu> -Date: Tue Jun 25 20:44:34 2019 -0400 - - can't link to containing collection - -[33mcommit 2d300b0cd3d02c900865c61eacd539efed5289e6[m -Author: Fawn <fangrui_tong@brown.edu> -Date: Tue Jun 25 20:18:14 2019 -0400 - - fixed link metadata rendering bug - -[33mcommit 2a698e88da5ef0a9fee1ff4ee69746f1242798c9[m -Author: Fawn <fangrui_tong@brown.edu> -Date: Tue Jun 25 18:32:17 2019 -0400 - - fixed render links in treeview - -[33mcommit 7abe170ce5bd0c415e23456eb2bed26e8fdee7aa[m -Merge: 41cf1e8 219cabb -Author: Fawn <fangrui_tong@brown.edu> -Date: Tue Jun 25 18:23:26 2019 -0400 - - merge - -[33mcommit 41cf1e8536964764f18ab752140e484e36cbe464[m -Author: Fawn <fangrui_tong@brown.edu> -Date: Tue Jun 25 17:09:36 2019 -0400 - - links can save - -[33mcommit 64ffa0accfc872c81035079527952aabaf56c6f6[m -Author: Mohammad Amoush <mohammad_amoush@brown.edu> -Date: Tue Jun 25 13:16:45 2019 -0400 - - Small Css Fix On weight - -[33mcommit 219cabb3fe42ab199550efc3423b7aaed4e1ee93[m -Author: Tyler Schicke <tyler_schicke@brown.edu> -Date: Mon Jun 24 22:45:19 2019 -0400 - - Switched shift drag of tabs to normal drag and added drag target for document drag - -[33mcommit d475b19e9ba7bc8870ec7bc1e10b5cc88decea0b[m -Author: Tyler Schicke <tyler_schicke@brown.edu> -Date: Mon Jun 24 15:56:42 2019 -0400 - - fixed crash - -[33mcommit 522970375fe0227f9221a7e8be02875afd74ca63[m -Author: Fawn <fangrui_tong@brown.edu> -Date: Mon Jun 24 14:01:29 2019 -0400 - - link menu styling - -[33mcommit addf0e443f64951a437701f0d5a087c1d5968faf[m -Merge: c9f77d5 d01039b -Author: tschicke-brown <tyler_schicke@brown.edu> -Date: Mon Jun 24 13:57:02 2019 -0400 - - Merge pull request #167 from browngraphicslab/schema_fixes - - Schema and scripting fixes - -[33mcommit d01039b10f0ebd328224c0b1a190b0f884a7c727[m -Merge: 6abf829 c9f77d5 -Author: Tyler Schicke <tyler_schicke@brown.edu> -Date: Mon Jun 24 13:56:30 2019 -0400 - - Merge branch 'master' of github-tsch-brown:browngraphicslab/Dash-Web into schema_fixes - -[33mcommit c9f77d5aab98e6e7865cdcad957d5c937631775d[m -Author: Tyler Schicke <tyler_schicke@brown.edu> -Date: Mon Jun 24 13:41:39 2019 -0400 - - Added ReadOnly mode for docs and changed computed values a bit - -[33mcommit e18662f2fa9e1d3dd1b0eb3b5531092258d05972[m -Author: Mohammad Amoush <mohammad_amoush@brown.edu> -Date: Mon Jun 24 12:42:44 2019 -0400 - - Refactoring - -[33mcommit 52051829373bc4acfe9d705b64c30e3fddebf439[m -Author: Tyler Schicke <tyler_schicke@brown.edu> -Date: Mon Jun 24 10:49:05 2019 -0400 - - Fixed image size stuff - -[33mcommit ac781d2fb714ca26fb364d00d5aeb7a20b008655[m -Author: Tyler Schicke <tyler_schicke@brown.edu> -Date: Mon Jun 24 10:26:57 2019 -0400 - - Changed how zooming works - -[33mcommit 6e5cd0e991e2e6d7ae8de1d73ff273ba0737355c[m -Author: Tyler Schicke <tschicke@gmail.com> -Date: Sun Jun 23 17:23:33 2019 -0400 - - Fixed shift dragging with no open panes - -[33mcommit 32ef8d83d5829e2faadbebaf6f9b694df5d7ea02[m -Author: Fawn <fangrui_tong@brown.edu> -Date: Fri Jun 21 17:41:20 2019 -0400 - - link menu styling - -[33mcommit 7962aff8431b692af5229cd8e6c390bbe1110336[m -Author: Fawn <fangrui_tong@brown.edu> -Date: Fri Jun 21 16:29:31 2019 -0400 - - link menu styling - -[33mcommit a4b34adcb34184728be0b69b33a561f6d10f0a98[m -Author: Fawn <fangrui_tong@brown.edu> -Date: Fri Jun 21 16:27:03 2019 -0400 - - can drag just a group of links on a doc - -[33mcommit e1f5f341854944c533efdb7d36306edd1e1dc747[m -Author: Mohammad Amoush <mohammad_amoush@brown.edu> -Date: Fri Jun 21 14:53:08 2019 -0400 - - Some More documentation - -[33mcommit 542f25d4af36cf0948696d45afba2e9e19f5bc37[m -Author: Mohammad Amoush <mohammad_amoush@brown.edu> -Date: Fri Jun 21 14:47:11 2019 -0400 - - Redo Grouping Fixed - -[33mcommit 60f9122ea31d660d60d5429890c4eb0ef6d8613b[m -Author: Fawn <fangrui_tong@brown.edu> -Date: Fri Jun 21 13:41:25 2019 -0400 - - following link without viewdoc opens it to right - -[33mcommit d78c651322ad228152b862eaa378946fe65cc9f9[m -Author: Fawn <fangrui_tong@brown.edu> -Date: Fri Jun 21 13:32:23 2019 -0400 - - dragged links from menu are aliases - -[33mcommit 179afa6e80631fcb8899408c3961bf1757e5b19b[m -Merge: ca5e29f a40e7bb -Author: Bob Zeleznik <zzzman@gmail.com> -Date: Thu Jun 20 22:23:40 2019 -0400 - - Merge branch 'master' of https://github.com/browngraphicslab/Dash-Web - -[33mcommit ca5e29fdc7c238274eaf90682a8fa2ddc90e4e17[m -Author: Bob Zeleznik <zzzman@gmail.com> -Date: Thu Jun 20 22:22:57 2019 -0400 - - fix to open on right, fix to image drag fro web, and layout fixes for stacking view multi-column - -[33mcommit a40e7bb5e9d1256002083d7e3f3c4db60cd8e9df[m -Author: Sam Wilkins <35748010+samwilkins333@users.noreply.github.com> -Date: Thu Jun 20 19:41:39 2019 -0400 - - Fixed missed pointer up event - -[33mcommit f4b75a7c921181faeeee04fbd57cd24fbd57523e[m -Author: Mohammad Amoush <mohammad_amoush@brown.edu> -Date: Thu Jun 20 19:16:42 2019 -0400 - - Undo/Redo First Version - -[33mcommit b1a2871fcca57ce934b8613b315a08eede188669[m -Author: Fawn <fangrui_tong@brown.edu> -Date: Thu Jun 20 19:03:16 2019 -0400 - - link menu styling - -[33mcommit f2b54dc49205f8ea8944e26e43662a0c8dd08ed0[m -Merge: 0cab79a 7d0f6c1 -Author: Tyler Schicke <tyler_schicke@brown.edu> -Date: Thu Jun 20 18:36:04 2019 -0400 - - Merge branch 'master' of github-tsch-brown:browngraphicslab/Dash-Web - -[33mcommit 0cab79a50719719e1dade40520a6967f7aa8f951[m -Author: Tyler Schicke <tyler_schicke@brown.edu> -Date: Thu Jun 20 18:35:45 2019 -0400 - - Added debug and release modes to server and client - -[33mcommit fbfe9faca199b6dedd6844f1fa20cc02060a3c5a[m -Author: Fawn <fangrui_tong@brown.edu> -Date: Thu Jun 20 18:25:49 2019 -0400 - - can see what docs are linked to in treeview: - -[33mcommit 7d0f6c18489f7155818611721985d9610b08d8e7[m -Merge: d2dfc0f 46a2a9e -Author: yipstanley <stanley_yip@brown.edu> -Date: Thu Jun 20 17:50:46 2019 -0400 - - Merge branch 'master' of https://github.com/browngraphicslab/Dash-Web - -[33mcommit 1f172642d12c4669960b8526324e4bd034994be4[m -Author: Tyler Schicke <tyler_schicke@brown.edu> -Date: Thu Jun 20 17:44:24 2019 -0400 - - Added arrange documents in grid command - -[33mcommit d2dfc0f9d35f0084a7c0dea73215f5d21055f2f3[m -Author: yipstanley <stanley_yip@brown.edu> -Date: Thu Jun 20 17:17:14 2019 -0400 - - pdf page sizes loading error - -[33mcommit e6ebed17e6ddb2ccee81d65fcb451a9b54302762[m -Author: Fawn <fangrui_tong@brown.edu> -Date: Thu Jun 20 17:12:48 2019 -0400 - - links can be made from freeform view to treeview - -[33mcommit 46a2a9e1f10b63feeb21a1e186daeaef2ccbcda4[m -Merge: a39b285 a5dc0e0 -Author: bob <bcz@cs.brown.edu> -Date: Thu Jun 20 17:11:29 2019 -0400 - - Merge branch 'master' of https://github.com/browngraphicslab/Dash-Web - -[33mcommit a39b2854b848006c19460685d7bf4005a9f650ae[m -Author: bob <bcz@cs.brown.edu> -Date: Thu Jun 20 17:09:50 2019 -0400 - - moved AddDocToList to Doc utils - -[33mcommit a5dc0e04add05f2f5bf1e17f1ac0a5e0aba1ea41[m -Author: Tyler Schicke <tyler_schicke@brown.edu> -Date: Thu Jun 20 16:27:44 2019 -0400 - - Added hidden flag to documents - -[33mcommit e88538bb8af2ba648da2326d0f6edd3e0186766e[m -Author: Mohammad Amoush <mohammad_amoush@brown.edu> -Date: Thu Jun 20 15:45:07 2019 -0400 - - Title changing to presentations added - -[33mcommit 9b3e80def0be6c09c31b5176817a54323d217d81[m -Author: Tyler Schicke <tyler_schicke@brown.edu> -Date: Thu Jun 20 15:06:41 2019 -0400 - - Handled more events in editable view - -[33mcommit 1f24c5010a1cf6365265ea1f02327bb81a98134a[m -Author: Tyler Schicke <tyler_schicke@brown.edu> -Date: Thu Jun 20 14:54:55 2019 -0400 - - Doc.GetProto change and swapped KVP syntax - -[33mcommit 4360287e6cafcb59af1ae62fc31ddc161bcf2e51[m -Author: Fawn <fangrui_tong@brown.edu> -Date: Thu Jun 20 12:56:13 2019 -0400 - - styling of link proxy - -[33mcommit 711abbeba69e4d9afc634b8edf019b12b6dff915[m -Author: Mohammad Amoush <mohammad_amoush@brown.edu> -Date: Thu Jun 20 12:54:41 2019 -0400 - - Documentation and reset Presentation at removal fixed - -[33mcommit a0246ef84396545f79fc4a8b21de1a56cbf06aca[m -Author: Fawn <fangrui_tong@brown.edu> -Date: Thu Jun 20 11:34:28 2019 -0400 - - merge - -[33mcommit 8dbfb3029a99eaf37a5234e9d9e33cc64f779b03[m -Merge: af8e5cf e9d62f4 -Author: Tyler Schicke <tyler_schicke@brown.edu> -Date: Thu Jun 20 11:33:01 2019 -0400 - - Merge branch 'master' of github-tsch-brown:browngraphicslab/Dash-Web - -[33mcommit af8e5cf1bfbfa2d57b4fd89c72306a71d8cabe1d[m -Author: Tyler Schicke <tyler_schicke@brown.edu> -Date: Thu Jun 20 11:32:54 2019 -0400 - - Fixed context menu search - -[33mcommit cd2db5bf11fb89e3cd7016f7f798d65698c74c5e[m -Merge: 73f0378 e9d62f4 -Author: Fawn <fangrui_tong@brown.edu> -Date: Thu Jun 20 11:31:15 2019 -0400 - - merge - -[33mcommit 73f03785f938542a91b28b35043f2feda2bc1432[m -Author: Fawn <fangrui_tong@brown.edu> -Date: Thu Jun 20 11:26:33 2019 -0400 - - merge - -[33mcommit e9d62f4ca0dbeb57e46239047041a8a04da7b504[m -Author: bob <bcz@cs.brown.edu> -Date: Thu Jun 20 11:26:16 2019 -0400 - - changed color picker. fixed delting selected docs. fixed scaling items in nested panels. - -[33mcommit a5478b2d4cc3b66c6b58471cbb05c623d0109724[m -Author: Tyler Schicke <tyler_schicke@brown.edu> -Date: Thu Jun 20 10:04:51 2019 -0400 - - "Fixed" search - -[33mcommit 01aee875e626c695fe208addaaa6f58aad387dd6[m -Author: Tyler Schicke <tyler_schicke@brown.edu> -Date: Thu Jun 20 10:02:08 2019 -0400 - - Mostly keep context menu on screen - -[33mcommit 38de022621175bda7410df4444fcd2bbee0919cb[m -Author: Bob Zeleznik <zzzman@gmail.com> -Date: Wed Jun 19 23:43:47 2019 -0400 - - slight tweaks. - -[33mcommit 9e55bfaad39aa47ab0594c6af7f1aa68e2a8db7a[m -Merge: 118ecb1 827c589 -Author: Bob Zeleznik <zzzman@gmail.com> -Date: Wed Jun 19 22:40:57 2019 -0400 - - Merge branch 'master' of https://github.com/browngraphicslab/Dash-Web - -[33mcommit 118ecb14ce519bcbade12b3d52e11b22fcc371b3[m -Author: Bob Zeleznik <zzzman@gmail.com> -Date: Wed Jun 19 22:40:54 2019 -0400 - - cleaned up and enhanced tree view - -[33mcommit c5e401cb0a7fec2279ceecbc8d1429dcdd2f04b9[m -Author: Fawn <fangrui_tong@brown.edu> -Date: Wed Jun 19 22:27:21 2019 -0400 - - buttons on cut links functional except for when dragged from link menu - -[33mcommit 6fc6054dc7aea144fd967a8cb3fe7d8fe5ec6d6d[m -Author: Mohammad Amoush <mohammad_amoush@brown.edu> -Date: Wed Jun 19 19:13:30 2019 -0400 - - Width of the presentations fixed, removal of presentations option added, backUP group and normal groups updated when a doc is removed from presentation by removing it from both - -[33mcommit 827c58950b649629c84211d41fdd4d041287801e[m -Merge: 05e50f2 96c26c5 -Author: Tyler Schicke <tyler_schicke@brown.edu> -Date: Wed Jun 19 18:49:50 2019 -0400 - - Merge branch 'master' of github-tsch-brown:browngraphicslab/Dash-Web - -[33mcommit 96c26c57527d443784bde9752551bfa10b3ce4d2[m -Author: Bob Zeleznik <zzzman@gmail.com> -Date: Wed Jun 19 18:34:45 2019 -0400 - - removed marquee summarizing icon - -[33mcommit 05e50f27a15e8a02ffb27606c51026d1b85bc677[m -Author: Tyler Schicke <tyler_schicke@brown.edu> -Date: Wed Jun 19 17:36:52 2019 -0400 - - Added basic keyboard controls to context menu - -[33mcommit fa37e023b88127cb8a6b393a848200361a396fb4[m -Merge: 565b27c 5b2a498 -Author: Tyler Schicke <tyler_schicke@brown.edu> -Date: Wed Jun 19 16:21:09 2019 -0400 - - Merge branch 'master' of github-tsch-brown:browngraphicslab/Dash-Web - -[33mcommit 565b27cca8953a60067de367cae4c0a99beb3cab[m -Author: Tyler Schicke <tyler_schicke@brown.edu> -Date: Wed Jun 19 16:21:03 2019 -0400 - - started adding selection to context menu - -[33mcommit 5b2a498aca75bd53ffab61f998218bec546b8154[m -Merge: 358437e 39e8a7a -Author: bob <bcz@cs.brown.edu> -Date: Wed Jun 19 16:17:21 2019 -0400 - - Merge branch 'master' of https://github.com/browngraphicslab/Dash-Web - -[33mcommit 358437eeafe42e029ffe27702bde15a3fad54a3b[m -Author: bob <bcz@cs.brown.edu> -Date: Wed Jun 19 16:17:18 2019 -0400 - - working version of embedded tree view docs. - -[33mcommit 4c1383e47f2203a00bc7f3d73c209f3149d6a772[m -Author: Mohammad Amoush <mohammad_amoush@brown.edu> -Date: Wed Jun 19 15:53:05 2019 -0400 - - ... - -[33mcommit a288a2fd0a30a3a16dd01bc4e12dcf6bc117c766[m -Author: Mohammad Amoush <mohammad_amoush@brown.edu> -Date: Wed Jun 19 15:25:24 2019 -0400 - - Navigation and Zoom Option For Manual Selection Added and New Presentation TItle Naming Added - - Now, You can manually click on navigate or zoom and navigate to that document if current was their index. A way to manually disregard groups, and just navigate to that doc. - -[33mcommit 39e8a7a365442cdc11024c4de8019184fd0057ac[m -Merge: 5b6f13d 9ab4739 -Author: Stanley Yip <33562077+yipstanley@users.noreply.github.com> -Date: Wed Jun 19 15:05:38 2019 -0400 - - Merge pull request #163 from browngraphicslab/pdf_fixes - - deleting annotations - -[33mcommit 5b6f13d64e9e38b94df0ae61ffedcb0b34290045[m -Merge: 35e73f3 4ebbdd8 -Author: Tyler Schicke <tyler_schicke@brown.edu> -Date: Wed Jun 19 15:04:46 2019 -0400 - - Merge branch 'master' of github-tsch-brown:browngraphicslab/Dash-Web - -[33mcommit 35e73f369a2145d8a042e0011a43e71763d57998[m -Author: Tyler Schicke <tyler_schicke@brown.edu> -Date: Wed Jun 19 15:02:48 2019 -0400 - - added better search to context menu - -[33mcommit 9ab47393a2ce3d174ad3238422c2c310764be9af[m -Author: yipstanley <stanley_yip@brown.edu> -Date: Wed Jun 19 14:40:28 2019 -0400 - - interaction improvements with delete button - -[33mcommit b9849810231e540a5898a56012abd32c197b23b5[m -Author: yipstanley <stanley_yip@brown.edu> -Date: Wed Jun 19 14:39:15 2019 -0400 - - anna - -[33mcommit b960a876d6a31b3eaebb0ac6eca6f191a0d4c900[m -Author: yipstanley <stanley_yip@brown.edu> -Date: Wed Jun 19 14:38:43 2019 -0400 - - oop - -[33mcommit 46d57bc21cda4703855b85a4603bd471975d845b[m -Author: yipstanley <stanley_yip@brown.edu> -Date: Wed Jun 19 14:25:47 2019 -0400 - - deleting annotations - -[33mcommit f362dbfc237536c6c4a8c6d088c3dc818080f7c2[m -Author: Fawn <fangrui_tong@brown.edu> -Date: Wed Jun 19 12:50:58 2019 -0400 - - both tail ends of a cut link appear on hover/focus of an anchor - -[33mcommit fb62f3b2e39bbe2dd3da5eaffedbaa8e60f06dbb[m -Author: Mohammad Amoush <mohammad_amoush@brown.edu> -Date: Wed Jun 19 12:35:54 2019 -0400 - - Grouping for different presentations fixed - -[33mcommit 4ebbdd803cdf83806902509dfa0432ce3a139403[m -Merge: 0bb2052 c056ade -Author: Stanley Yip <33562077+yipstanley@users.noreply.github.com> -Date: Wed Jun 19 11:48:16 2019 -0400 - - Merge pull request #162 from browngraphicslab/pdf_fixes - - Pdf fixes - -[33mcommit c056adeca11f35972b5f75c6b1cc31292d5765d4[m -Author: yipstanley <stanley_yip@brown.edu> -Date: Wed Jun 19 11:47:20 2019 -0400 - - push - -[33mcommit 37f327ab659e6fa1221f9f4ed7649402c5dedc00[m -Author: yipstanley <stanley_yip@brown.edu> -Date: Wed Jun 19 11:24:32 2019 -0400 - - aspect ratio, dragging, and full screen scrolling fixed - -[33mcommit 0bb20528c8167b3ba1c4c88d97586d50ae183b4c[m -Author: bob <bcz@cs.brown.edu> -Date: Wed Jun 19 10:37:36 2019 -0400 - - added highlight for expanded tree view items - -[33mcommit f60398d5db9041e09c809c16a0b885936ac11a3d[m -Author: bob <bcz@cs.brown.edu> -Date: Wed Jun 19 10:21:37 2019 -0400 - - fixed multi-column stacking - -[33mcommit 0674331f3611d297028526c888c718a75b012e0a[m -Author: bob <bcz@cs.brown.edu> -Date: Wed Jun 19 09:36:21 2019 -0400 - - fixed resizing stacking views. changed defaults for new docs in treeView - -[33mcommit 1472d2b56aa64896f0a93f172322121d19cd1592[m -Author: bob <bcz@cs.brown.edu> -Date: Wed Jun 19 09:11:35 2019 -0400 - - fixed lint errors. - -[33mcommit 8c94bb92b23dea138fa752929b6134e7214dfb60[m -Merge: 3b880d7 13e301d -Author: Bob Zeleznik <zzzman@gmail.com> -Date: Tue Jun 18 22:51:48 2019 -0400 - - Merge branch 'master' of https://github.com/browngraphicslab/Dash-Web - -[33mcommit 3b880d7b15b7107049ae27601b9f759b17f7fde9[m -Author: Bob Zeleznik <zzzman@gmail.com> -Date: Tue Jun 18 22:51:46 2019 -0400 - - added initial keyboard shortcuts for adding and moving docs in TreeView. fixed image drag bug. - -[33mcommit 13e301dea2f537b67b338cc6a98d3f3b5a8e1f36[m -Author: Tyler Schicke <tyler_schicke@brown.edu> -Date: Tue Jun 18 20:58:32 2019 -0400 - - Fixed linter errors - -[33mcommit 464fa03d6ebb2a7aaef1d7622afa3e1e7ee816a3[m -Author: Tyler Schicke <tyler_schicke@brown.edu> -Date: Tue Jun 18 20:11:31 2019 -0400 - - Context menu improvements and error fixes - -[33mcommit 4ffcff69a2fc767c6a03d46d7296b6a8c7ffd281[m -Author: madelinegr <mgriswold99@gmail.com> -Date: Tue Jun 18 19:13:45 2019 -0400 - - Presentations Listed, Option to Change Added, and - -[33mcommit ca126adda9e4def83fb5c2e07e382917ca0b4ee0[m -Author: Tyler Schicke <tyler_schicke@brown.edu> -Date: Tue Jun 18 17:24:59 2019 -0400 - - Fixed docking view? - -[33mcommit b0ac30172019713e1c75083c1199485d902e0eed[m -Author: Tyler Schicke <tyler_schicke@brown.edu> -Date: Tue Jun 18 16:37:28 2019 -0400 - - Fixed zoomBasis stuff and added deletion handling for reponse from server - -[33mcommit 8e5afb5bbb47324a381b5184254e77eba7bd8536[m -Author: Fawn <fangrui_tong@brown.edu> -Date: Tue Jun 18 16:30:24 2019 -0400 - - can click on button link to node in different context than source - -[33mcommit 6fcd0d8d6fb1471b8af460f6d80bdf0d0e681566[m -Author: Fawn <fangrui_tong@brown.edu> -Date: Tue Jun 18 15:17:27 2019 -0400 - - added button to delete a link - -[33mcommit d91e7eec9a62363b383b929166cdf600b124334c[m -Author: Fawn <fangrui_tong@brown.edu> -Date: Tue Jun 18 15:09:21 2019 -0400 - - links to nodes in different contexts render as a circle - -[33mcommit d3cad099d49690810166d0342f7c371bda0f007e[m -Merge: 04668e2 b1af251 -Author: bob <bcz@cs.brown.edu> -Date: Tue Jun 18 13:30:55 2019 -0400 - - Merge branch 'master' of https://github.com/browngraphicslab/Dash-Web - -[33mcommit 04668e21313f6e62e5ab35ac737fc54191769a5a[m -Author: bob <bcz@cs.brown.edu> -Date: Tue Jun 18 13:30:41 2019 -0400 - - fixed cleanup of marquee keyhandler. - -[33mcommit b1af251b058743798aa3fa3895d22327c8560dfc[m -Author: Sam Wilkins <35748010+samwilkins333@users.noreply.github.com> -Date: Tue Jun 18 13:19:50 2019 -0400 - - Added pointer down flag for tab focus - -[33mcommit 9544576ec0167d64f564ae4c87d392eba07ff467[m -Author: Sam Wilkins <35748010+samwilkins333@users.noreply.github.com> -Date: Tue Jun 18 13:18:34 2019 -0400 - - Added tab focusing on hover - -[33mcommit 2633f61d311528e62d50d4ff56f5884b3b51ac61[m -Author: bob <bcz@cs.brown.edu> -Date: Tue Jun 18 13:12:15 2019 -0400 - - added undo/redo bindings for app. - -[33mcommit 3a25bad918c72f5d6de9a720de9e0d316c00f2fe[m -Author: bob <bcz@cs.brown.edu> -Date: Tue Jun 18 13:03:28 2019 -0400 - - fixed issues with expanding text boxes that have a dynamic title - -[33mcommit f4fcf306e2579b7479610899a01c06fb157d47de[m -Author: bob <bcz@cs.brown.edu> -Date: Tue Jun 18 12:03:14 2019 -0400 - - fixed goldenlayout nesting - -[33mcommit 4f0086f6ea948c1c5254db2acc93f6735987daa5[m -Merge: 749eef1 d7ebe7b -Author: bob <bcz@cs.brown.edu> -Date: Tue Jun 18 11:31:49 2019 -0400 - - Merge branch 'master' of https://github.com/browngraphicslab/Dash-Web - -[33mcommit 749eef13af1338225b2bec4dbcd7a50a5650d285[m -Author: bob <bcz@cs.brown.edu> -Date: Tue Jun 18 11:31:46 2019 -0400 - - fixed image drag drop when not selected. - -[33mcommit d7ebe7b7d19cf7dc797443aa485293670c3ee4e2[m -Merge: 66d4cc9 08872de -Author: yipstanley <stanley_yip@brown.edu> -Date: Tue Jun 18 11:08:44 2019 -0400 - - Merge branch 'master' of https://github.com/browngraphicslab/Dash-Web - -[33mcommit 66d4cc94bcc69f590d90dd35823f93b8e2fb90d8[m -Author: yipstanley <stanley_yip@brown.edu> -Date: Tue Jun 18 10:52:10 2019 -0400 - - selection fixes - -[33mcommit 08872def596af073c5f14336c8faf07f44561bbc[m -Merge: 8d00265 c50ba1c -Author: bob <bcz@cs.brown.edu> -Date: Tue Jun 18 10:28:31 2019 -0400 - - Merge branch 'master' of https://github.com/browngraphicslab/Dash-Web - -[33mcommit 8d0026573ad9a196f864490bcf07c78f54082bad[m -Author: bob <bcz@cs.brown.edu> -Date: Tue Jun 18 10:28:29 2019 -0400 - - fixed selection within multicolumn stacking view. added drop of html image selections. - -[33mcommit c50ba1c4cc01d5cd085dee0dae6f633164efeb80[m -Merge: cc032e2 64e6a94 -Author: yipstanley <stanley_yip@brown.edu> -Date: Tue Jun 18 10:10:58 2019 -0400 - - Merge branch 'master' of https://github.com/browngraphicslab/Dash-Web - -[33mcommit cc032e2f60015728f64f46ef009c9306e36746a0[m -Author: yipstanley <stanley_yip@brown.edu> -Date: Tue Jun 18 10:05:49 2019 -0400 - - fixes - -[33mcommit 64e6a941639aab8d7109178aa151a50909547309[m -Author: Bob Zeleznik <zzzman@gmail.com> -Date: Tue Jun 18 09:05:41 2019 -0400 - - fixed index out of range - -[33mcommit 4b8324fcf44c5d3c3a4b3f6e98a4d1dfce84811b[m -Author: Bob Zeleznik <zzzman@gmail.com> -Date: Tue Jun 18 08:53:01 2019 -0400 - - removed trace - -[33mcommit a3b8a57027d7c45ea19d259e1ec18fa6a8648c24[m -Author: Bob Zeleznik <zzzman@gmail.com> -Date: Tue Jun 18 08:49:02 2019 -0400 - - looked like wrong code... - -[33mcommit 2f5c38c6a0a5220c2a31931c34d94e199854d703[m -Author: Bob Zeleznik <zzzman@gmail.com> -Date: Tue Jun 18 08:36:37 2019 -0400 - - more streamlining - -[33mcommit 62c781c0c79ac395c5e117d208a90485ff1ba599[m -Author: Bob Zeleznik <zzzman@gmail.com> -Date: Tue Jun 18 02:19:07 2019 -0400 - - faster loading of PDFs - -[33mcommit 4dc8c03562a0473becb895824740da487e16e771[m -Author: Bob Zeleznik <zzzman@gmail.com> -Date: Tue Jun 18 00:17:58 2019 -0400 - - added dropping of Dash urls from gmail - -[33mcommit 9c7ff72a8ad249c05b672a46e3fbbb69ffca3a2a[m -Merge: 8c64ffd 71b1cfb -Author: Tyler Schicke <tyler_schicke@brown.edu> -Date: Mon Jun 17 23:04:22 2019 -0400 - - Merge branch 'master' of github-tsch-brown:browngraphicslab/Dash-Web - -[33mcommit 8c64ffd92e382050bc8727981cf9fb830e4f02a7[m -Author: Tyler Schicke <tyler_schicke@brown.edu> -Date: Mon Jun 17 23:04:07 2019 -0400 - - Added share with user functionality |