import { library } from '@fortawesome/fontawesome-svg-core'; import { faHireAHelper, faBuffer } from '@fortawesome/free-brands-svg-icons'; import * as fa from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, computed, configure, observable, reaction, runInAction } 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 { 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 { DocServer } from '../DocServer'; import { Docs, DocumentOptions } from '../documents/Documents'; import { DocumentType } from '../documents/DocumentTypes'; import { CurrentUserUtils } from '../util/CurrentUserUtils'; import { DocumentManager } from '../util/DocumentManager'; import GroupManager from '../util/GroupManager'; import { HistoryUtil } from '../util/History'; import { Scripting } from '../util/Scripting'; import { SelectionManager } from '../util/SelectionManager'; 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 { CollectionLinearView } from './collections/CollectionLinearView'; import CollectionMenu from './collections/CollectionMenu'; import { CollectionView, CollectionViewType } from './collections/CollectionView'; import { ContextMenu } from './ContextMenu'; import { DictationOverlay } from './DictationOverlay'; import { DocumentDecorations } from './DocumentDecorations'; import GestureOverlay from './GestureOverlay'; import { ANTIMODEMENU_HEIGHT } from './globalCssVariables.scss'; import KeyManager from './GlobalKeyHandler'; import { LinkMenu } from './linking/LinkMenu'; import "./MainView.scss"; import { MainViewNotifs } from './MainViewNotifs'; import { AudioBox } from './nodes/AudioBox'; import { DocumentLinksButton } from './nodes/DocumentLinksButton'; import { DocumentView } from './nodes/DocumentView'; import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox'; import RichTextMenu from './nodes/formattedText/RichTextMenu'; import { LinkDescriptionPopup } from './nodes/LinkDescriptionPopup'; import { LinkDocPreview } from './nodes/LinkDocPreview'; import { RadialMenu } from './nodes/RadialMenu'; import { TaskCompletionBox } from './nodes/TaskCompletedBox'; import { OverlayView } from './OverlayView'; import PDFMenu from './pdf/PDFMenu'; import { PreviewCursor } from './PreviewCursor'; import { Hypothesis } from '../apis/hypothesis/HypothesisUtils'; import { undoBatch } from '../util/UndoManager'; import { WebBox } from './nodes/WebBox'; import * as ReactDOM from 'react-dom'; import { SearchBox } from './search/SearchBox'; @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(); private _mainViewRef = React.createRef(); @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); } @computed private get userDoc() { return Doc.UserDoc(); } @computed private get mainContainer() { return this.userDoc ? FieldValue(Cast(this.userDoc.activeWorkspace, Doc)) : CurrentUserUtils.GuestWorkspace; } @computed public get mainFreeform(): Opt { 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; componentDidMount() { DocServer.setPlaygroundFields(["dataTransition", "_viewTransition", "_panX", "_panY", "_viewScale", "_viewType", "_chromeStatus"]); // can play with these fields on someone else's const tag = document.createElement('script'); const proto = DocServer.GetRefField("rtfProto").then(proto => { (proto instanceof Doc) && reaction(() => StrCast(proto.BROADCAST_MESSAGE), msg => msg && alert(msg)); }); 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.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); } }); }); document.addEventListener("linkAnnotationToDash", Hypothesis.linkListener); } componentWillUnMount() { 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); } constructor(props: Readonly<{}>) { super(props); MainView.Instance = this; this._urlState = HistoryUtil.parseUrl(window.location) || {} as any; // causes errors to be generated when modifying an observable outside of an action CurrentUserUtils.propertiesWidth = 0; 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 instanceof Doc && (CurrentUserUtils.GuestTarget = field))); } } } } library.add(fa.faEdit, fa.faTrash, fa.faTrashAlt, fa.faShare, fa.faDownload, fa.faExpandArrowsAlt, fa.faLayerGroup, fa.faExternalLinkAlt, 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.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.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.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.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.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); this.initEventListeners(); 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-table" || (thing as any)?.dataset[icon] === "filter" || thing.className.toString() === "beta" || thing.className.toString() === "collectionSchemaView-menuOptions-wrapper") { check = true; } }); if (check === false) { SearchBox.Instance.closeSearch(); } } }); 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 document.addEventListener("pointerdown", this.globalPointerDown); document.addEventListener("pointerup", this.globalPointerUp); } initAuthenticationRouters = async () => { // Load the user's active workspace, 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 } ); } else { if (received && this._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); } }), ); } const doc = this.userDoc && await Cast(this.userDoc.activeWorkspace, Doc); if (doc) { this.openWorkspace(doc); } else { this.createNewWorkspace(); } } } @action createNewWorkspace = async (id?: string) => { 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: "Collection " + workspaceCount, }; const freeformDoc = CurrentUserUtils.GuestTarget || Docs.Create.FreeformDocument([], freeformOptions); const workspaceDoc = Docs.Create.StandardCollectionDockingDocument([{ doc: freeformDoc, initialWidth: 600, path: [Doc.UserDoc().myCatalog as Doc] }], { title: `Workspace ${workspaceCount}` }, id, "row"); const toggleTheme = ScriptField.MakeScript(`self.darkScheme = !self.darkScheme`); const toggleComic = ScriptField.MakeScript(`toggleComicMode()`); const copyWorkspace = ScriptField.MakeScript(`copyWorkspace()`); workspaceDoc.contextMenuScripts = new List([toggleTheme!, toggleComic!, copyWorkspace!]); workspaceDoc.contextMenuLabels = new List(["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([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, }); 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(); } } // if there is a pending doc, and it has new data, show it (syip: we use a timeout to prevent collection docking view from being uninitialized) setTimeout(async () => { const col = this.userDoc && await Cast(this.userDoc["sidebar-sharing"], Doc); col && Cast(col.data, listSpec(Doc)) && runInAction(() => MainViewNotifs.NotifsCol = col); }, 100); return true; } onDrop = (e: React.DragEvent) => { e.preventDefault(); e.stopPropagation(); } @action onResize = (r: any) => { this._panelWidth = r.offset.width;// - this.propertiesWidth(); this._panelHeight = r.offset.height; } @action getPWidth = () => this._panelWidth - this.propertiesWidth() getPHeight = () => this._panelHeight; getContentsHeight = () => this._panelHeight - this._buttonBarHeight; defaultBackgroundColors = (doc: Opt) => { 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(Doc.UserDoc().defaultColor); } 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)"; } default: return "black"; } } else { switch (doc?.type) { case DocumentType.FONTICON: return "black"; case DocumentType.RTF: return "#f1efeb"; 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"; } default: return "white"; } } } @computed get mainDocView() { return ; } @computed get dockingContent() { TraceMobx(); const mainContainer = this.mainContainer; const width = this.flyoutWidth + this.propertiesWidth(); return
{!mainContainer ? (null) : this.mainDocView}
; } @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); } @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(); })); } } 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); } sidebarScreenToLocal = () => new Transform(0, (CollectionMenu.Instance.Pinned ? -35 : 0), 1); //sidebarScreenToLocal = () => new Transform(0, (RichTextMenu.Instance.Pinned ? -35 : 0) + (CollectionMenu.Instance.Pinned ? -35 : 0), 1); mainContainerXf = () => this.sidebarScreenToLocal().translate(-55, 0); @computed get closePosition() { return 55 + this.flyoutWidth; } @computed get flyout() { if (!this.sidebarContent) return null; return
{/* {this.flyoutWidth > 0 ?
: null} */} "lightgrey"} />
{this.docButtons}
; } @computed get menuPanel() { return
60} PanelHeight={this.getContentsHeight} renderDepth={0} focus={emptyFunction} backgroundColor={this.defaultBackgroundColors} parentActive={returnTrue} whenActiveChanged={emptyFunction} bringToFront={emptyFunction} docFilters={returnEmptyFilter} ContainingCollectionView={undefined} ContainingCollectionDoc={undefined} relative={true} scriptContext={this} />
; } @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, str: string) => { this._lastButton && (this._lastButton.color = "white"); this._lastButton && (this._lastButton._backgroundColor = ""); if (this.panelContent === str && this.flyoutWidth !== 0) { this.panelContent = "none"; this.flyoutWidth = 0; } else { let panelDoc: Doc | undefined; switch (this.panelContent = str) { 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 "Sharing": panelDoc = Doc.UserDoc()["sidebar-sharing"] as Doc ?? undefined; break; case "UserDoc": panelDoc = Doc.UserDoc()["sidebar-userDoc"] as Doc ?? undefined; break; } 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
; } @computed get mainInnerContent() { const rightFlyout = this.propertiesWidth() - 1; return <> {this.menuPanel}
{this.flyoutWidth !== 0 ?
: null}
{this.flyout} {this.expandButton}
{this.dockingContent} {this.showProperties ? (null) :
} {this.propertiesWidth() < 10 ? (null) :
{this.propertiesView}
}
; } @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) : ( {({ measureRef }) =>
{innerContent}
}
); } public static expandFlyout = action(() => { MainView.Instance._flyoutTranslate = true; MainView.Instance.flyoutWidth = (MainView.Instance.flyoutWidth || 250); }); @computed get expandButton() { return !this._flyoutTranslate ? (
) : (null); } addButtonDoc = (doc: Doc | Doc[]) => (doc instanceof Doc ? [doc] : doc).reduce((flg: boolean, doc) => flg && Doc.AddDocToList(Doc.UserDoc().dockedBtns as Doc, "data", doc), 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); 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
; } return (null); } get mainViewElement() { return document.getElementById("mainView-container"); } get mainViewRef() { return this._mainViewRef; } @computed get snapLines() { return !Doc.UserDoc().showSnapLines ? (null) :
{SnappingManager.horizSnapLines().map(l => )} {SnappingManager.vertSnapLines().map(l => )}
; } @computed get inkResources() { return ; } @computed get search() { return
{/*
{Doc.CurrentUserEmail}
*/}
; } @computed get invisibleWebBox() { // see note under the makeLink method in HypothesisUtils.ts return !DocumentLinksButton.invisibleWebDoc ? null :
500} PanelHeight={() => 800} NativeHeight={() => 500} NativeWidth={() => 800} ContentScaling={returnOne} docFilters={returnEmptyFilter} />
; } render() { return (
{this.inkResources} {this.search}
{LinkDescriptionPopup.descriptionPopup ? : null} {DocumentLinksButton.EditLink ? : (null)} {LinkDocPreview.LinkInfo ? : (null)} {this.mainContent} {this.snapLines}
); } makeWebRef = (ele: HTMLDivElement) => { reaction(() => DocumentLinksButton.invisibleWebDoc, invisibleDoc => { ReactDOM.unmountComponentAtNode(ele); invisibleDoc && ReactDOM.render(
500} PanelHeight={() => 800} NativeHeight={() => 500} NativeWidth={() => 800} ContentScaling={returnOne} docFilters={returnEmptyFilter} />
;
, ele); var success = false; const onSuccess = () => { console.log("EDIT SUCCESS"); success = true; clearTimeout(interval); document.removeEventListener("editSuccess", onSuccess); }; const interval = setInterval(() => { // keep trying to click until annotations have loaded and editing is successful console.log("clicked"); !success && simulateMouseClick(ele, 50, 50, 50, 50); }, 500); setTimeout(() => !success && clearInterval(interval), 10000); // give up if no success after 10s document.addEventListener("editSuccess", onSuccess); }); } } 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); });