diff options
Diffstat (limited to 'src/client/documents/Documents.ts')
-rw-r--r-- | src/client/documents/Documents.ts | 143 |
1 files changed, 96 insertions, 47 deletions
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index f112bad38..369876428 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -1,7 +1,7 @@ import { action, runInAction } from "mobx"; -import { basename, extname } from "path"; +import { basename } from "path"; import { DateField } from "../../fields/DateField"; -import { Doc, DocListCast, DocListCastAsync, Field, HeightSym, Opt, WidthSym, Initializing, updateCachedAcls } from "../../fields/Doc"; +import { Doc, DocListCast, DocListCastAsync, Field, HeightSym, Initializing, Opt, updateCachedAcls, WidthSym } from "../../fields/Doc"; import { Id } from "../../fields/FieldSymbols"; import { HtmlField } from "../../fields/HtmlField"; import { InkField } from "../../fields/InkField"; @@ -13,20 +13,20 @@ import { ComputedField, ScriptField } from "../../fields/ScriptField"; import { Cast, NumCast, StrCast } from "../../fields/Types"; import { AudioField, ImageField, MapField, PdfField, VideoField, WebField, YoutubeField } from "../../fields/URLField"; import { SharingPermissions } from "../../fields/util"; -import { MessageStore } from "../../server/Message"; import { Upload } from "../../server/SharedMediaTypes"; import { OmitKeys, Utils } from "../../Utils"; import { YoutubeBox } from "../apis/youtube/YoutubeBox"; import { DocServer } from "../DocServer"; import { Networking } from "../Network"; +import { CurrentUserUtils } from "../util/CurrentUserUtils"; import { DocumentManager } from "../util/DocumentManager"; import { dropActionType } from "../util/DragManager"; import { DirectoryImportBox } from "../util/Import & Export/DirectoryImportBox"; import { LinkManager } from "../util/LinkManager"; import { Scripting } from "../util/Scripting"; import { undoBatch, UndoManager } from "../util/UndoManager"; -import { DimUnit } from "../views/collections/collectionMulticolumn/CollectionMulticolumnView"; import { CollectionDockingView } from "../views/collections/CollectionDockingView"; +import { DimUnit } from "../views/collections/collectionMulticolumn/CollectionMulticolumnView"; import { CollectionView, CollectionViewType } from "../views/collections/CollectionView"; import { ContextMenu } from "../views/ContextMenu"; import { ContextMenuProps } from "../views/ContextMenuItem"; @@ -36,30 +36,30 @@ import { AudioBox } from "../views/nodes/AudioBox"; import { ColorBox } from "../views/nodes/ColorBox"; import { ComparisonBox } from "../views/nodes/ComparisonBox"; import { DocFocusOptions } from "../views/nodes/DocumentView"; +import { EquationBox } from "../views/nodes/EquationBox"; +import { FieldViewProps } from "../views/nodes/FieldView"; import { FilterBox } from "../views/nodes/FilterBox"; -import { FontIconBox } from "../views/nodes/FontIconBox"; +import { FontIconBox } from "../views/nodes/button/FontIconBox"; import { FormattedTextBox } from "../views/nodes/formattedText/FormattedTextBox"; +import { FunctionPlotBox } from "../views/nodes/FunctionPlotBox"; import { ImageBox } from "../views/nodes/ImageBox"; import { KeyValueBox } from "../views/nodes/KeyValueBox"; import { LabelBox } from "../views/nodes/LabelBox"; import { LinkBox } from "../views/nodes/LinkBox"; import { LinkDescriptionPopup } from "../views/nodes/LinkDescriptionPopup"; import { PDFBox } from "../views/nodes/PDFBox"; -import { PresBox } from "../views/nodes/trails/PresBox"; import { ScreenshotBox } from "../views/nodes/ScreenshotBox"; import { ScriptingBox } from "../views/nodes/ScriptingBox"; import { SliderBox } from "../views/nodes/SliderBox"; import { TaskCompletionBox } from "../views/nodes/TaskCompletedBox"; +import { PresBox } from "../views/nodes/trails/PresBox"; +import { PresElementBox } from "../views/nodes/trails/PresElementBox"; import { VideoBox } from "../views/nodes/VideoBox"; import { WebBox } from "../views/nodes/WebBox"; -import { PresElementBox } from "../views/nodes/trails/PresElementBox"; import { SearchBox } from "../views/search/SearchBox"; import { DashWebRTCVideo } from "../views/webcam/DashWebRTCVideo"; import { DocumentType } from "./DocumentTypes"; -import { EquationBox } from "../views/nodes/EquationBox"; -import { FunctionPlotBox } from "../views/nodes/FunctionPlotBox"; -import { CurrentUserUtils } from "../util/CurrentUserUtils"; -import { FieldViewProps } from "../views/nodes/FieldView"; +import { IconProp } from "@fortawesome/fontawesome-svg-core"; import { MapBox } from "../views/nodes/MapBox/MapBox"; const path = require('path'); @@ -160,6 +160,7 @@ export class DocumentOptions { lng?: number; author?: string; _layoutKey?: string; + unrendered?: boolean; // denotes an annotation that is not rendered with a DocumentView (e.g, rtf/pdf text selections and links to scroll locations in web/pdf) type?: string; title?: string; "acl-Public"?: string; // public permissions @@ -218,7 +219,33 @@ export class DocumentOptions { annotationOn?: Doc; isPushpin?: boolean; _removeDropProperties?: List<string>; // list of properties that should be removed from a document when it is dropped. e.g., a creator button may be forceActive to allow it be dragged, but the forceActive property can be removed from the dropped document + + // BACKGROUND GRID + _backgroundGridShow?: boolean; + + //BUTTONS + buttonText?: string; iconShape?: string; // shapes of the fonticon border + btnType?: string; + btnList?: List<string>; + docColorBtn?: string; + userColorBtn?: string; + canClick?: string; + script?: string; + numBtnType?: string; + numBtnMax?: number; + numBtnMin?: number; + switchToggle?: boolean; + + //LINEAR VIEW + linearViewIsExpanded?: boolean; // is linear view expanded + linearViewExpandable?: boolean; // can linear view be expanded + linearViewToggleButton?: string; // button to open close linear view group + linearViewSubMenu?: boolean; + linearViewFloating?: boolean; + flexGap?: number; // Linear view flex gap + flexDirection?: "unset" | "row" | "column" | "row-reverse" | "column-reverse"; + layout_linkView?: Doc; // view template for a link document layout_keyValue?: string; // view tempalte for key value docs linkRelationship?: string; // type of relatinoship a link represents @@ -250,7 +277,12 @@ export class DocumentOptions { treeViewHideTitle?: boolean; // whether to hide the top document title of a tree view treeViewHideHeader?: boolean; // whether to hide the header for a document in a tree view treeViewHideHeaderFields?: boolean; // whether to hide the drop down options for tree view items. - treeViewShowClearButton?: boolean; // whether a clear button should be displayed + + // Action Button + buttonMenu?: boolean; // whether a action button should be displayed + buttonMenuDoc?: Doc; + explainer?: string; + treeViewOpenIsTransient?: boolean; // ignores the treeViewOpen Doc flag, allowing a treeViewItem's expand/collapse state to be independent of other views of the same document in the same or any other tree view _treeViewOpen?: boolean; // whether this document is expanded in a tree view (note: need _ and regular versions since this can be specified for both proto and layout docs) treeViewOpen?: boolean; // whether this document is expanded in a tree view @@ -265,14 +297,14 @@ export class DocumentOptions { text?: string; textTransform?: string; // is linear view expanded letterSpacing?: string; // is linear view expanded - flexDirection?: "unset" | "row" | "column" | "row-reverse" | "column-reverse"; selectedIndex?: number; // which item in a linear view has been selected using the "thumb doc" ui clipboard?: Doc; searchQuery?: string; // for quersyBox - linearViewIsExpanded?: boolean; // is linear view expanded useLinkSmallAnchor?: boolean; // whether links to this document should use a miniature linkAnchorBox border?: string; //for searchbox hoverBackgroundColor?: string; // background color of a label when hovered + linkRelationshipList?: List<string>; // for storing different link relationships (when set by user in the link editor) + linkColorList?: List<string>; // colors of links corresponding to specific link relationships } export namespace Docs { @@ -359,7 +391,7 @@ export namespace Docs { }], [DocumentType.AUDIO, { layout: { view: AudioBox, dataField: defaultDataKey }, - options: { _height: 35, backgroundColor: "lightGray", links: ComputedField.MakeFunction("links(self)") as any } + options: { _height: 100, backgroundColor: "lightGray", links: ComputedField.MakeFunction("links(self)") as any } }], [DocumentType.PDF, { layout: { view: PDFBox, dataField: defaultDataKey }, @@ -685,14 +717,14 @@ export namespace Docs { return linkDoc; } - export function InkDocument(color: string, tool: string, strokeWidth: string, strokeBezier: string, fillColor: string, arrowStart: string, arrowEnd: string, dash: string, points: { X: number, Y: number }[], options: DocumentOptions = {}) { + export function InkDocument(color: string, tool: string, strokeWidth: number, strokeBezier: string, fillColor: string, arrowStart: string, arrowEnd: string, dash: string, points: { X: number, Y: number }[], options: DocumentOptions = {}) { const I = new Doc(); I[Initializing] = true; I.type = DocumentType.INK; I.layout = InkingStroke.LayoutString("data"); I.color = color; I.fillColor = fillColor; - I.strokeWidth = Number(strokeWidth); + I.strokeWidth = strokeWidth; I.strokeBezier = strokeBezier; I.strokeStartMarker = arrowStart; I.strokeEndMarker = arrowEnd; @@ -701,7 +733,6 @@ export namespace Docs { I.title = "ink"; I.x = options.x; I.y = options.y; - I._backgroundColor = "transparent"; I._width = options._width as number; I._height = options._height as number; I._fontFamily = "cursive"; @@ -710,15 +741,26 @@ export namespace Docs { I.data = new InkField(points); I["acl-Public"] = Doc.UserDoc()?.defaultAclPrivate ? SharingPermissions.None : SharingPermissions.Augment; I["acl-Override"] = "None"; + I.links = ComputedField.MakeFunction("links(self)") as any; I[Initializing] = false; return I; } export function PdfDocument(url: string, options: DocumentOptions = {}) { + const width = options._width || undefined; + const height = options._height || undefined; + const nwid = options._nativeWidth || undefined; + const nhght = options._nativeHeight || undefined; + if (!nhght && width && height && nwid) options._nativeHeight = Number(nwid) * Number(height) / Number(width); return InstanceFromProto(Prototypes.get(DocumentType.PDF), new PdfField(url), options); } export function WebDocument(url: string, options: DocumentOptions = {}) { + const width = options._width || undefined; + const height = options._height || undefined; + const nwid = options._nativeWidth || undefined; + const nhght = options._nativeHeight || undefined; + if (!nhght && width && height && nwid) options._nativeHeight = Number(nwid) * Number(height) / Number(width); return InstanceFromProto(Prototypes.get(DocumentType.WEB), url ? new WebField(url) : undefined, options); } @@ -731,9 +773,9 @@ export namespace Docs { } export function MapMarkerDocument(lat: number, lng: number, documents: Array<Doc>, options: DocumentOptions, id?: string) { - return InstanceFromProto(Prototypes.get(DocumentType.MARKER), new List(documents), {lat, lng, ...options}, id); + return InstanceFromProto(Prototypes.get(DocumentType.MARKER), new List(documents), { lat, lng, ...options }, id); } - + export function KVPDocument(document: Doc, options: DocumentOptions = {}) { return InstanceFromProto(Prototypes.get(DocumentType.KVP), document, { title: document.title + ".kvp", ...options }); } @@ -932,12 +974,16 @@ export namespace DocUtils { // facets that have a check next to them const checks = Object.keys(facet).filter(value => facet[value] === "check"); + // metadata facets that exist + const exists = Object.keys(facet).filter(value => facet[value] === "exists"); + // facets that have an x next to them const xs = Object.keys(facet).filter(value => facet[value] === "x"); - if (!xs.length && !checks.length && !matches.length) return true; + if (!exists.length && !xs.length && !checks.length && !matches.length) return true; const failsNotEqualFacets = !xs.length ? false : xs.some(value => Doc.matchFieldValue(d, facetKey, value)); const satisfiesCheckFacets = !checks.length ? true : checks.some(value => Doc.matchFieldValue(d, facetKey, value)); + const satisfiesExistsFacets = !exists.length ? true : exists.some(value => d[facetKey] !== undefined); const satisfiesMatchFacets = !matches.length ? true : matches.some(value => { if (facetKey.startsWith("*")) { // fields starting with a '*' are used to match families of related fields. ie, *lastModified will match text-lastModified, data-lastModified, etc const allKeys = Array.from(Object.keys(d)); @@ -949,11 +995,11 @@ export namespace DocUtils { }); // if we're ORing them together, the default return is false, and we return true for a doc if it satisfies any one set of criteria if ((parentCollection?.currentFilter as Doc)?.filterBoolean === "OR") { - if (satisfiesCheckFacets && !failsNotEqualFacets && satisfiesMatchFacets) return true; + if (satisfiesExistsFacets && satisfiesCheckFacets && !failsNotEqualFacets && satisfiesMatchFacets) return true; } // if we're ANDing them together, the default return is true, and we return false for a doc if it doesn't satisfy any set of criteria else { - if (!satisfiesCheckFacets || failsNotEqualFacets || (matches.length && !satisfiesMatchFacets)) return false; + if (!satisfiesExistsFacets || !satisfiesCheckFacets || failsNotEqualFacets || (matches.length && !satisfiesMatchFacets)) return false; } } @@ -1155,11 +1201,12 @@ export namespace DocUtils { export function addDocumentCreatorMenuItems(docTextAdder: (d: Doc) => void, docAdder: (d: Doc) => void, x: number, y: number, simpleMenu: boolean = false): void { !simpleMenu && ContextMenu.Instance.addItem({ - description: "Add Note ...", + description: "Quick Notes", subitems: DocListCast((Doc.UserDoc()["template-notes"] as Doc).data).map((note, i) => ({ description: ":" + StrCast(note.title), event: undoBatch((args: { x: number, y: number }) => { const textDoc = Docs.Create.TextDocument("", { + _fontFamily: StrCast(Doc.UserDoc()._fontFamily), _fontSize: StrCast(Doc.UserDoc()._fontSize), _width: 200, x, y, _autoHeight: note._autoHeight !== false, title: StrCast(note.title) + "#" + (note.aliasCount = NumCast(note.aliasCount) + 1) }); @@ -1167,12 +1214,12 @@ export namespace DocUtils { textDoc[textDoc.layoutKey] = note; docTextAdder(textDoc); }), - icon: "eye" + icon: StrCast(note.icon) as IconProp })) as ContextMenuProps[], - icon: "eye" + icon: "sticky-note" }); - ContextMenu.Instance.addItem({ - description: ":=math", event: () => { + const math: ContextMenuProps = ({ + description: ":Math", event: () => { const created = Docs.Create.EquationDocument(); if (created) { created.author = Doc.CurrentUserEmail; @@ -1183,25 +1230,27 @@ export namespace DocUtils { EquationBox.SelectOnLoad = created[Id]; docAdder?.(created); } - }, icon: "compress-arrows-alt" + }, icon: "calculator" }); + const documentList: ContextMenuProps[] = DocListCast(Cast(Doc.UserDoc().myItemCreators, Doc, null)?.data).filter(btnDoc => !btnDoc.hidden).map(btnDoc => Cast(btnDoc?.dragFactory, Doc, null)).filter(doc => doc && doc !== Doc.UserDoc().emptyPresentation).map((dragDoc, i) => ({ + description: ":" + StrCast(dragDoc.title), + event: undoBatch((args: { x: number, y: number }) => { + const newDoc = Doc.copyDragFactory(dragDoc); + if (newDoc) { + newDoc.author = Doc.CurrentUserEmail; + newDoc.x = x; + newDoc.y = y; + if (newDoc.type === DocumentType.RTF) FormattedTextBox.SelectOnLoad = newDoc[Id]; + docAdder?.(newDoc); + } + }), + icon: Doc.toIcon(dragDoc), + })) as ContextMenuProps[]; + documentList.push(math); ContextMenu.Instance.addItem({ - description: "Add Template Doc ...", - subitems: DocListCast(Cast(Doc.UserDoc().myItemCreators, Doc, null)?.data).filter(btnDoc => !btnDoc.hidden).map(btnDoc => Cast(btnDoc?.dragFactory, Doc, null)).filter(doc => doc && doc !== Doc.UserDoc().emptyPresentation).map((dragDoc, i) => ({ - description: ":" + StrCast(dragDoc.title), - event: undoBatch((args: { x: number, y: number }) => { - const newDoc = Doc.copyDragFactory(dragDoc); - if (newDoc) { - newDoc.author = Doc.CurrentUserEmail; - newDoc.x = x; - newDoc.y = y; - if (newDoc.type === DocumentType.RTF) FormattedTextBox.SelectOnLoad = newDoc[Id]; - docAdder?.(newDoc); - } - }), - icon: "eye" - })) as ContextMenuProps[], - icon: "eye" + description: "Create document", + subitems: documentList, + icon: "file" }); }// applies a custom template to a document. the template is identified by it's short name (e.g, slideView not layout_slideView) export function makeCustomViewClicked(doc: Doc, creator: Opt<(documents: Array<Doc>, options: DocumentOptions, id?: string) => Doc>, templateSignature: string = "custom", docLayoutTemplate?: Doc) { @@ -1345,12 +1394,12 @@ export namespace DocUtils { let degrees = dms[0] / dms[1]; let minutes = dms[2] / dms[3] / 60.0; let seconds = dms[4] / dms[5] / 3600.0; - + if (['S', 'W'].includes(ref)) { degrees = -degrees; minutes = -minutes; seconds = -seconds } return (degrees + minutes + seconds).toFixed(5); - } + } } async function processFileupload(generatedDocuments: Doc[], name: string, type: string, result: Error | Upload.FileInformation, options: DocumentOptions) { |