diff options
Diffstat (limited to 'src/client/views/MainView.tsx')
-rw-r--r-- | src/client/views/MainView.tsx | 741 |
1 files changed, 215 insertions, 526 deletions
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index ec43e6e1d..5193c3c02 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -1,48 +1,45 @@ import { library } from '@fortawesome/fontawesome-svg-core'; -import { faHireAHelper, faBuffer } from '@fortawesome/free-brands-svg-icons'; +import { faBuffer, faHireAHelper } from '@fortawesome/free-brands-svg-icons'; import * as fa from '@fortawesome/free-solid-svg-icons'; +import * as far from '@fortawesome/free-regular-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { action, computed, configure, observable, reaction, runInAction } from 'mobx'; +import { action, computed, configure, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; import "normalize.css"; import * as React from 'react'; -import Measure from 'react-measure'; -import { Doc, DocListCast, Field, Opt } from '../../fields/Doc'; -import { Id } from '../../fields/FieldSymbols'; +import * as ReactDOM from 'react-dom'; +import { Doc, DocListCast, Opt } from '../../fields/Doc'; import { List } from '../../fields/List'; -import { listSpec } from '../../fields/Schema'; -import { ScriptField } from '../../fields/ScriptField'; -import { BoolCast, Cast, FieldValue, StrCast } from '../../fields/Types'; -import { TraceMobx } from '../../fields/util'; -import { emptyFunction, emptyPath, returnEmptyFilter, returnFalse, returnOne, returnTrue, returnZero, setupMoveUpEvents, Utils, simulateMouseClick } from '../../Utils'; -import GoogleAuthenticationManager from '../apis/GoogleAuthenticationManager'; +import { PrefetchProxy } from '../../fields/Proxy'; +import { BoolCast, PromiseValue, StrCast } from '../../fields/Types'; +import { emptyFunction, emptyPath, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnOne, returnTrue, returnZero, setupMoveUpEvents, simulateMouseClick, Utils } from '../../Utils'; +import { GoogleAuthenticationManager } from '../apis/GoogleAuthenticationManager'; import { DocServer } from '../DocServer'; -import { Docs, DocumentOptions } from '../documents/Documents'; +import { Docs } from '../documents/Documents'; import { DocumentType } from '../documents/DocumentTypes'; import { CurrentUserUtils } from '../util/CurrentUserUtils'; import { DocumentManager } from '../util/DocumentManager'; -import GroupManager from '../util/GroupManager'; +import { GroupManager } from '../util/GroupManager'; import { HistoryUtil } from '../util/History'; +import { Hypothesis } from '../util/HypothesisUtils'; import { Scripting } from '../util/Scripting'; -import { SelectionManager } from '../util/SelectionManager'; -import SettingsManager from '../util/SettingsManager'; -import SharingManager from '../util/SharingManager'; +import { SettingsManager } from '../util/SettingsManager'; +import { SharingManager } from '../util/SharingManager'; import { SnappingManager } from '../util/SnappingManager'; import { Transform } from '../util/Transform'; import { TimelineMenu } from './animationtimeline/TimelineMenu'; import { CollectionDockingView } from './collections/CollectionDockingView'; -import FormatShapePane from "./collections/collectionFreeForm/FormatShapePane"; -import MarqueeOptionsMenu from './collections/collectionFreeForm/MarqueeOptionsMenu'; -import { PropertiesView } from './collections/collectionFreeForm/PropertiesView'; +import { MarqueeOptionsMenu } from './collections/collectionFreeForm/MarqueeOptionsMenu'; import { CollectionLinearView } from './collections/CollectionLinearView'; -import CollectionMenu from './collections/CollectionMenu'; -import { CollectionView, CollectionViewType } from './collections/CollectionView'; +import { CollectionMenu } from './collections/CollectionMenu'; +import { CollectionViewType } from './collections/CollectionView'; import { ContextMenu } from './ContextMenu'; import { DictationOverlay } from './DictationOverlay'; import { DocumentDecorations } from './DocumentDecorations'; -import GestureOverlay from './GestureOverlay'; -import { ANTIMODEMENU_HEIGHT, SEARCH_PANEL_HEIGHT } from './globalCssVariables.scss'; -import KeyManager from './GlobalKeyHandler'; +import { InkStrokeProperties } from './InkStrokeProperties'; +import { GestureOverlay } from './GestureOverlay'; +import { MENU_PANEL_WIDTH, SEARCH_PANEL_HEIGHT } from './globalCssVariables.scss'; +import { KeyManager } from './GlobalKeyHandler'; import { LinkMenu } from './linking/LinkMenu'; import "./MainView.scss"; import { AudioBox } from './nodes/AudioBox'; @@ -53,91 +50,67 @@ import { LinkDescriptionPopup } from './nodes/LinkDescriptionPopup'; import { LinkDocPreview } from './nodes/LinkDocPreview'; import { RadialMenu } from './nodes/RadialMenu'; import { TaskCompletionBox } from './nodes/TaskCompletedBox'; +import { WebBox } from './nodes/WebBox'; import { OverlayView } from './OverlayView'; -import PDFMenu from './pdf/PDFMenu'; +import { PDFMenu } from './pdf/PDFMenu'; import { PreviewCursor } from './PreviewCursor'; -import { Hypothesis } from '../util/HypothesisUtils'; -import { WebBox } from './nodes/WebBox'; -import * as ReactDOM from 'react-dom'; +import { PropertiesView } from './PropertiesView'; import { SearchBox } from './search/SearchBox'; -import { SearchUtil } from '../util/SearchUtil'; -import { Networking } from '../Network'; -import * as rp from 'request-promise'; -import { LinkManager } from '../util/LinkManager'; -import RichTextMenu from './nodes/formattedText/RichTextMenu'; +import { TraceMobx } from '../../fields/util'; +import { SelectionManager } from '../util/SelectionManager'; +const _global = (window /* browser */ || global /* node */) as any; @observer export class MainView extends React.Component { public static Instance: MainView; - private _buttonBarHeight = 36; - private _flyoutSizeOnDown = 0; - private _urlState: HistoryUtil.DocUrl; private _docBtnRef = React.createRef<HTMLDivElement>(); private _mainViewRef = React.createRef<HTMLDivElement>(); + private _lastButton: Doc | undefined; @observable private _panelWidth: number = 0; @observable private _panelHeight: number = 0; - @observable private _flyoutTranslate: boolean = false; - @observable public flyoutWidth: number = 0; - private get darkScheme() { return BoolCast(Cast(this.userDoc?.activeWorkspace, Doc, null)?.darkScheme); } + @observable private _panelContent: string = "none"; + @observable private _sidebarContent: any = this.userDoc?.sidebar; + @observable private _flyoutWidth: number = 0; + @computed private get topOffset() { return (CollectionMenu.Instance?.Pinned ? 35 : 0) + Number(SEARCH_PANEL_HEIGHT.replace("px", "")); } @computed private get userDoc() { return Doc.UserDoc(); } - @computed private get mainContainer() { return this.userDoc ? FieldValue(Cast(this.userDoc.activeWorkspace, Doc)) : CurrentUserUtils.GuestWorkspace; } + @computed private get darkScheme() { return BoolCast(CurrentUserUtils.ActiveDashboard?.darkScheme); } + @computed private get mainContainer() { return this.userDoc ? CurrentUserUtils.ActiveDashboard : CurrentUserUtils.GuestDashboard; } @computed public get mainFreeform(): Opt<Doc> { return (docs => (docs && docs.length > 1) ? docs[1] : undefined)(DocListCast(this.mainContainer!.data)); } - @computed public get searchDoc() { return Cast(this.userDoc["search-panel"], Doc) as Doc; } - - @observable public sidebarContent: any = this.userDoc?.sidebar; - @observable public panelContent: string = "none"; - @observable public showProperties: boolean = false; - public isPointerDown = false; - @computed get selectedDocumentView() { - if (SelectionManager.SelectedDocuments().length) { - return SelectionManager.SelectedDocuments()[0]; - } else { return undefined; } - } - - propertiesWidth = () => Math.max(0, Math.min(this._panelWidth - 50, CurrentUserUtils.propertiesWidth)); - @computed get propertiesIcon() { - if (this.propertiesWidth() < 10) { - return "chevron-left"; - } else { - return "chevron-right"; - } - } - @observable propertiesDownX: number | undefined; + menuPanelWidth = () => Number(MENU_PANEL_WIDTH.replace("px", "")); + propertiesWidth = () => Math.max(0, Math.min(this._panelWidth - 50, CurrentUserUtils.propertiesWidth || 0)); componentDidMount() { - DocServer.setPlaygroundFields(["dataTransition", "_viewTransition", "_panX", "_panY", "_viewScale", "_viewType", "_chromeStatus"]); // can play with these fields on someone else's - - const tag = document.createElement('script'); + document.getElementById("root")?.addEventListener("scroll", e => ((ele) => ele.scrollLeft = ele.scrollTop = 0)(document.getElementById("root")!)); + new InkStrokeProperties(); + this._sidebarContent.proto = undefined; + DocServer.setPlaygroundFields(["dataTransition", "_delayAutoHeight", "_autoHeight", "_showSidebar", "_sidebarWidthPercent", "_width", "_height", "_viewTransition", "_panX", "_panY", "_viewScale", "_scrollY", "_scrollTop", "hidden", "_curPage", "_viewType", "_chromeStatus"]); // can play with these fields on someone else's - const proto = DocServer.GetRefField("rtfProto").then(proto => { - (proto instanceof Doc) && reaction(() => StrCast(proto.BROADCAST_MESSAGE), - msg => msg && alert(msg)); - }); + DocServer.GetRefField("rtfProto").then(proto => (proto instanceof Doc) && reaction(() => StrCast(proto.BROADCAST_MESSAGE), msg => msg && alert(msg))); + const tag = document.createElement('script'); tag.src = "https://www.youtube.com/iframe_api"; const firstScriptTag = document.getElementsByTagName('script')[0]; firstScriptTag.parentNode!.insertBefore(tag, firstScriptTag); window.removeEventListener("keydown", KeyManager.Instance.handle); window.addEventListener("keydown", KeyManager.Instance.handle); + window.removeEventListener("keyup", KeyManager.Instance.unhandle); + window.addEventListener("keyup", KeyManager.Instance.unhandle); window.addEventListener("paste", KeyManager.Instance.paste as any); document.addEventListener("dash", (e: any) => { // event used by chrome plugin to tell Dash which document to focus on const id = FormattedTextBox.GetDocFromUrl(e.detail); - DocServer.GetRefField(id).then(doc => { - if (doc instanceof Doc) { - DocumentManager.Instance.jumpToDocument(doc, false, undefined); - } - }); + DocServer.GetRefField(id).then(doc => (doc instanceof Doc) ? DocumentManager.Instance.jumpToDocument(doc, false, undefined) : (null)); }); document.addEventListener("linkAnnotationToDash", Hypothesis.linkListener); + this.initEventListeners(); } componentWillUnMount() { + window.removeEventListener("keyup", KeyManager.Instance.unhandle); window.removeEventListener("keydown", KeyManager.Instance.handle); window.removeEventListener("pointerdown", this.globalPointerDown); - window.removeEventListener("pointerup", this.globalPointerUp); window.removeEventListener("paste", KeyManager.Instance.paste as any); document.removeEventListener("linkAnnotationToDash", Hypothesis.linkListener); } @@ -145,217 +118,124 @@ export class MainView extends React.Component { constructor(props: Readonly<{}>) { super(props); MainView.Instance = this; - this.sidebarContent.proto = undefined; - this._urlState = HistoryUtil.parseUrl(window.location) || {} as any; - // causes errors to be generated when modifying an observable outside of an action - - CurrentUserUtils.propertiesWidth = 0; + CurrentUserUtils._urlState = HistoryUtil.parseUrl(window.location) || {} as any; + // causes errors to be generated when modifying an observable outside of an action configure({ enforceActions: "observed" }); + if (window.location.pathname !== "/home") { const pathname = window.location.pathname.substr(1).split("/"); - if (pathname.length > 1) { - const type = pathname[0]; - if (type === "doc") { - CurrentUserUtils.MainDocId = pathname[1]; - if (!this.userDoc) { - runInAction(() => this.closeFlyout()); - DocServer.GetRefField(CurrentUserUtils.MainDocId).then(action((field: Opt<Field>) => - field instanceof Doc && (CurrentUserUtils.GuestTarget = field))); - } - } + if (pathname.length > 1 && pathname[0] === "doc") { + CurrentUserUtils.MainDocId = pathname[1]; + !this.userDoc && DocServer.GetRefField(pathname[1]).then(action(field => field instanceof Doc && (CurrentUserUtils.GuestTarget = field))); } } library.add(fa.faEdit, fa.faTrash, fa.faTrashAlt, fa.faShare, fa.faDownload, fa.faExpandArrowsAlt, fa.faLayerGroup, fa.faExternalLinkAlt, fa.faCalendar, - fa.faSquare, fa.faConciergeBell, fa.faWindowRestore, fa.faFolder, fa.faMapPin, fa.faFingerprint, fa.faCrosshairs, fa.faDesktop, fa.faUnlock, - fa.faLock, fa.faLaptopCode, fa.faMale, fa.faCopy, fa.faHandPointRight, fa.faCompass, fa.faSnowflake, fa.faMicrophone, fa.faKeyboard, - fa.faQuestion, fa.faTasks, fa.faPalette, fa.faAngleRight, fa.faBell, fa.faCamera, fa.faExpand, fa.faCaretDown, fa.faCaretLeft, fa.faCaretRight, + fa.faSquare, fa.faConciergeBell, fa.faWindowRestore, fa.faFolder, fa.faMapPin, fa.faMapMarker, fa.faFingerprint, fa.faCrosshairs, fa.faDesktop, fa.faUnlock, + fa.faLock, fa.faLaptopCode, fa.faMale, fa.faCopy, fa.faHandPointLeft, fa.faHandPointRight, fa.faCompass, fa.faSnowflake, fa.faMicrophone, fa.faKeyboard, + fa.faQuestion, fa.faTasks, fa.faPalette, fa.faAngleLeft, fa.faAngleRight, fa.faBell, fa.faCamera, fa.faExpand, fa.faCaretDown, fa.faCaretLeft, fa.faCaretRight, fa.faCaretSquareDown, fa.faCaretSquareRight, fa.faArrowsAltH, fa.faPlus, fa.faMinus, fa.faTerminal, fa.faToggleOn, fa.faFile, fa.faLocationArrow, - fa.faSearch, fa.faFileDownload, fa.faStop, fa.faCalculator, fa.faWindowMaximize, fa.faAddressCard, fa.faQuestionCircle, fa.faArrowLeft, - fa.faArrowRight, fa.faArrowDown, fa.faArrowUp, fa.faBolt, fa.faBullseye, fa.faCaretUp, fa.faCat, fa.faCheck, fa.faChevronRight, fa.faClipboard, + fa.faSearch, fa.faFileDownload, fa.faFileUpload, fa.faStop, fa.faCalculator, fa.faWindowMaximize, fa.faAddressCard, fa.faQuestionCircle, fa.faArrowLeft, + fa.faArrowRight, fa.faArrowDown, fa.faArrowUp, fa.faBolt, fa.faBullseye, fa.faCaretUp, fa.faCat, fa.faCheck, fa.faChevronRight, fa.faChevronLeft, fa.faChevronDown, fa.faChevronUp, fa.faClone, fa.faCloudUploadAlt, fa.faCommentAlt, fa.faCompressArrowsAlt, fa.faCut, fa.faEllipsisV, fa.faEraser, fa.faExclamation, fa.faFileAlt, - fa.faFileAudio, fa.faFilePdf, fa.faFilm, fa.faFilter, fa.faFont, fa.faGlobeAsia, fa.faHighlighter, fa.faLongArrowAltRight, fa.faMousePointer, + fa.faFileAudio, fa.faFilePdf, fa.faFilm, fa.faFilter, fa.faFont, fa.faGlobeAmericas, fa.faGlobeAsia, fa.faHighlighter, fa.faLongArrowAltRight, fa.faMousePointer, fa.faMusic, fa.faObjectGroup, fa.faPause, fa.faPen, fa.faPenNib, fa.faPhone, fa.faPlay, fa.faPortrait, fa.faRedoAlt, fa.faStamp, fa.faStickyNote, fa.faTimesCircle, fa.faThumbtack, fa.faTree, fa.faTv, fa.faUndoAlt, fa.faVideo, fa.faAsterisk, fa.faBrain, fa.faImage, fa.faPaintBrush, fa.faTimes, fa.faEye, fa.faArrowsAlt, fa.faQuoteLeft, fa.faSortAmountDown, fa.faAlignLeft, fa.faAlignCenter, fa.faAlignRight, fa.faHeading, fa.faRulerCombined, - fa.faFillDrip, fa.faLink, fa.faUnlink, fa.faBold, fa.faItalic, fa.faChevronLeft, fa.faUnderline, fa.faStrikethrough, fa.faSuperscript, fa.faSubscript, + fa.faFillDrip, fa.faLink, fa.faUnlink, fa.faBold, fa.faItalic, fa.faClipboard, fa.faUnderline, fa.faStrikethrough, fa.faSuperscript, fa.faSubscript, fa.faIndent, fa.faEyeDropper, fa.faPaintRoller, fa.faBars, fa.faBrush, fa.faShapes, fa.faEllipsisH, fa.faHandPaper, fa.faMap, fa.faUser, faHireAHelper, - fa.faDesktop, fa.faTrashRestore, fa.faUsers, fa.faWrench, fa.faCog, fa.faMap, fa.faBellSlash, fa.faExpandAlt, fa.faArchive, fa.faBezierCurve, fa.faCircle, + fa.faTrashRestore, fa.faUsers, fa.faWrench, fa.faCog, fa.faMap, fa.faBellSlash, fa.faExpandAlt, fa.faArchive, fa.faBezierCurve, fa.faCircle, far.faCircle, fa.faLongArrowAltRight, fa.faPenFancy, fa.faAngleDoubleRight, faBuffer, fa.faExpand, fa.faUndo, fa.faSlidersH, fa.faAngleDoubleLeft, fa.faAngleUp, fa.faAngleDown, fa.faPlayCircle, fa.faClock, fa.faRocket, fa.faExchangeAlt, faBuffer, fa.faHashtag, fa.faAlignJustify, fa.faCheckSquare, fa.faListUl, - fa.faWindowMinimize, fa.faWindowRestore); - this.initEventListeners(); + fa.faWindowMinimize, fa.faWindowRestore, fa.faTextWidth, fa.faTextHeight, fa.faClosedCaptioning, fa.faInfoCircle, fa.faTag, fa.faSyncAlt, fa.faPhotoVideo, + fa.faArrowAltCircleDown, fa.faArrowAltCircleUp, fa.faArrowAltCircleLeft, fa.faArrowAltCircleRight, fa.faStopCircle, fa.faCheckCircle, fa.faGripVertical, + fa.faSortUp, fa.faSortDown, fa.faTable, fa.faTh, fa.faThList, fa.faProjectDiagram, fa.faSignature, fa.faColumns, fa.faChevronCircleUp, fa.faUpload, + fa.faBraille, fa.faChalkboard, fa.faPencilAlt, fa.faEyeSlash, fa.faSmile, fa.faIndent, fa.faOutdent, fa.faChartBar, fa.faBan, fa.faPhoneSlash, fa.faGripLines); this.initAuthenticationRouters(); } globalPointerDown = action((e: PointerEvent) => { - this.isPointerDown = true; AudioBox.Enabled = true; const targets = document.elementsFromPoint(e.x, e.y); - if (targets && targets.length && targets[0].className.toString().indexOf("contextMenu") === -1) { - ContextMenu.Instance.closeMenu(); - } - if (targets && (targets.length && targets[0].className.toString() !== "timeline-menu-desc" && targets[0].className.toString() !== "timeline-menu-item" && targets[0].className.toString() !== "timeline-menu-input")) { - TimelineMenu.Instance.closeMenu(); - } - if (targets && targets.length && SearchBox.Instance._searchbarOpen) { - let check = false; - const icon = "icon"; - targets.forEach((thing) => { - if (thing.className.toString() === "collectionSchemaView-searchContainer" || (thing as any)?.dataset[icon] === "filter" || thing.className.toString() === "collectionSchema-header-menuOptions" || thing.className.toString() === "altcollectionTimeView-treeView") { - check = true; - } - }); - if (check === false) { - SearchBox.Instance.closeSearch(); + if (targets.length) { + const targClass = targets[0].className.toString(); + if (SearchBox.Instance._searchbarOpen || SearchBox.Instance.open) { + const check = targets.some((thing) => + (thing.className === "collectionSchemaView-searchContainer" || (thing as any)?.dataset.icon === "filter" || + thing.className === "collectionSchema-header-menuOptions")); + !check && SearchBox.Instance.resetSearch(true); } + !targClass.includes("contextMenu") && ContextMenu.Instance.closeMenu(); + !["timeline-menu-desc", "timeline-menu-item", "timeline-menu-input"].includes(targClass) && TimelineMenu.Instance.closeMenu(); } - - }); - globalPointerUp = () => this.isPointerDown = false; - initEventListeners = () => { - window.addEventListener("drop", (e) => { e.preventDefault(); }, false); // drop event handler - window.addEventListener("dragover", (e) => { e.preventDefault(); }, false); // drag event handler - // click interactions for the context menu + window.addEventListener("drop", e => e.preventDefault(), false); // prevent default behavior of navigating to a new web page + window.addEventListener("dragover", e => e.preventDefault(), false); document.addEventListener("pointerdown", this.globalPointerDown); - document.addEventListener("pointerup", this.globalPointerUp); + document.addEventListener("click", (e: MouseEvent) => { + if (!e.cancelBubble) { + const pathstr = (e as any)?.path.map((p: any) => p.classList?.toString()).join(); + if (pathstr.includes("libraryFlyout")) { + SelectionManager.DeselectAll(); + } + } + }, false); } initAuthenticationRouters = async () => { - // Load the user's active workspace, or create a new one if initial session after signup + // Load the user's active dashboard, or create a new one if initial session after signup const received = CurrentUserUtils.MainDocId; if (received && !this.userDoc) { - reaction( - () => CurrentUserUtils.GuestTarget, - target => target && this.createNewWorkspace(), - { fireImmediately: true } - ); + reaction(() => CurrentUserUtils.GuestTarget, target => target && CurrentUserUtils.createNewDashboard(Doc.UserDoc()), { fireImmediately: true }); } else { - if (received && this._urlState.sharing) { + if (received && CurrentUserUtils._urlState.sharing) { reaction(() => CollectionDockingView.Instance && CollectionDockingView.Instance.initialized, initialized => initialized && received && DocServer.GetRefField(received).then(docField => { if (docField instanceof Doc && docField._viewType !== CollectionViewType.Docking) { - CollectionDockingView.AddRightSplit(docField); + CollectionDockingView.AddSplit(docField, "right"); } }), ); } - const doc = this.userDoc && await Cast(this.userDoc.activeWorkspace, Doc); - if (doc) { - this.openWorkspace(doc); - } else { - this.createNewWorkspace(); - } - } - } - - @action - createNewWorkspace = async (id?: string) => { - const myCatalog = Doc.UserDoc().myCatalog as Doc; - const presentation = Doc.MakeCopy(Doc.UserDoc().emptyPresentation as Doc, true); - const workspaces = Cast(this.userDoc.myWorkspaces, Doc) as Doc; - const workspaceCount = DocListCast(workspaces.data).length + 1; - const freeformOptions: DocumentOptions = { - x: 0, - y: 400, - _width: this._panelWidth * .7 - this.propertiesWidth() * 0.7, - _height: this._panelHeight, - title: "Untitled Collection", - }; - const freeformDoc = CurrentUserUtils.GuestTarget || Docs.Create.FreeformDocument([], freeformOptions); - const workspaceDoc = Docs.Create.StandardCollectionDockingDocument([{ doc: freeformDoc, initialWidth: 600, path: [myCatalog] }], { title: `Workspace ${workspaceCount}` }, id, "row"); - Doc.AddDocToList(myCatalog, "data", freeformDoc); - Doc.AddDocToList(myCatalog, "data", presentation); - Doc.UserDoc().activePresentation = presentation; - const toggleTheme = ScriptField.MakeScript(`self.darkScheme = !self.darkScheme`); - const toggleComic = ScriptField.MakeScript(`toggleComicMode()`); - const copyWorkspace = ScriptField.MakeScript(`copyWorkspace()`); - workspaceDoc.contextMenuScripts = new List<ScriptField>([toggleTheme!, toggleComic!, copyWorkspace!]); - workspaceDoc.contextMenuLabels = new List<string>(["Toggle Theme Colors", "Toggle Comic Mode", "Snapshot Workspace"]); - - Doc.AddDocToList(workspaces, "data", workspaceDoc); - // bcz: strangely, we need a timeout to prevent exceptions/issues initializing GoldenLayout (the rendering engine for Main Container) - setTimeout(() => this.openWorkspace(workspaceDoc), 0); - } - - @action - openWorkspace = (doc: Doc, fromHistory = false) => { - CurrentUserUtils.MainDocId = doc[Id]; - - if (doc) { // this has the side-effect of setting the main container since we're assigning the active/guest workspace - !("presentationView" in doc) && (doc.presentationView = new List<Doc>([Docs.Create.TreeDocument([], { title: "Presentation" })])); - this.userDoc ? (this.userDoc.activeWorkspace = doc) : (CurrentUserUtils.GuestWorkspace = doc); - } - const state = this._urlState; - if (state.sharing === true && !this.userDoc) { - DocServer.Control.makeReadOnly(); - } else { - fromHistory || HistoryUtil.pushState({ - type: "doc", - docId: doc[Id], - readonly: state.readonly, - nro: state.nro, - sharing: false, + const activeDash = PromiseValue(this.userDoc.activeDashboard); + activeDash.then(dash => { + if (dash instanceof Doc) CurrentUserUtils.openDashboard(this.userDoc, dash); + else CurrentUserUtils.createNewDashboard(this.userDoc); }); - if (state.readonly === true || state.readonly === null) { - DocServer.Control.makeReadOnly(); - } else if (state.safe) { - if (!state.nro) { - DocServer.Control.makeReadOnly(); - } - CollectionView.SetSafeMode(true); - } else if (state.nro || state.nro === null || state.readonly === false) { - } else if (doc.readOnly) { - DocServer.Control.makeReadOnly(); - } else { - DocServer.Control.makeEditable(); - } } - - return true; - } - - onDrop = (e: React.DragEvent<HTMLDivElement>) => { - e.preventDefault(); - e.stopPropagation(); } @action - onResize = (r: any) => { - this._panelWidth = r.offset.width;// - this.propertiesWidth(); - this._panelHeight = r.offset.height; + createNewPresentation = async () => { + if (!await this.userDoc.myPresentations) { + this.userDoc.myPresentations = new PrefetchProxy(Docs.Create.TreeDocument([], { + title: "PRESENTATION TRAILS", _height: 100, forceActive: true, boxShadow: "0 0", lockedPosition: true, treeViewOpen: true, system: true + })); + } + const pres = Docs.Create.PresDocument(new List<Doc>(), + { title: "Untitled Presentation", _viewType: CollectionViewType.Stacking, _width: 400, _height: 500, targetDropAction: "alias", _chromeStatus: "replaced", boxShadow: "0 0" }); + CollectionDockingView.AddSplit(pres, "right"); + this.userDoc.activePresentation = pres; + Doc.AddDocToList(this.userDoc.myPresentations as Doc, "data", pres); } - @action - getPWidth = () => this._panelWidth - this.propertiesWidth() - + getPWidth = () => this._panelWidth - this.propertiesWidth(); getPHeight = () => this._panelHeight; - getContentsHeight = () => this._panelHeight - this._buttonBarHeight; + getContentsHeight = () => this._panelHeight - Number(SEARCH_PANEL_HEIGHT.replace("px", "")); defaultBackgroundColors = (doc: Opt<Doc>, renderDepth: number) => { - if (this.panelContent === doc?.title) return "lightgrey"; - if (doc?.type === DocumentType.COL) { - if (doc.title === "Basic Item Creators" || doc.title === "sidebar-tools" - || doc.title === "sidebar-recentlyClosed" || doc.title === "sidebar-catalog" - || doc.title === "Mobile Uploads" || doc.title === "COLLECTION_PROTO" - || doc.title === "Advanced Item Prototypes" || doc.title === "all Creators") { - return "lightgrey"; - } - return StrCast(renderDepth > 0 ? Doc.UserDoc().activeCollectionNestedBackground : Doc.UserDoc().activeCollectionBackground); + return Doc.IsSystem(doc) ? "lightgrey" : StrCast(renderDepth > 0 ? Doc.UserDoc().activeCollectionNestedBackground : Doc.UserDoc().activeCollectionBackground); } if (this.darkScheme) { switch (doc?.type) { case DocumentType.FONTICON: return "white"; case DocumentType.RTF || DocumentType.LABEL || DocumentType.BUTTON: return "#2d2d2d"; case DocumentType.LINK: - case DocumentType.COL: { - if (doc._viewType !== CollectionViewType.Freeform && doc._viewType !== CollectionViewType.Time) return "rgb(62,62,62)"; - } + case DocumentType.COL: if (doc._viewType !== CollectionViewType.Freeform && doc._viewType !== CollectionViewType.Time) return "rgb(62,62,62)"; default: return "black"; } } else { @@ -365,9 +245,7 @@ export class MainView extends React.Component { case DocumentType.BUTTON: case DocumentType.LABEL: return "lightgray"; case DocumentType.LINK: - case DocumentType.COL: { - if (doc._viewType !== CollectionViewType.Freeform && doc._viewType !== CollectionViewType.Time) return "lightgray"; - } + case DocumentType.COL: if (doc._viewType !== CollectionViewType.Freeform && doc._viewType !== CollectionViewType.Time) return "lightgray"; default: return "white"; } } @@ -387,8 +265,6 @@ export class MainView extends React.Component { removeDocument={undefined} ScreenToLocalTransform={Transform.Identity} ContentScaling={returnOne} - NativeHeight={returnZero} - NativeWidth={returnZero} PanelWidth={this.getPWidth} PanelHeight={this.getPHeight} focus={emptyFunction} @@ -396,6 +272,8 @@ export class MainView extends React.Component { whenActiveChanged={emptyFunction} bringToFront={emptyFunction} docFilters={returnEmptyFilter} + docRangeFilters={returnEmptyFilter} + searchFilterDocs={returnEmptyDoclist} ContainingCollectionView={undefined} ContainingCollectionDoc={undefined} renderDepth={-1} @@ -403,67 +281,46 @@ export class MainView extends React.Component { } @computed get dockingContent() { - TraceMobx(); - const mainContainer = this.mainContainer; - const width = this.flyoutWidth + this.propertiesWidth(); - return <div className="mainContent-div" onDrop={this.onDrop} style={{ width: `calc(100% - ${width}px)`, height: `calc(100% - ${SEARCH_PANEL_HEIGHT})` }}> - {!mainContainer ? (null) : this.mainDocView} + return <div className={`mainContent-div${this._flyoutWidth ? "-flyout" : ""}`} onDrop={e => { e.stopPropagation(); e.preventDefault(); }} + style={{ minWidth: `calc(100% - ${this._flyoutWidth + this.menuPanelWidth() + this.propertiesWidth()}px)`, width: `calc(100% - ${this._flyoutWidth + this.menuPanelWidth() + this.propertiesWidth()}px)` }}> + {!this.mainContainer ? (null) : this.mainDocView} </div>; } @action onPropertiesPointerDown = (e: React.PointerEvent) => { - setupMoveUpEvents(this, e, action((e: PointerEvent, down: number[], delta: number[]) => { - CurrentUserUtils.propertiesWidth = this._panelWidth - e.clientX; - return false; - }), returnFalse, action(() => CurrentUserUtils.propertiesWidth = this.propertiesWidth() < 15 ? Math.min(this._panelWidth - 50, 250) : 0), false); + setupMoveUpEvents(this, e, + action(e => (CurrentUserUtils.propertiesWidth = Math.max(0, this._panelWidth - e.clientX)) ? false : false), + action(() => CurrentUserUtils.propertiesWidth < 5 && (CurrentUserUtils.propertiesWidth = 0)), + action(() => CurrentUserUtils.propertiesWidth = this.propertiesWidth() < 15 ? Math.min(this._panelWidth - 50, 250) : 0), false); } @action onFlyoutPointerDown = (e: React.PointerEvent) => { - if (this._flyoutTranslate) { - setupMoveUpEvents(this, e, action((e: PointerEvent) => { - this.flyoutWidth = Math.max(e.clientX, 0); - if (this.flyoutWidth < 5) { - this.panelContent = "none"; - this._lastButton && (this._lastButton.color = "white"); - this._lastButton && (this._lastButton._backgroundColor = ""); - } - return false; - }), emptyFunction, action(() => { - if (this.flyoutWidth < 15) MainView.expandFlyout(); - else this.closeFlyout(); - })); - } + setupMoveUpEvents(this, e, + action(e => (this._flyoutWidth = Math.max(e.clientX - 58, 0)) ? false : false), + () => this._flyoutWidth < 5 && this.closeFlyout(), + this.closeFlyout); } - flyoutWidthFunc = () => this.flyoutWidth; - addDocTabFunc = (doc: Doc, where: string, libraryPath?: Doc[]): boolean => { - return where === "close" ? CollectionDockingView.CloseRightSplit(doc) : - doc.dockingConfig ? this.openWorkspace(doc) : - CollectionDockingView.AddRightSplit(doc, libraryPath); - } + flyoutWidthFunc = () => this._flyoutWidth; sidebarScreenToLocal = () => new Transform(0, (CollectionMenu.Instance.Pinned ? -35 : 0) - Number(SEARCH_PANEL_HEIGHT.replace("px", "")), 1); mainContainerXf = () => this.sidebarScreenToLocal().translate(-58, 0); + addDocTabFunc = (doc: Doc, where: string, libraryPath?: Doc[]): boolean => { + return where === "close" ? CollectionDockingView.CloseSplit(doc) : + doc.dockingConfig ? CurrentUserUtils.openDashboard(Doc.UserDoc(), doc) : CollectionDockingView.AddSplit(doc, "right"); + } @computed get flyout() { - if (!this.sidebarContent) return null; - return <div className="mainView-libraryFlyout"> - <div className="mainView-contentArea" style={{ position: "relative", height: `calc(100% - ${SEARCH_PANEL_HEIGHT})`, width: "100%", overflow: "visible" }}> - {/* {this.flyoutWidth > 0 ? <div className="mainView-libraryFlyout-close" - onPointerDown={this.closeFlyout}> - <FontAwesomeIcon icon="times" color="black" size="lg" /> - </div> : null} */} - + return <div className={`mainView-libraryFlyout${this._flyoutWidth ? "" : "-out"}`} style={{ minWidth: this._flyoutWidth, width: this._flyoutWidth }} > + <div className="mainView-contentArea" > <DocumentView - Document={this.sidebarContent} + Document={this._sidebarContent} DataDoc={undefined} LibraryPath={emptyPath} addDocument={undefined} addDocTab={this.addDocTabFunc} pinToPres={emptyFunction} - NativeHeight={returnZero} - NativeWidth={returnZero} rootSelected={returnTrue} removeDocument={returnFalse} onClick={undefined} @@ -478,13 +335,16 @@ export class MainView extends React.Component { whenActiveChanged={emptyFunction} bringToFront={emptyFunction} docFilters={returnEmptyFilter} + docRangeFilters={returnEmptyFilter} + searchFilterDocs={returnEmptyDoclist} ContainingCollectionView={undefined} ContainingCollectionDoc={undefined} relative={true} forcedBackgroundColor={() => "lightgrey"} /> </div> - {this.docButtons}</div>; + {this.docButtons} + </div>; } @computed get menuPanel() { @@ -496,14 +356,12 @@ export class MainView extends React.Component { addDocument={undefined} addDocTab={this.addDocTabFunc} pinToPres={emptyFunction} - NativeHeight={returnZero} - NativeWidth={returnZero} rootSelected={returnTrue} removeDocument={returnFalse} onClick={undefined} ScreenToLocalTransform={this.sidebarScreenToLocal} ContentScaling={returnOne} - PanelWidth={() => 60} + PanelWidth={this.menuPanelWidth} PanelHeight={this.getContentsHeight} renderDepth={0} focus={emptyFunction} @@ -512,6 +370,8 @@ export class MainView extends React.Component { whenActiveChanged={emptyFunction} bringToFront={emptyFunction} docFilters={returnEmptyFilter} + docRangeFilters={returnEmptyFilter} + searchFilterDocs={returnEmptyDoclist} ContainingCollectionView={undefined} ContainingCollectionDoc={undefined} relative={true} @@ -520,163 +380,90 @@ export class MainView extends React.Component { </div>; } - - @action - closeFlyout = () => { - this._lastButton && (this._lastButton.color = "white"); - this._lastButton && (this._lastButton._backgroundColor = ""); - this.panelContent = "none"; - this.flyoutWidth = 0; - } - - get groupManager() { return GroupManager.Instance; } - - _lastButton: Doc | undefined; @action selectMenu = (button: Doc) => { const title = StrCast(Doc.GetProto(button).title); - this._lastButton && (this._lastButton.color = "white"); - this._lastButton && (this._lastButton._backgroundColor = ""); - if (this.panelContent === title && this.flyoutWidth !== 0) { - this.panelContent = "none"; - this.flyoutWidth = 0; - } else { - let panelDoc: Doc | undefined; - switch (this.panelContent = title) { - case "Tools": panelDoc = Doc.UserDoc()["sidebar-tools"] as Doc ?? undefined; break; - case "Workspace": panelDoc = Doc.UserDoc()["sidebar-workspaces"] as Doc ?? undefined; break; - case "Catalog": panelDoc = Doc.UserDoc()["sidebar-catalog"] as Doc ?? undefined; break; - case "Archive": panelDoc = Doc.UserDoc()["sidebar-recentlyClosed"] as Doc ?? undefined; break; - case "Settings": SettingsManager.Instance.open(); break; - case "Import": panelDoc = Doc.UserDoc()["sidebar-import"] as Doc ?? undefined; break; - case "Sharing": panelDoc = Doc.UserDoc()["sidebar-sharing"] as Doc ?? undefined; break; - case "User Doc": panelDoc = Doc.UserDoc()["sidebar-userDoc"] as Doc ?? undefined; break; + const willOpen = !this._flyoutWidth || this._panelContent !== title; + this.closeFlyout(); + if (willOpen) { + switch (this._panelContent = title) { + case "Settings": + SettingsManager.Instance.open(); + break; + case "Catalog": + SearchBox.Instance._searchFullDB = "My Stuff"; + SearchBox.Instance.enter(undefined); + break; + default: + this.expandFlyout(button); } - this.sidebarContent.proto = panelDoc; - if (panelDoc) { - MainView.expandFlyout(); - button._backgroundColor = "lightgrey"; - button.color = "black"; - this._lastButton = button; - } else this.flyoutWidth = 0; } return true; } - @action - closeProperties = () => { - CurrentUserUtils.propertiesWidth = 0; - } - - @computed get propertiesView() { - TraceMobx(); - return <div className="mainView-propertiesView" style={{ - overflow: this.propertiesWidth() < 15 ? "hidden" : undefined - }}> - <PropertiesView - width={this.propertiesWidth()} - height={this._panelHeight} - renderDepth={1} - ScreenToLocalTransform={Transform.Identity} - onDown={this.closeProperties} - /> - </div>; - } - @computed get mainInnerContent() { - const rightFlyout = this.propertiesWidth() - 1; return <> {this.menuPanel} - <div style={{ display: "contents", flexDirection: "row", position: "relative" }}> - <div className="mainView-flyoutContainer" style={{ width: this.flyoutWidth }}> - {this.flyoutWidth !== 0 ? <div className="mainView-libraryHandle" - onPointerDown={this.onFlyoutPointerDown} - //style={{ backgroundColor: '#8c8b8b' }} - > - <span title="library View Dragger" style={{ - width: (this.flyoutWidth !== 0 && this._flyoutTranslate) ? "100%" : "3vw", - //height: (this.flyoutWidth !== 0 && this._flyoutTranslate) ? "100%" : "100vh", - position: (this.flyoutWidth !== 0 && this._flyoutTranslate) ? "absolute" : "fixed", - top: (this.flyoutWidth !== 0 && this._flyoutTranslate) ? "" : "0" - }} /> - <div className="mainview-libraryHandle-icon"> - <FontAwesomeIcon icon="chevron-left" color="black" size="sm" /> - </div> - </div> : null} - <div className="mainView-libraryFlyout" style={{ - //transformOrigin: this._flyoutTranslate ? "" : "left center", - transition: this._flyoutTranslate ? "" : "width .5s", - //transform: `scale(${this._flyoutTranslate ? 1 : 0.8})`, - boxShadow: this._flyoutTranslate ? "" : "rgb(156, 147, 150) 0.2vw 0.2vw 0.2vw" - }}> - {this.flyout} - {this.expandButton} - </div> + <div className="mainView-innerContent" > + {this.flyout} + <div className="mainView-libraryHandle" style={{ display: !this._flyoutWidth ? "none" : undefined }} onPointerDown={this.onFlyoutPointerDown} > + <FontAwesomeIcon icon="chevron-left" color="black" size="sm" /> </div> + {this.dockingContent} - {this.showProperties ? (null) : - <div className="mainView-propertiesDragger" title="Properties View Dragger" onPointerDown={this.onPropertiesPointerDown} - style={{ right: rightFlyout, top: "50%" }}> - <div className="mainView-propertiesDragger-icon"> - <FontAwesomeIcon icon={this.propertiesIcon} color="black" size="sm" /> </div> - </div> - } - {this.propertiesWidth() < 10 ? (null) : - <div style={{ width: this.propertiesWidth(), height: "calc(100% - 35px)" }}> {this.propertiesView} </div>} + + <div className="mainView-propertiesDragger" onPointerDown={this.onPropertiesPointerDown} style={{ right: this.propertiesWidth() - 1 }}> + <FontAwesomeIcon icon={this.propertiesWidth() < 10 ? "chevron-left" : "chevron-right"} color="black" size="sm" /> + </div> + {this.propertiesWidth() < 10 ? (null) : <PropertiesView width={this.propertiesWidth()} height={this.getContentsHeight()} />} </div> </>; } @computed get mainContent() { - const n = (CollectionMenu.Instance?.Pinned ? 1 : 0); - const height = `calc(100% - ${n * Number(ANTIMODEMENU_HEIGHT.replace("px", ""))}px)`; - const pinned = FormatShapePane.Instance?.Pinned; - const innerContent = this.mainInnerContent; - return !this.userDoc ? (null) : ( - <Measure offset onResize={this.onResize}> - {({ measureRef }) => - <div className="mainView-mainContent" ref={measureRef} style={{ - color: this.darkScheme ? "rgb(205,205,205)" : "black", - //change to times 2 for both pinned - height, - width: pinned ? `calc(100% - 200px)` : "100%" - }} > - {innerContent} - </div> - } - </Measure>); + return !this.userDoc ? (null) : + <div className="mainView-mainContent" ref={r => { + r && new _global.ResizeObserver(action(() => { this._panelWidth = r.getBoundingClientRect().width; this._panelHeight = r.getBoundingClientRect().height; })).observe(r); + }} style={{ + color: this.darkScheme ? "rgb(205,205,205)" : "black", + height: `calc(100% - ${this.topOffset}px)`, + width: "100%", + }} > + {this.mainInnerContent} + </div>; } - public static expandFlyout = action(() => { - MainView.Instance._flyoutTranslate = true; - MainView.Instance.flyoutWidth = (MainView.Instance.flyoutWidth || 250); - + expandFlyout = action((button: Doc) => { + this._flyoutWidth = (this._flyoutWidth || 250); + this._sidebarContent.proto = button.target as any; + button._backgroundColor = "lightgrey"; + button.color = "black"; + this._lastButton = button; }); - @computed get expandButton() { - return !this._flyoutTranslate ? (<div className="mainView-expandFlyoutButton" title="Re-attach sidebar" onPointerDown={MainView.expandFlyout}></div>) : (null); - } + closeFlyout = action(() => { + this._lastButton && (this._lastButton.color = "white"); + this._lastButton && (this._lastButton._backgroundColor = ""); + this._panelContent = "none"; + this._sidebarContent.proto = undefined; + this._flyoutWidth = 0; + }); - addButtonDoc = (doc: Doc | Doc[]) => (doc instanceof Doc ? [doc] : doc).reduce((flg: boolean, doc) => { - const ret = flg && Doc.AddDocToList(Doc.UserDoc().dockedBtns as Doc, "data", doc); - ret && (doc._stayInCollection = undefined); - return ret; - }, true) remButtonDoc = (doc: Doc | Doc[]) => (doc instanceof Doc ? [doc] : doc).reduce((flg: boolean, doc) => flg && Doc.RemoveDocFromList(Doc.UserDoc().dockedBtns as Doc, "data", doc), true); moveButtonDoc = (doc: Doc | Doc[], targetCollection: Doc | undefined, addDocument: (document: Doc | Doc[]) => boolean) => this.remButtonDoc(doc) && addDocument(doc); + addButtonDoc = (doc: Doc | Doc[]) => (doc instanceof Doc ? [doc] : doc).reduce((flg: boolean, doc) => flg && Doc.AddDocToList(Doc.UserDoc().dockedBtns as Doc, "data", doc), true); buttonBarXf = () => { if (!this._docBtnRef.current) return Transform.Identity(); const { scale, translateX, translateY } = Utils.GetScreenTransform(this._docBtnRef.current); return new Transform(-translateX, -translateY, 1 / scale); } + @computed get docButtons() { - const dockedBtns = Doc.UserDoc()?.dockedBtns; - if (dockedBtns instanceof Doc) { - return <div className="mainView-docButtons" ref={this._docBtnRef} - style={{ height: !dockedBtns.linearViewIsExpanded ? "42px" : undefined }} > + return !(this.userDoc.dockedBtns instanceof Doc) ? (null) : + <div className="mainView-docButtons" ref={this._docBtnRef} style={{ height: !this.userDoc.dockedBtns.linearViewIsExpanded ? "42px" : undefined }} > <CollectionLinearView - Document={dockedBtns} + Document={this.userDoc.dockedBtns} DataDoc={undefined} LibraryPath={emptyPath} fieldKey={"data"} @@ -697,31 +484,20 @@ export class MainView extends React.Component { onClick={undefined} ScreenToLocalTransform={this.buttonBarXf} ContentScaling={returnOne} - NativeHeight={returnZero} - NativeWidth={returnZero} PanelWidth={this.flyoutWidthFunc} PanelHeight={this.getContentsHeight} renderDepth={0} focus={emptyFunction} whenActiveChanged={emptyFunction} docFilters={returnEmptyFilter} + docRangeFilters={returnEmptyFilter} + searchFilterDocs={returnEmptyDoclist} ContainingCollectionView={undefined} ContainingCollectionDoc={undefined} /> </div>; - } - return (null); - } - - get mainViewElement() { - return document.getElementById("mainView-container"); - } - - get mainViewRef() { - return this._mainViewRef; } - @computed get snapLines() { - return !Doc.UserDoc().showSnapLines ? (null) : <div className="mainView-snapLines"> + return !this.userDoc.showSnapLines ? (null) : <div className="mainView-snapLines"> <svg style={{ width: "100%", height: "100%" }}> {SnappingManager.horizSnapLines().map(l => <line x1="0" y1={l} x2="2000" y2={l} stroke="black" opacity={0.3} strokeWidth={0.5} strokeDasharray={"1 1"} />)} {SnappingManager.vertSnapLines().map(l => <line y1="0" x1={l} y2="2000" x2={l} stroke="black" opacity={0.3} strokeWidth={0.5} strokeDasharray={"1 1"} />)} @@ -751,12 +527,18 @@ export class MainView extends React.Component { </defs> </svg>; } + select = (ctrlPressed: boolean) => { }; @computed get search() { + TraceMobx(); return <div className="mainView-searchPanel"> - {/* <div style={{ float: "left", marginLeft: "10px" }}>{Doc.CurrentUserEmail}</div> */} - <div><DocumentView Document={this.searchDoc} - DataDoc={undefined} + <SearchBox Document={CurrentUserUtils.MySearchPanelDoc} + DataDoc={CurrentUserUtils.MySearchPanelDoc} + fieldKey="data" + dropAction="move" + isSelected={returnTrue} + active={returnTrue} + select={this.select} LibraryPath={emptyPath} addDocument={undefined} addDocTab={this.addDocTabFunc} @@ -767,25 +549,23 @@ export class MainView extends React.Component { removeDocument={undefined} ScreenToLocalTransform={Transform.Identity} ContentScaling={returnOne} - NativeHeight={returnZero} - NativeWidth={returnZero} PanelWidth={this.getPWidth} PanelHeight={this.getPHeight} renderDepth={0} focus={emptyFunction} - parentActive={returnTrue} whenActiveChanged={emptyFunction} bringToFront={emptyFunction} docFilters={returnEmptyFilter} + docRangeFilters={returnEmptyFilter} + searchFilterDocs={returnEmptyDoclist} ContainingCollectionView={undefined} - ContainingCollectionDoc={undefined} - /></div> + ContainingCollectionDoc={undefined} /> </div>; } @computed get invisibleWebBox() { // see note under the makeLink method in HypothesisUtils.ts return !DocumentLinksButton.invisibleWebDoc ? null : - <div style={{ position: 'absolute', left: 50, top: 50, display: 'block', width: '500px', height: '1000px' }} ref={DocumentLinksButton.invisibleWebRef}> + <div className="mainView-invisibleWebRef" ref={DocumentLinksButton.invisibleWebRef}> <WebBox fieldKey={"data"} ContainingCollectionView={undefined} @@ -806,17 +586,16 @@ export class MainView extends React.Component { focus={returnFalse} PanelWidth={() => 500} PanelHeight={() => 800} - NativeHeight={() => 500} - NativeWidth={() => 800} ContentScaling={returnOne} docFilters={returnEmptyFilter} + docRangeFilters={returnEmptyFilter} + searchFilterDocs={returnEmptyDoclist} /> </div>; } render() { - return (<div className={"mainView-container" + (this.darkScheme ? "-dark" : "")} ref={this._mainViewRef}> - + return (<div className={"mainView-container" + (this.darkScheme ? "-dark" : "")} onScroll={() => ((ele) => ele.scrollTop = ele.scrollLeft = 0)(document.getElementById("root")!)} ref={this._mainViewRef}> {this.inkResources} <DictationOverlay /> <SharingManager /> @@ -826,7 +605,6 @@ export class MainView extends React.Component { <DocumentDecorations /> {this.search} <CollectionMenu /> - <FormatShapePane /> {LinkDescriptionPopup.descriptionPopup ? <LinkDescriptionPopup /> : null} {DocumentLinksButton.EditLink ? <LinkMenu docView={DocumentLinksButton.EditLink} addDocTab={DocumentLinksButton.EditLink.props.addDocTab} changeFlyout={emptyFunction} /> : (null)} {LinkDocPreview.LinkInfo ? <LinkDocPreview location={LinkDocPreview.LinkInfo.Location} backgroundColor={this.defaultBackgroundColors} @@ -838,15 +616,13 @@ export class MainView extends React.Component { <PreviewCursor /> <TaskCompletionBox /> <ContextMenu /> - <FormatShapePane /> <RadialMenu /> <PDFMenu /> <MarqueeOptionsMenu /> - <OverlayView /> <TimelineMenu /> {this.snapLines} - <div ref={this.makeWebRef} style={{ position: 'absolute', left: -1000, top: -1000, display: 'block', width: '200px', height: '800px' }} /> + <div className="mainView-webRef" ref={this.makeWebRef} /> </div >); } @@ -855,7 +631,7 @@ export class MainView extends React.Component { invisibleDoc => { ReactDOM.unmountComponentAtNode(ele); invisibleDoc && ReactDOM.render(<span title="Drag as document" className="invisible-webbox" > - <div style={{ position: 'absolute', left: -1000, top: -1000, display: 'block', width: '200px', height: '800px' }} ref={DocumentLinksButton.invisibleWebRef}> + <div className="mainView-webRef" ref={DocumentLinksButton.invisibleWebRef}> <WebBox fieldKey={"data"} ContainingCollectionView={undefined} @@ -876,116 +652,29 @@ export class MainView extends React.Component { focus={returnFalse} PanelWidth={() => 500} PanelHeight={() => 800} - NativeHeight={() => 500} - NativeWidth={() => 800} ContentScaling={returnOne} docFilters={returnEmptyFilter} + docRangeFilters={returnEmptyFilter} + searchFilterDocs={returnEmptyDoclist} /> </div>; </span>, ele); - var success = false; + let success = false; const onSuccess = () => { success = true; clearTimeout(interval); document.removeEventListener("editSuccess", onSuccess); }; - // For some reason, Hypothes.is annotations don't load until a click is registered on the page, + // For some reason, Hypothes.is annotations don't load until a click is registered on the page, // so we keep simulating clicks until annotations have loaded and editing is successful - const interval = setInterval(() => { - !success && simulateMouseClick(ele, 50, 50, 50, 50); - }, 500); - + const interval = setInterval(() => !success && simulateMouseClick(ele, 50, 50, 50, 50), 500); setTimeout(() => !success && clearInterval(interval), 10000); // give up if no success after 10s document.addEventListener("editSuccess", onSuccess); }); } - - importDocument = () => { - const sidebar = Cast(Doc.UserDoc()["sidebar-import-documents"], Doc, null); - const sidebarDocView = DocumentManager.Instance.getDocumentView(sidebar); - const input = document.createElement("input"); - input.type = "file"; - input.multiple = true; - input.accept = ".zip, application/pdf, video/*, image/*, audio/*"; - input.onchange = async _e => { - const upload = Utils.prepend("/uploadDoc"); - const formData = new FormData(); - const file = input.files && input.files[0]; - if (file && file.type === 'application/zip') { - formData.append('file', file); - formData.append('remap', "true"); - const response = await fetch(upload, { method: "POST", body: formData }); - const json = await response.json(); - if (json !== "error") { - const doc = await DocServer.GetRefField(json); - if (doc instanceof Doc && sidebarDocView) { - sidebarDocView.props.addDocument?.(doc); - setTimeout(() => { - SearchUtil.Search(`{!join from=id to=proto_i}id:link*`, true, {}).then(docs => { - docs.docs.forEach(d => LinkManager.Instance.addLink(d)); - }); - }, 2000); // need to give solr some time to update so that this query will find any link docs we've added. - - } - } - } else if (input.files && input.files.length !== 0) { - const files = input.files || []; - Array.from(files).forEach(async file => { - const res = await Networking.UploadFilesToServer(file); - res.map(async ({ result }) => { - const name = file.name; - if (result instanceof Error) { - return; - } - const path = Utils.prepend(result.accessPaths.agnostic.client); - let doc: Doc; - // Case 1: File is a video - if (file.type.includes("video")) { - doc = Docs.Create.VideoDocument(path, { _height: 100, title: name }); - // Case 2: File is a PDF document - } else if (file.type === "application/pdf") { - doc = Docs.Create.PdfDocument(path, { _height: 100, _fitWidth: true, title: name }); - // Case 3: File is an image - } else if (file.type.includes("image")) { - doc = Docs.Create.ImageDocument(path, { _height: 100, title: name }); - // Case 4: File is an audio document - } else { - doc = Docs.Create.AudioDocument(path, { title: name }); - } - const res = await rp.get(Utils.prepend("/getUserDocumentId")); - if (!res) { - throw new Error("No user id returned"); - } - const field = await DocServer.GetRefField(res); - let pending: Opt<Doc>; - if (field instanceof Doc) { - pending = sidebar; - } - if (pending) { - const data = await Cast(pending.data, listSpec(Doc)); - if (data) data.push(doc); - else pending.data = new List([doc]); - } - }); - }); - } else { - console.log("No file selected"); - } - }; - input.click(); - } } + Scripting.addGlobal(function selectMainMenu(doc: Doc, title: string) { MainView.Instance.selectMenu(doc); }); -Scripting.addGlobal(function freezeSidebar() { MainView.expandFlyout(); }); -Scripting.addGlobal(function toggleComicMode() { Doc.UserDoc().fontFamily = "Comic Sans MS"; Doc.UserDoc().renderStyle = Doc.UserDoc().renderStyle === "comic" ? undefined : "comic"; }); -Scripting.addGlobal(function copyWorkspace() { - const copiedWorkspace = Doc.MakeCopy(Cast(Doc.UserDoc().activeWorkspace, Doc, null), true); - const workspaces = Cast(Doc.UserDoc().myWorkspaces, Doc, null); - Doc.AddDocToList(workspaces, "data", copiedWorkspace); - // bcz: strangely, we need a timeout to prevent exceptions/issues initializing GoldenLayout (the rendering engine for Main Container) - setTimeout(() => MainView.Instance.openWorkspace(copiedWorkspace), 0); -}); -Scripting.addGlobal(function importDocument() { return MainView.Instance.importDocument(); }, - "imports files from device directly into the import sidebar"); +Scripting.addGlobal(function toggleComicMode() { Doc.UserDoc().fontFamily = "Comic Sans MS"; Doc.UserDoc().renderStyle = Doc.UserDoc().renderStyle === "comic" ? undefined : "comic"; });
\ No newline at end of file |