From 408c8beb55e774f466abe455bb1296c89fe0c256 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Wed, 13 May 2020 11:40:58 -0400 Subject: fixed presentations to not find items in the presentation list. cleaned up webbox css --- src/client/views/collections/CollectionStackingView.tsx | 1 + .../views/collections/collectionFreeForm/CollectionFreeFormView.tsx | 1 + 2 files changed, 2 insertions(+) (limited to 'src/client/views/collections') diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index 821a6d476..d97f26daf 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -207,6 +207,7 @@ export class CollectionStackingView extends CollectionSubView(StackingDocument) NativeHeight={returnZero} NativeWidth={returnZero} fitToBox={false} + dontRegisterView={this.props.dontRegisterView} rootSelected={this.rootSelected} dropAction={StrCast(this.props.Document.childDropAction) as dropActionType} onClick={this.onChildClickHandler} diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 6caee960d..cfa1a046f 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -893,6 +893,7 @@ export class CollectionFreeFormView extends CollectionSubView Date: Wed, 13 May 2020 20:09:06 -0400 Subject: fixed map view doc references. changed doc view lock icon. made web box content @computed --- src/client/views/collections/CollectionMapView.tsx | 4 +++- src/client/views/nodes/DocumentView.tsx | 4 +++- src/client/views/nodes/WebBox.tsx | 9 +++++++-- 3 files changed, 13 insertions(+), 4 deletions(-) (limited to 'src/client/views/collections') diff --git a/src/client/views/collections/CollectionMapView.tsx b/src/client/views/collections/CollectionMapView.tsx index 971224482..13c06b0a3 100644 --- a/src/client/views/collections/CollectionMapView.tsx +++ b/src/client/views/collections/CollectionMapView.tsx @@ -206,7 +206,8 @@ class CollectionMapView extends CollectionSubView render() { const { childLayoutPairs } = this; const { Document, fieldKey, active, google } = this.props; - let center = this.getLocation(Document, `${fieldKey}-mapCenter`, false); + const mapLoc = this.getLocation(this.rootDoc, `${fieldKey}-mapCenter`, false); + let center = mapLoc; if (center === undefined) { const childLocations = childLayoutPairs.map(({ layout }) => this.getLocation(layout, Doc.LayoutFieldKey(layout), false)); center = childLocations.find(location => location) || defaultLocation; @@ -246,6 +247,7 @@ class CollectionMapView extends CollectionSubView }} > {this.reactiveContents} + {mapLoc ? this.renderMarker(this.rootDoc) : undefined} ; diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 91275d89b..d821bb8ac 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -1165,7 +1165,9 @@ export class DocumentView extends DocComponent(Docu : this.innards} {(this.Document.isBackground !== undefined || this.isSelected(false)) && this.props.renderDepth > 0 && this.props.PanelWidth() > 0 ? -
this.toggleBackground(true)}>
+
this.toggleBackground(true)}> + +
: (null)} ; { this._showKPQuery ? : undefined; } diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index b0abb2479..6d4cc1a07 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -311,7 +311,8 @@ export class WebBox extends ViewBoxAnnotatableComponent; } - + return view; + } + @computed + get content() { + const view = this.urlContent; const decInteracting = DocumentDecorations.Instance?.Interacting; const frozen = !this.props.isSelected() || decInteracting; -- cgit v1.2.3-70-g09d2 From f9385130fe297088754d4ce46d6c318c8be2121d Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Thu, 14 May 2020 01:29:19 -0700 Subject: server side restructure, some documentation to accompany new wiki overview entry --- src/client/util/CurrentUserUtils.ts | 738 +++++++++++++++++++++ src/client/util/SettingsManager.tsx | 2 +- src/client/views/GestureOverlay.tsx | 2 +- src/client/views/InkingControl.tsx | 2 +- src/client/views/Main.tsx | 2 +- src/client/views/MainView.tsx | 2 +- src/client/views/collections/CollectionMapView.tsx | 13 +- src/client/views/collections/CollectionSubView.tsx | 2 +- src/client/views/collections/CollectionView.tsx | 2 +- .../CollectionFreeFormRemoteCursors.tsx | 2 +- src/client/views/nodes/ColorBox.tsx | 2 +- src/mobile/ImageUpload.tsx | 3 +- src/mobile/MobileInterface.tsx | 4 +- src/server/ApiManagers/ApiManager.ts | 2 +- src/server/ApiManagers/DeleteManager.ts | 2 +- src/server/ApiManagers/GeneralGoogleManager.ts | 2 +- src/server/DashSession/DashSessionAgent.ts | 2 +- src/server/RouteManager.ts | 2 +- src/server/Websocket/Websocket.ts | 305 --------- src/server/apis/google/CredentialsLoader.ts | 29 + src/server/apis/google/GoogleApiServerUtils.ts | 10 +- .../apis/google/google_project_credentials.json | 11 + src/server/apis/youtube/youtubeApiSample.js | 22 +- src/server/authentication/AuthenticationManager.ts | 268 ++++++++ src/server/authentication/DashUserModel.ts | 86 +++ src/server/authentication/Passport.ts | 29 + src/server/authentication/config/passport.ts | 29 - .../authentication/controllers/user_controller.ts | 268 -------- .../authentication/models/current_user_utils.ts | 738 --------------------- src/server/authentication/models/user_model.ts | 86 --- src/server/credentials/CredentialsLoader.ts | 29 - .../credentials/google_project_credentials.json | 11 - src/server/database.ts | 78 ++- src/server/index.ts | 7 +- src/server/server_Initialization.ts | 4 +- src/server/websocket.ts | 297 +++++++++ webpack.config.js | 27 +- 37 files changed, 1586 insertions(+), 1534 deletions(-) create mode 100644 src/client/util/CurrentUserUtils.ts delete mode 100644 src/server/Websocket/Websocket.ts create mode 100644 src/server/apis/google/CredentialsLoader.ts create mode 100644 src/server/apis/google/google_project_credentials.json create mode 100644 src/server/authentication/AuthenticationManager.ts create mode 100644 src/server/authentication/DashUserModel.ts create mode 100644 src/server/authentication/Passport.ts delete mode 100644 src/server/authentication/config/passport.ts delete mode 100644 src/server/authentication/controllers/user_controller.ts delete mode 100644 src/server/authentication/models/current_user_utils.ts delete mode 100644 src/server/authentication/models/user_model.ts delete mode 100644 src/server/credentials/CredentialsLoader.ts delete mode 100644 src/server/credentials/google_project_credentials.json create mode 100644 src/server/websocket.ts (limited to 'src/client/views/collections') diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts new file mode 100644 index 000000000..46d356263 --- /dev/null +++ b/src/client/util/CurrentUserUtils.ts @@ -0,0 +1,738 @@ +import { computed, observable, reaction } from "mobx"; +import * as rp from 'request-promise'; +import { Utils } from "../../Utils"; +import { DocServer } from "../DocServer"; +import { Docs, DocumentOptions } from "../documents/Documents"; +import { UndoManager } from "./UndoManager"; +import { Doc, DocListCast, DocListCastAsync } from "../../new_fields/Doc"; +import { List } from "../../new_fields/List"; +import { listSpec } from "../../new_fields/Schema"; +import { ScriptField, ComputedField } from "../../new_fields/ScriptField"; +import { Cast, PromiseValue, StrCast, NumCast } from "../../new_fields/Types"; +import { nullAudio } from "../../new_fields/URLField"; +import { DragManager } from "./DragManager"; +import { InkingControl } from "../views/InkingControl"; +import { Scripting } from "./Scripting"; +import { CollectionViewType } from "../views/collections/CollectionView"; +import { makeTemplate } from "./DropConverter"; +import { RichTextField } from "../../new_fields/RichTextField"; +import { PrefetchProxy } from "../../new_fields/Proxy"; +import { FormattedTextBox } from "../views/nodes/formattedText/FormattedTextBox"; +import { MainView } from "../views/MainView"; +import { DocumentType } from "../documents/DocumentTypes"; +import { SchemaHeaderField } from "../../new_fields/SchemaHeaderField"; +import { DimUnit } from "../views/collections/collectionMulticolumn/CollectionMulticolumnView"; + +export class CurrentUserUtils { + private static curr_id: string; + //TODO tfs: these should be temporary... + private static mainDocId: string | undefined; + + public static get id() { return this.curr_id; } + public static get MainDocId() { return this.mainDocId; } + public static set MainDocId(id: string | undefined) { this.mainDocId = id; } + @computed public static get UserDocument() { return Doc.UserDoc(); } + @computed public static get ActivePen() { return Doc.UserDoc().activePen instanceof Doc && (Doc.UserDoc().activePen as Doc).inkPen as Doc; } + + @observable public static GuestTarget: Doc | undefined; + @observable public static GuestWorkspace: Doc | undefined; + @observable public static GuestMobile: Doc | undefined; + + // sets up the default User Templates - slideView, queryView, descriptionView + static setupUserTemplateButtons(doc: Doc) { + if (doc["template-button-query"] === undefined) { + const queryTemplate = Docs.Create.MulticolumnDocument( + [ + Docs.Create.QueryDocument({ title: "query", _height: 200 }), + Docs.Create.FreeformDocument([], { title: "data", _height: 100, _LODdisable: true }) + ], + { _width: 400, _height: 300, title: "queryView", _chromeStatus: "disabled", _xMargin: 3, _yMargin: 3, hideFilterView: true } + ); + queryTemplate.isTemplateDoc = makeTemplate(queryTemplate); + doc["template-button-query"] = CurrentUserUtils.ficon({ + onDragStart: ScriptField.MakeFunction('getCopy(this.dragFactory, true)'), + dragFactory: new PrefetchProxy(queryTemplate) as any as Doc, + removeDropProperties: new List(["dropAction"]), title: "query view", icon: "question-circle" + }); + } + + if (doc["template-button-slides"] === undefined) { + const slideTemplate = Docs.Create.MultirowDocument( + [ + Docs.Create.MulticolumnDocument([], { title: "data", _height: 200 }), + Docs.Create.TextDocument("", { title: "text", _height: 100 }) + ], + { _width: 400, _height: 300, title: "slideView", _chromeStatus: "disabled", _xMargin: 3, _yMargin: 3, hideFilterView: true } + ); + slideTemplate.isTemplateDoc = makeTemplate(slideTemplate); + doc["template-button-slides"] = CurrentUserUtils.ficon({ + onDragStart: ScriptField.MakeFunction('getCopy(this.dragFactory, true)'), + dragFactory: new PrefetchProxy(slideTemplate) as any as Doc, + removeDropProperties: new List(["dropAction"]), title: "presentation slide", icon: "address-card" + }); + } + + if (doc["template-button-description"] === undefined) { + const descriptionTemplate = Docs.Create.TextDocument(" ", { title: "header", _height: 100 }, "header"); // text needs to be a space to allow templateText to be created + Doc.GetProto(descriptionTemplate).layout = + "
" + + "
"; + descriptionTemplate.isTemplateDoc = makeTemplate(descriptionTemplate, true, "descriptionView"); + + doc["template-button-description"] = CurrentUserUtils.ficon({ + onDragStart: ScriptField.MakeFunction('makeDelegate(this.dragFactory)'), + dragFactory: new PrefetchProxy(descriptionTemplate) as any as Doc, + removeDropProperties: new List(["dropAction"]), title: "description view", icon: "window-maximize" + }); + } + + if (doc["template-button-switch"] === undefined) { + const { FreeformDocument, MulticolumnDocument, TextDocument } = Docs.Create; + + const yes = FreeformDocument([], { title: "yes", _height: 35, _width: 50, _LODdisable: true, _dimUnit: DimUnit.Pixel, _dimMagnitude: 40 }); + const name = TextDocument("name", { title: "name", _height: 35, _width: 70, _dimMagnitude: 1 }); + const no = FreeformDocument([], { title: "no", _height: 100, _width: 100, _LODdisable: true }); + const labelTemplate = { + doc: { + type: "doc", content: [{ + type: "paragraph", + content: [{ type: "dashField", attrs: { fieldKey: "PARAMS", hideKey: true } }] + }] + }, + selection: { type: "text", anchor: 1, head: 1 }, + storedMarks: [] + }; + Doc.GetProto(name).text = new RichTextField(JSON.stringify(labelTemplate), "PARAMS"); + Doc.GetProto(yes).backgroundColor = ComputedField.MakeFunction("self[this.PARAMS] ? 'green':'red'"); + // Doc.GetProto(no).backgroundColor = ComputedField.MakeFunction("!self[this.PARAMS] ? 'red':'white'"); + // Doc.GetProto(yes).onClick = ScriptField.MakeScript("self[this.PARAMS] = true"); + Doc.GetProto(yes).onClick = ScriptField.MakeScript("self[this.PARAMS] = !self[this.PARAMS]"); + // Doc.GetProto(no).onClick = ScriptField.MakeScript("self[this.PARAMS] = false"); + const box = MulticolumnDocument([/*no, */ yes, name], { title: "value", _width: 120, _height: 35, }); + box.isTemplateDoc = makeTemplate(box, true, "switch"); + + doc["template-button-switch"] = CurrentUserUtils.ficon({ + onDragStart: ScriptField.MakeFunction('getCopy(this.dragFactory, true)'), + dragFactory: new PrefetchProxy(box) as any as Doc, + removeDropProperties: new List(["dropAction"]), title: "data switch", icon: "toggle-on" + }); + } + + if (doc["template-button-detail"] === undefined) { + const { TextDocument, MasonryDocument, CarouselDocument } = Docs.Create; + + const openInTarget = ScriptField.MakeScript("openOnRight(self.doubleClickView)"); + const carousel = CarouselDocument([], { + title: "data", _height: 350, _itemIndex: 0, "_carousel-caption-xMargin": 10, "_carousel-caption-yMargin": 10, + onChildDoubleClick: openInTarget, backgroundColor: "#9b9b9b3F" + }); + + const details = TextDocument("", { title: "details", _height: 350, _autoHeight: true }); + const short = TextDocument("", { title: "shortDescription", treeViewOpen: true, treeViewExpandedView: "layout", _height: 100, _autoHeight: true }); + const long = TextDocument("", { title: "longDescription", treeViewOpen: false, treeViewExpandedView: "layout", _height: 350, _autoHeight: true }); + + const buxtonFieldKeys = ["year", "originalPrice", "degreesOfFreedom", "company", "attribute", "primaryKey", "secondaryKey", "dimensions"]; + const detailedTemplate = { + doc: { + type: "doc", content: buxtonFieldKeys.map(fieldKey => ({ + type: "paragraph", + content: [{ type: "dashField", attrs: { fieldKey } }] + })) + }, + selection: { type: "text", anchor: 1, head: 1 }, + storedMarks: [] + }; + details.text = new RichTextField(JSON.stringify(detailedTemplate), buxtonFieldKeys.join(" ")); + + const shared = { _chromeStatus: "disabled", _autoHeight: true, _xMargin: 0 }; + const detailViewOpts = { title: "detailView", _width: 300, _fontFamily: "Arial", _fontSize: 12 }; + const descriptionWrapperOpts = { title: "descriptions", _height: 300, columnWidth: -1, treeViewHideTitle: true, _pivotField: "title" }; + + const descriptionWrapper = MasonryDocument([details, short, long], { ...shared, ...descriptionWrapperOpts }); + descriptionWrapper.sectionHeaders = new List([ + new SchemaHeaderField("[A Short Description]", "dimGray", undefined, undefined, undefined, false), + new SchemaHeaderField("[Long Description]", "dimGray", undefined, undefined, undefined, true), + new SchemaHeaderField("[Details]", "dimGray", undefined, undefined, undefined, true), + ]); + const detailView = Docs.Create.StackingDocument([carousel, descriptionWrapper], { ...shared, ...detailViewOpts }); + detailView.isTemplateDoc = makeTemplate(detailView); + + details.title = "Details"; + short.title = "A Short Description"; + long.title = "Long Description"; + + doc["template-button-detail"] = CurrentUserUtils.ficon({ + onDragStart: ScriptField.MakeFunction('getCopy(this.dragFactory, true)'), + dragFactory: new PrefetchProxy(detailView) as any as Doc, + removeDropProperties: new List(["dropAction"]), title: "detail view", icon: "window-maximize" + }); + } + + if (doc["template-buttons"] === undefined) { + doc["template-buttons"] = new PrefetchProxy(Docs.Create.MasonryDocument([doc["template-button-slides"] as Doc, doc["template-button-description"] as Doc, + doc["template-button-query"] as Doc, doc["template-button-detail"] as Doc, doc["template-button-switch"] as Doc], { + title: "Advanced Item Prototypes", _xMargin: 0, _showTitle: "title", + _autoHeight: true, _width: 500, columnWidth: 35, ignoreClick: true, lockedPosition: true, _chromeStatus: "disabled", + dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }), + })); + } else { + const curButnTypes = Cast(doc["template-buttons"], Doc, null); + const requiredTypes = [doc["template-button-slides"] as Doc, doc["template-button-description"] as Doc, + doc["template-button-query"] as Doc, doc["template-button-detail"] as Doc, doc["template-button-switch"] as Doc]; + DocListCastAsync(curButnTypes.data).then(async curBtns => { + await Promise.all(curBtns!); + requiredTypes.map(btype => Doc.AddDocToList(curButnTypes, "data", btype)); + }); + } + return doc["template-buttons"] as Doc; + } + + // setup the different note type skins + static setupNoteTemplates(doc: Doc) { + if (doc["template-note-Note"] === undefined) { + const noteView = Docs.Create.TextDocument("", { title: "text", style: "Note", isTemplateDoc: true, backgroundColor: "yellow" }); + noteView.isTemplateDoc = makeTemplate(noteView, true, "Note"); + doc["template-note-Note"] = new PrefetchProxy(noteView); + } + if (doc["template-note-Idea"] === undefined) { + const noteView = Docs.Create.TextDocument("", { title: "text", style: "Idea", backgroundColor: "pink" }); + noteView.isTemplateDoc = makeTemplate(noteView, true, "Idea"); + doc["template-note-Idea"] = new PrefetchProxy(noteView); + } + if (doc["template-note-Topic"] === undefined) { + const noteView = Docs.Create.TextDocument("", { title: "text", style: "Topic", backgroundColor: "lightBlue" }); + noteView.isTemplateDoc = makeTemplate(noteView, true, "Topic"); + doc["template-note-Topic"] = new PrefetchProxy(noteView); + } + if (doc["template-note-Todo"] === undefined) { + const noteView = Docs.Create.TextDocument("", { + title: "text", style: "Todo", backgroundColor: "orange", _autoHeight: false, _height: 100, _showCaption: "caption", + layout: FormattedTextBox.LayoutString("Todo"), caption: RichTextField.DashField("taskStatus") + }); + noteView.isTemplateDoc = makeTemplate(noteView, true, "Todo"); + doc["template-note-Todo"] = new PrefetchProxy(noteView); + } + const taskStatusValues = [ + { title: "todo", _backgroundColor: "blue", color: "white" }, + { title: "in progress", _backgroundColor: "yellow", color: "black" }, + { title: "completed", _backgroundColor: "green", color: "white" } + ]; + if (doc.fieldTypes === undefined) { + doc.fieldTypes = Docs.Create.TreeDocument([], { title: "field enumerations" }); + Doc.addFieldEnumerations(Doc.GetProto(doc["template-note-Todo"] as any as Doc), "taskStatus", taskStatusValues); + } + + if (doc["template-notes"] === undefined) { + doc["template-notes"] = new PrefetchProxy(Docs.Create.TreeDocument([doc["template-note-Note"] as any as Doc, + doc["template-note-Idea"] as any as Doc, doc["template-note-Topic"] as any as Doc, doc["template-note-Todo"] as any as Doc], + { title: "Note Layouts", _height: 75 })); + } else { + const curNoteTypes = Cast(doc["template-notes"], Doc, null); + const requiredTypes = [doc["template-note-Note"] as any as Doc, doc["template-note-Idea"] as any as Doc, + doc["template-note-Topic"] as any as Doc, doc["template-note-Todo"] as any as Doc]; + DocListCastAsync(curNoteTypes.data).then(async curNotes => { + await Promise.all(curNotes!); + requiredTypes.map(ntype => Doc.AddDocToList(curNoteTypes, "data", ntype)); + }); + } + + return doc["template-notes"] as Doc; + } + + // creates Note templates, and initial "user" templates + static setupDocTemplates(doc: Doc) { + const noteTemplates = CurrentUserUtils.setupNoteTemplates(doc); + const userTemplateBtns = CurrentUserUtils.setupUserTemplateButtons(doc); + const clickTemplates = CurrentUserUtils.setupClickEditorTemplates(doc); + if (doc.templateDocs === undefined) { + doc.templateDocs = new PrefetchProxy(Docs.Create.TreeDocument([noteTemplates, userTemplateBtns, clickTemplates], { + title: "template layouts", _xPadding: 0, + dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }) + })); + } + } + + // setup templates for different document types when they are iconified from Document Decorations + static setupDefaultIconTemplates(doc: Doc) { + if (doc["template-icon-view"] === undefined) { + const iconView = Docs.Create.TextDocument("", { + title: "icon", _width: 150, _height: 30, isTemplateDoc: true, onDoubleClick: ScriptField.MakeScript("deiconifyView(self)") + }); + Doc.GetProto(iconView).icon = new RichTextField('{"doc":{"type":"doc","content":[{"type":"paragraph","attrs":{"align":null,"color":null,"id":null,"indent":null,"inset":null,"lineSpacing":null,"paddingBottom":null,"paddingTop":null},"content":[{"type":"dashField","attrs":{"fieldKey":"title","docid":""}}]}]},"selection":{"type":"text","anchor":2,"head":2},"storedMarks":[]}', ""); + iconView.isTemplateDoc = makeTemplate(iconView); + doc["template-icon-view"] = new PrefetchProxy(iconView); + } + if (doc["template-icon-view-rtf"] === undefined) { + const iconRtfView = Docs.Create.LabelDocument({ + title: "icon_" + DocumentType.RTF, textTransform: "unset", letterSpacing: "unset", + _width: 150, _height: 70, _xPadding: 10, _yPadding: 10, isTemplateDoc: true, onDoubleClick: ScriptField.MakeScript("deiconifyView(self)") + }); + iconRtfView.isTemplateDoc = makeTemplate(iconRtfView, true, "icon_" + DocumentType.RTF); + doc["template-icon-view-rtf"] = new PrefetchProxy(iconRtfView); + } + if (doc["template-icon-view-img"] === undefined) { + const iconImageView = Docs.Create.ImageDocument("http://www.cs.brown.edu/~bcz/face.gif", { + title: "data", _width: 50, isTemplateDoc: true, onDoubleClick: ScriptField.MakeScript("deiconifyView(self)") + }); + iconImageView.isTemplateDoc = makeTemplate(iconImageView, true, "icon_" + DocumentType.IMG); + doc["template-icon-view-img"] = new PrefetchProxy(iconImageView); + } + if (doc["template-icon-view-col"] === undefined) { + const iconColView = Docs.Create.TreeDocument([], { title: "data", _width: 180, _height: 80, onDoubleClick: ScriptField.MakeScript("deiconifyView(self)") }); + iconColView.isTemplateDoc = makeTemplate(iconColView, true, "icon_" + DocumentType.COL); + doc["template-icon-view-col"] = new PrefetchProxy(iconColView); + } + if (doc["template-icons"] === undefined) { + doc["template-icons"] = new PrefetchProxy(Docs.Create.TreeDocument([doc["template-icon-view"] as Doc, doc["template-icon-view-img"] as Doc, + doc["template-icon-view-col"] as Doc, doc["template-icon-view-rtf"] as Doc], { title: "icon templates", _height: 75 })); + } else { + const templateIconsDoc = Cast(doc["template-icons"], Doc, null); + const requiredTypes = [doc["template-icon-view"] as Doc, doc["template-icon-view-img"] as Doc, + doc["template-icon-view-col"] as Doc, doc["template-icon-view-rtf"] as Doc]; + DocListCastAsync(templateIconsDoc.data).then(async curIcons => { + await Promise.all(curIcons!); + requiredTypes.map(ntype => Doc.AddDocToList(templateIconsDoc, "data", ntype)); + }); + } + return doc["template-icons"] as Doc; + } + + static creatorBtnDescriptors(doc: Doc): { + title: string, label: string, icon: string, drag?: string, ignoreClick?: boolean, + click?: string, ischecked?: string, activePen?: Doc, backgroundColor?: string, dragFactory?: Doc + }[] { + if (doc.emptyPresentation === undefined) { + doc.emptyPresentation = Docs.Create.PresDocument(new List(), + { title: "Presentation", _viewType: CollectionViewType.Stacking, targetDropAction: "alias", _LODdisable: true, _chromeStatus: "replaced", _showTitle: "title", boxShadow: "0 0" }); + } + if (doc.emptyCollection === undefined) { + doc.emptyCollection = Docs.Create.FreeformDocument([], + { _nativeWidth: undefined, _nativeHeight: undefined, _LODdisable: true, _width: 150, _height: 100, title: "freeform" }); + } + if (doc.emptyDocHolder === undefined) { + doc.emptyDocHolder = Docs.Create.DocumentDocument( + ComputedField.MakeFunction("selectedDocs(this,this.excludeCollections,[_last_])?.[0]") as any, + { _width: 250, _height: 250, title: "container" }); + } + if (doc.emptyWebpage === undefined) { + doc.emptyWebpage = Docs.Create.WebDocument("", { title: "New Webpage", _width: 600, UseCors: true }); + } + return [ + { title: "Drag a collection", label: "Col", icon: "folder", click: 'openOnRight(getCopy(this.dragFactory, true))', drag: 'getCopy(this.dragFactory, true)', dragFactory: doc.emptyCollection as Doc }, + { title: "Drag a web page", label: "Web", icon: "globe-asia", click: 'openOnRight(getCopy(this.dragFactory, true))', drag: 'getCopy(this.dragFactory, true)', dragFactory: doc.emptyWebpage as Doc }, + { title: "Drag a cat image", label: "Img", icon: "cat", ignoreClick: true, drag: 'Docs.Create.ImageDocument("https://upload.wikimedia.org/wikipedia/commons/thumb/3/3a/Cat03.jpg/1200px-Cat03.jpg", { _width: 250, _nativeWidth:250, title: "an image of a cat" })' }, + { title: "Drag a screenshot", label: "Grab", icon: "photo-video", ignoreClick: true, drag: 'Docs.Create.ScreenshotDocument("", { _width: 400, _height: 200, title: "screen snapshot" })' }, + { title: "Drag a webcam", label: "Cam", icon: "video", ignoreClick: true, drag: 'Docs.Create.WebCamDocument("", { _width: 400, _height: 400, title: "a test cam" })' }, + { title: "Drag a audio recorder", label: "Audio", icon: "microphone", ignoreClick: true, drag: `Docs.Create.AudioDocument("${nullAudio}", { _width: 200, title: "ready to record audio" })` }, + { title: "Drag a clickable button", label: "Btn", icon: "bolt", ignoreClick: true, drag: 'Docs.Create.ButtonDocument({ _width: 150, _height: 50, _xPadding:10, _yPadding: 10, title: "Button" })' }, + { title: "Drag a presentation view", label: "Prezi", icon: "tv", click: 'openOnRight(Doc.UserDoc().activePresentation = getCopy(this.dragFactory, true))', drag: `Doc.UserDoc().activePresentation = getCopy(this.dragFactory,true)`, dragFactory: doc.emptyPresentation as Doc }, + { title: "Drag a search box", label: "Query", icon: "search", ignoreClick: true, drag: 'Docs.Create.QueryDocument({ _width: 200, title: "an image of a cat" })' }, + { title: "Drag a scripting box", label: "Script", icon: "terminal", ignoreClick: true, drag: 'Docs.Create.ScriptingDocument(undefined, { _width: 200, _height: 250 title: "untitled script" })' }, + { title: "Drag an import folder", label: "Load", icon: "cloud-upload-alt", ignoreClick: true, drag: 'Docs.Create.DirectoryImportDocument({ title: "Directory Import", _width: 400, _height: 400 })' }, + { title: "Drag a mobile view", label: "Phone", icon: "phone", ignoreClick: true, drag: 'Doc.UserDoc().activeMobile' }, + { title: "Drag an instance of the device collection", label: "Buxton", icon: "globe-asia", ignoreClick: true, drag: 'Docs.Create.Buxton()' }, + // { title: "use pen", icon: "pen-nib", click: 'activatePen(this.activePen.inkPen = sameDocs(this.activePen.inkPen, this) ? undefined : this,2, this.backgroundColor)', backgroundColor: "blue", ischecked: `sameDocs(this.activePen.inkPen, this)`, activePen: doc }, + // { title: "use highlighter", icon: "highlighter", click: 'activateBrush(this.activePen.inkPen = sameDocs(this.activePen.inkPen, this) ? undefined : this,20,this.backgroundColor)', backgroundColor: "yellow", ischecked: `sameDocs(this.activePen.inkPen, this)`, activePen: doc }, + // { title: "use stamp", icon: "stamp", click: 'activateStamp(this.activePen.inkPen = sameDocs(this.activePen.inkPen, this) ? undefined : this)', backgroundColor: "orange", ischecked: `sameDocs(this.activePen.inkPen, this)`, activePen: doc }, + // { title: "use eraser", icon: "eraser", click: 'activateEraser(this.activePen.inkPen = sameDocs(this.activePen.inkPen, this) ? undefined : this);', ischecked: `sameDocs(this.activePen.inkPen, this)`, backgroundColor: "pink", activePen: doc }, + // { title: "use drag", icon: "mouse-pointer", click: 'deactivateInk();this.activePen.inkPen = this;', ischecked: `sameDocs(this.activePen.inkPen, this)`, backgroundColor: "white", activePen: doc }, + { title: "Drag a document previewer", label: "Prev", icon: "expand", click: 'openOnRight(getCopy(this.dragFactory, true))', drag: 'getCopy(this.dragFactory,true)', dragFactory: doc.emptyDocHolder as Doc }, + { title: "Toggle a Calculator REPL", label: "repl", icon: "calculator", click: 'addOverlayWindow("ScriptingRepl", { x: 300, y: 100, width: 200, height: 200, title: "Scripting REPL" })' }, + { title: "Connect a Google Account", label: "Google Account", icon: "external-link-alt", click: 'GoogleAuthenticationManager.Instance.fetchOrGenerateAccessToken(true)' }, + ]; + + } + + // setup the "creator" buttons for the sidebar-- eg. the default set of draggable document creation tools + static async setupCreatorButtons(doc: Doc) { + let alreadyCreatedButtons: string[] = []; + const dragCreatorSet = await Cast(doc.myItemCreators, Doc, null); + if (dragCreatorSet) { + const dragCreators = await Cast(dragCreatorSet.data, listSpec(Doc)); + if (dragCreators) { + const dragDocs = await Promise.all(dragCreators); + alreadyCreatedButtons = dragDocs.map(d => StrCast(d.title)); + } + } + const buttons = CurrentUserUtils.creatorBtnDescriptors(doc).filter(d => !alreadyCreatedButtons?.includes(d.title)); + const creatorBtns = buttons.map(({ title, label, icon, ignoreClick, drag, click, ischecked, activePen, backgroundColor, dragFactory }) => Docs.Create.FontIconDocument({ + _nativeWidth: 100, _nativeHeight: 100, _width: 100, _height: 100, + icon, + title, + label, + ignoreClick, + dropAction: "copy", + onDragStart: drag ? ScriptField.MakeFunction(drag) : undefined, + onClick: click ? ScriptField.MakeScript(click) : undefined, + ischecked: ischecked ? ComputedField.MakeFunction(ischecked) : undefined, + activePen, + backgroundColor, + removeDropProperties: new List(["dropAction"]), + dragFactory, + })); + + if (dragCreatorSet === undefined) { + doc.myItemCreators = new PrefetchProxy(Docs.Create.MasonryDocument(creatorBtns, { + title: "Basic Item Creators", _showTitle: "title", _xMargin: 0, + _autoHeight: true, _width: 500, columnWidth: 35, ignoreClick: true, lockedPosition: true, _chromeStatus: "disabled", + dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }), + })); + } else { + creatorBtns.forEach(nb => Doc.AddDocToList(doc.myItemCreators as Doc, "data", nb)); + } + return doc.myItemCreators as Doc; + } + + static setupMobileButtons(doc: Doc, buttons?: string[]) { + const docProtoData: { title: string, icon: string, drag?: string, ignoreClick?: boolean, click?: string, ischecked?: string, activePen?: Doc, backgroundColor?: string, dragFactory?: Doc }[] = [ + { title: "record", icon: "microphone", ignoreClick: true, click: "FILL" }, + { title: "use pen", icon: "pen-nib", click: 'activatePen(this.activePen.inkPen = sameDocs(this.activePen.inkPen, this) ? undefined : this,2, this.backgroundColor)', backgroundColor: "blue", ischecked: `sameDocs(this.activePen.inkPen, this)`, activePen: doc }, + { title: "use highlighter", icon: "highlighter", click: 'activateBrush(this.activePen.inkPen = sameDocs(this.activePen.inkPen, this) ? undefined : this,20,this.backgroundColor)', backgroundColor: "yellow", ischecked: `sameDocs(this.activePen.inkPen, this)`, activePen: doc }, + { title: "use eraser", icon: "eraser", click: 'activateEraser(this.activePen.inkPen = sameDocs(this.activePen.inkPen, this) ? undefined : this);', ischecked: `sameDocs(this.activePen.inkPen, this)`, backgroundColor: "pink", activePen: doc }, + { title: "use drag", icon: "mouse-pointer", click: 'deactivateInk();this.activePen.inkPen = this;', ischecked: `sameDocs(this.activePen.inkPen, this)`, backgroundColor: "white", activePen: doc }, + // { title: "draw", icon: "pen-nib", click: 'switchMobileView(setupMobileInkingDoc, renderMobileInking, onSwitchMobileInking);', ischecked: `sameDocs(this.activePen.inkPen, this)`, backgroundColor: "red", activePen: doc }, + { title: "upload", icon: "upload", click: 'switchMobileView(setupMobileUploadDoc, renderMobileUpload, onSwitchMobileUpload);', backgroundColor: "orange" }, + // { title: "upload", icon: "upload", click: 'uploadImageMobile();', backgroundColor: "cyan" }, + ]; + return docProtoData.filter(d => !buttons || !buttons.includes(d.title)).map(data => Docs.Create.FontIconDocument({ + _nativeWidth: 100, _nativeHeight: 100, _width: 100, _height: 100, dropAction: data.click ? "copy" : undefined, title: data.title, icon: data.icon, ignoreClick: data.ignoreClick, + onDragStart: data.drag ? ScriptField.MakeFunction(data.drag) : undefined, onClick: data.click ? ScriptField.MakeScript(data.click) : undefined, + ischecked: data.ischecked ? ComputedField.MakeFunction(data.ischecked) : undefined, activePen: data.activePen, + backgroundColor: data.backgroundColor, removeDropProperties: new List(["dropAction"]), dragFactory: data.dragFactory, + })); + } + + static setupThumbButtons(doc: Doc) { + const docProtoData: { title: string, icon: string, drag?: string, ignoreClick?: boolean, pointerDown?: string, pointerUp?: string, ischecked?: string, clipboard?: Doc, activePen?: Doc, backgroundColor?: string, dragFactory?: Doc }[] = [ + { title: "use pen", icon: "pen-nib", pointerUp: "resetPen()", pointerDown: 'setPen(2, this.backgroundColor)', backgroundColor: "blue", ischecked: `sameDocs(this.activePen.inkPen, this)`, activePen: doc }, + { title: "use highlighter", icon: "highlighter", pointerUp: "resetPen()", pointerDown: 'setPen(20, this.backgroundColor)', backgroundColor: "yellow", ischecked: `sameDocs(this.activePen.inkPen, this)`, activePen: doc }, + { title: "notepad", icon: "clipboard", pointerUp: "GestureOverlay.Instance.closeFloatingDoc()", pointerDown: 'GestureOverlay.Instance.openFloatingDoc(this.clipboard)', clipboard: Docs.Create.FreeformDocument([], { _width: 300, _height: 300 }), backgroundColor: "orange", ischecked: `sameDocs(this.activePen.inkPen, this)`, activePen: doc }, + { title: "interpret text", icon: "font", pointerUp: "setToolglass('none')", pointerDown: "setToolglass('inktotext')", backgroundColor: "orange", ischecked: `sameDocs(this.activePen.inkPen, this)`, activePen: doc }, + { title: "ignore gestures", icon: "signature", pointerUp: "setToolglass('none')", pointerDown: "setToolglass('ignoregesture')", backgroundColor: "green", ischecked: `sameDocs(this.activePen.inkPen, this)`, activePen: doc }, + ]; + return docProtoData.map(data => Docs.Create.FontIconDocument({ + _nativeWidth: 10, _nativeHeight: 10, _width: 10, _height: 10, title: data.title, icon: data.icon, + dropAction: data.pointerDown ? "copy" : undefined, ignoreClick: data.ignoreClick, + onDragStart: data.drag ? ScriptField.MakeFunction(data.drag) : undefined, + clipboard: data.clipboard, + onPointerUp: data.pointerUp ? ScriptField.MakeScript(data.pointerUp) : undefined, onPointerDown: data.pointerDown ? ScriptField.MakeScript(data.pointerDown) : undefined, + ischecked: data.ischecked ? ComputedField.MakeFunction(data.ischecked) : undefined, activePen: data.activePen, pointerHack: true, + backgroundColor: data.backgroundColor, removeDropProperties: new List(["dropAction"]), dragFactory: data.dragFactory, + })); + } + + static setupThumbDoc(userDoc: Doc) { + if (!userDoc.thumbDoc) { + const thumbDoc = Docs.Create.LinearDocument(CurrentUserUtils.setupThumbButtons(userDoc), { + _width: 100, _height: 50, ignoreClick: true, lockedPosition: true, _chromeStatus: "disabled", title: "buttons", + _autoHeight: true, _yMargin: 5, linearViewIsExpanded: true, backgroundColor: "white" + }); + thumbDoc.inkToTextDoc = Docs.Create.LinearDocument([], { + _width: 300, _height: 25, _autoHeight: true, _chromeStatus: "disabled", linearViewIsExpanded: true, flexDirection: "column" + }); + userDoc.thumbDoc = thumbDoc; + } + return Cast(userDoc.thumbDoc, Doc); + } + + static setupMobileDoc(userDoc: Doc) { + return userDoc.activeMoble ?? Docs.Create.MasonryDocument(CurrentUserUtils.setupMobileButtons(userDoc), { + columnWidth: 100, ignoreClick: true, lockedPosition: true, _chromeStatus: "disabled", title: "buttons", _autoHeight: true, _yMargin: 5 + }); + } + + static setupMobileInkingDoc(userDoc: Doc) { + return Docs.Create.FreeformDocument([], { title: "Mobile Inking", backgroundColor: "white" }); + } + + static setupMobileUploadDoc(userDoc: Doc) { + // const addButton = Docs.Create.FontIconDocument({ onDragStart: ScriptField.MakeScript('addWebToMobileUpload()'), title: "Add Web Doc to Upload Collection", icon: "plus", backgroundColor: "black" }) + const webDoc = Docs.Create.WebDocument("https://www.britannica.com/biography/Miles-Davis", { + title: "Upload Images From the Web", _chromeStatus: "enabled", lockedPosition: true + }); + const uploadDoc = Docs.Create.StackingDocument([], { + title: "Mobile Upload Collection", backgroundColor: "white", lockedPosition: true + }); + return Docs.Create.StackingDocument([webDoc, uploadDoc], { + _width: screen.width, lockedPosition: true, _chromeStatus: "disabled", title: "Upload", _autoHeight: true, _yMargin: 80, backgroundColor: "lightgray" + }); + } + + // setup the Creator button which will display the creator panel. This panel will include the drag creators and the color picker. + // when clicked, this panel will be displayed in the target container (ie, sidebarContainer) + static async setupToolsBtnPanel(doc: Doc, sidebarContainer: Doc) { + // setup a masonry view of all he creators + const creatorBtns = await CurrentUserUtils.setupCreatorButtons(doc); + const templateBtns = CurrentUserUtils.setupUserTemplateButtons(doc); + + if (doc.myCreators === undefined) { + doc.myCreators = new PrefetchProxy(Docs.Create.StackingDocument([creatorBtns, templateBtns], { + title: "all Creators", _yMargin: 0, _autoHeight: true, _xMargin: 0, + _width: 500, ignoreClick: true, lockedPosition: true, _chromeStatus: "disabled", + })); + } + // setup a color picker + if (doc.myColorPicker === undefined) { + const color = Docs.Create.ColorDocument({ + title: "color picker", _width: 300, dropAction: "alias", forceActive: true, removeDropProperties: new List(["dropAction", "forceActive"]) + }); + doc.myColorPicker = new PrefetchProxy(color); + } + + if (doc["tabs-button-tools"] === undefined) { + doc["tabs-button-tools"] = new PrefetchProxy(Docs.Create.ButtonDocument({ + _width: 35, _height: 25, title: "Tools", _fontSize: 10, + letterSpacing: "0px", textTransform: "unset", borderRounding: "5px 5px 0px 0px", boxShadow: "3px 3px 0px rgb(34, 34, 34)", + sourcePanel: new PrefetchProxy(Docs.Create.StackingDocument([doc.myCreators as Doc, doc.myColorPicker as Doc], { + _width: 500, lockedPosition: true, _chromeStatus: "disabled", title: "tools stack", forceActive: true + })) as any as Doc, + targetContainer: new PrefetchProxy(sidebarContainer) as any as Doc, + onClick: ScriptField.MakeScript("this.targetContainer.proto = this.sourcePanel"), + })); + } + (doc["tabs-button-tools"] as Doc).sourcePanel; // prefetch sourcePanel + return doc["tabs-button-tools"] as Doc; + } + + static setupWorkspaces(doc: Doc) { + // setup workspaces library item + if (doc.myWorkspaces === undefined) { + doc.myWorkspaces = new PrefetchProxy(Docs.Create.TreeDocument([], { + title: "WORKSPACES", _height: 100, forceActive: true, boxShadow: "0 0", lockedPosition: true, + })); + } + const newWorkspace = ScriptField.MakeScript(`createNewWorkspace()`); + (doc.myWorkspaces as Doc).contextMenuScripts = new List([newWorkspace!]); + (doc.myWorkspaces as Doc).contextMenuLabels = new List(["Create New Workspace"]); + + return doc.myWorkspaces as Doc; + } + static setupCatalog(doc: Doc) { + if (doc.myCatalog === undefined) { + doc.myCatalog = new PrefetchProxy(Docs.Create.TreeDocument([], { + title: "CATALOG", _height: 42, forceActive: true, boxShadow: "0 0", treeViewPreventOpen: false, lockedPosition: true, + })); + } + return doc.myCatalog as Doc; + } + static setupRecentlyClosed(doc: Doc) { + // setup Recently Closed library item + if (doc.myRecentlyClosed === undefined) { + doc.myRecentlyClosed = new PrefetchProxy(Docs.Create.TreeDocument([], { + title: "RECENTLY CLOSED", _height: 75, forceActive: true, boxShadow: "0 0", treeViewPreventOpen: true, lockedPosition: true, + })); + } + // this is equivalent to using PrefetchProxies to make sure the recentlyClosed doc is ready + PromiseValue(Cast(doc.myRecentlyClosed, Doc)).then(recent => recent && PromiseValue(recent.data).then(DocListCast)); + const clearAll = ScriptField.MakeScript(`self.data = new List([])`); + (doc.myRecentlyClosed as Doc).contextMenuScripts = new List([clearAll!]); + (doc.myRecentlyClosed as Doc).contextMenuLabels = new List(["Clear All"]); + + return doc.myRecentlyClosed as Doc; + } + // setup the Library button which will display the library panel. This panel includes a collection of workspaces, documents, and recently closed views + static setupLibraryPanel(doc: Doc, sidebarContainer: Doc) { + const workspaces = CurrentUserUtils.setupWorkspaces(doc); + const documents = CurrentUserUtils.setupCatalog(doc); + const recentlyClosed = CurrentUserUtils.setupRecentlyClosed(doc); + + if (doc["tabs-button-library"] === undefined) { + doc["tabs-button-library"] = new PrefetchProxy(Docs.Create.ButtonDocument({ + _width: 50, _height: 25, title: "Library", _fontSize: 10, + letterSpacing: "0px", textTransform: "unset", borderRounding: "5px 5px 0px 0px", boxShadow: "3px 3px 0px rgb(34, 34, 34)", + sourcePanel: new PrefetchProxy(Docs.Create.TreeDocument([workspaces, documents, recentlyClosed, doc], { + title: "Library", _xMargin: 5, _yMargin: 5, _gridGap: 5, forceActive: true, childDropAction: "alias", lockedPosition: true, boxShadow: "0 0", dontRegisterChildViews: true + })) as any as Doc, + targetContainer: new PrefetchProxy(sidebarContainer) as any as Doc, + onClick: ScriptField.MakeScript("this.targetContainer.proto = this.sourcePanel;") + })); + } + return doc["tabs-button-library"] as Doc; + } + + // setup the Search button which will display the search panel. + static setupSearchBtnPanel(doc: Doc, sidebarContainer: Doc) { + if (doc["tabs-button-search"] === undefined) { + doc["tabs-button-search"] = new PrefetchProxy(Docs.Create.ButtonDocument({ + _width: 50, _height: 25, title: "Search", _fontSize: 10, + letterSpacing: "0px", textTransform: "unset", borderRounding: "5px 5px 0px 0px", boxShadow: "3px 3px 0px rgb(34, 34, 34)", + sourcePanel: new PrefetchProxy(Docs.Create.QueryDocument({ title: "search stack", })) as any as Doc, + searchFileTypes: new List([DocumentType.RTF, DocumentType.IMG, DocumentType.PDF, DocumentType.VID, DocumentType.WEB, DocumentType.SCRIPTING]), + targetContainer: new PrefetchProxy(sidebarContainer) as any as Doc, + lockedPosition: true, + onClick: ScriptField.MakeScript("this.targetContainer.proto = this.sourcePanel") + })); + } + return doc["tabs-button-search"] as Doc; + } + + static setupSidebarContainer(doc: Doc) { + if (doc["tabs-panelContainer"] === undefined) { + const sidebarContainer = new Doc(); + sidebarContainer._chromeStatus = "disabled"; + sidebarContainer.onClick = ScriptField.MakeScript("freezeSidebar()"); + doc["tabs-panelContainer"] = new PrefetchProxy(sidebarContainer); + } + return doc["tabs-panelContainer"] as Doc; + } + + // setup the list of sidebar mode buttons which determine what is displayed in the sidebar + static async setupSidebarButtons(doc: Doc) { + const sidebarContainer = CurrentUserUtils.setupSidebarContainer(doc); + const toolsBtn = await CurrentUserUtils.setupToolsBtnPanel(doc, sidebarContainer); + const libraryBtn = CurrentUserUtils.setupLibraryPanel(doc, sidebarContainer); + const searchBtn = CurrentUserUtils.setupSearchBtnPanel(doc, sidebarContainer); + + // Finally, setup the list of buttons to display in the sidebar + if (doc["tabs-buttons"] === undefined) { + doc["tabs-buttons"] = new PrefetchProxy(Docs.Create.StackingDocument([searchBtn, libraryBtn, toolsBtn], { + _width: 500, _height: 80, boxShadow: "0 0", _pivotField: "title", hideHeadings: true, ignoreClick: true, _chromeStatus: "view-mode", + title: "sidebar btn row stack", backgroundColor: "dimGray", + })); + (toolsBtn.onClick as ScriptField).script.run({ this: toolsBtn }); + } + } + + static blist = (opts: DocumentOptions, docs: Doc[]) => new PrefetchProxy(Docs.Create.LinearDocument(docs, { + ...opts, + _gridGap: 5, _xMargin: 5, _yMargin: 5, _height: 42, _width: 100, boxShadow: "0 0", forceActive: true, + dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }), + backgroundColor: "black", treeViewPreventOpen: true, lockedPosition: true, _chromeStatus: "disabled", linearViewIsExpanded: true + })) as any as Doc + + static ficon = (opts: DocumentOptions) => new PrefetchProxy(Docs.Create.FontIconDocument({ + ...opts, + dropAction: "alias", removeDropProperties: new List(["dropAction"]), _nativeWidth: 100, _nativeHeight: 100, _width: 100, _height: 100 + })) as any as Doc + + /// sets up the default list of buttons to be shown in the expanding button menu at the bottom of the Dash window + static setupDockedButtons(doc: Doc) { + if (doc["dockedBtn-pen"] === undefined) { + doc["dockedBtn-pen"] = CurrentUserUtils.ficon({ + onClick: ScriptField.MakeScript("activatePen(this.activePen.inkPen = sameDocs(this.activePen.inkPen, this) ? undefined : this,2, this.backgroundColor)"), + author: "systemTemplates", title: "ink mode", icon: "pen-nib", ischecked: ComputedField.MakeFunction(`sameDocs(this.activePen.inkPen, this)`), activePen: doc + }); + } + if (doc["dockedBtn-undo"] === undefined) { + doc["dockedBtn-undo"] = CurrentUserUtils.ficon({ onClick: ScriptField.MakeScript("undo()"), title: "undo button", icon: "undo-alt" }); + } + if (doc["dockedBtn-redo"] === undefined) { + doc["dockedBtn-redo"] = CurrentUserUtils.ficon({ onClick: ScriptField.MakeScript("redo()"), title: "redo button", icon: "redo-alt" }); + } + if (doc.dockedBtns === undefined) { + doc.dockedBtns = CurrentUserUtils.blist({ title: "docked buttons", ignoreClick: true }, [doc["dockedBtn-undo"] as Doc, doc["dockedBtn-redo"] as Doc, doc["dockedBtn-pen"] as Doc]); + } + } + // sets up the default set of documents to be shown in the Overlay layer + static setupOverlays(doc: Doc) { + if (doc.myOverlayDocuments === undefined) { + doc.myOverlayDocuments = new PrefetchProxy(Docs.Create.FreeformDocument([], { title: "overlay documents", backgroundColor: "#aca3a6" })); + } + } + + // the initial presentation Doc to use + static setupDefaultPresentation(doc: Doc) { + if (doc.activePresentation === undefined) { + doc.activePresentation = Docs.Create.PresDocument(new List(), { + title: "Presentation", _viewType: CollectionViewType.Stacking, targetDropAction: "alias", + _LODdisable: true, _chromeStatus: "replaced", _showTitle: "title", boxShadow: "0 0" + }); + } + } + + static setupRightSidebar(doc: Doc) { + if (doc.rightSidebarCollection === undefined) { + doc.rightSidebarCollection = new PrefetchProxy(Docs.Create.StackingDocument([], { title: "Right Sidebar" })); + } + } + + static setupClickEditorTemplates(doc: Doc) { + if (doc["clickFuncs-child"] === undefined) { + const openInTarget = Docs.Create.ScriptingDocument(ScriptField.MakeScript( + "docCast(thisContainer.target).then((target) => {" + + " target && docCast(this.source).then((source) => { " + + " target.proto.data = new List([source || this]); " + + " }); " + + "})", + { target: Doc.name }), { title: "Click to open in target", _width: 300, _height: 200, targetScriptKey: "onChildClick" }); + + const openDetail = Docs.Create.ScriptingDocument(ScriptField.MakeScript( + "openOnRight(self.doubleClickView)", + { target: Doc.name }), { title: "Double click to open doubleClickView", _width: 300, _height: 200, targetScriptKey: "onChildDoubleClick" }); + + doc["clickFuncs-child"] = Docs.Create.TreeDocument([openInTarget, openDetail], { title: "on Child Click function templates" }); + } + // this is equivalent to using PrefetchProxies to make sure all the childClickFuncs have been retrieved. + PromiseValue(Cast(doc["clickFuncs-child"], Doc)).then(func => func && PromiseValue(func.data).then(DocListCast)); + + if (doc.clickFuncs === undefined) { + const onClick = Docs.Create.ScriptingDocument(undefined, { + title: "onClick", "onClick-rawScript": "console.log('click')", + isTemplateDoc: true, isTemplateForField: "onClick", _width: 300, _height: 200 + }, "onClick"); + const onDoubleClick = Docs.Create.ScriptingDocument(undefined, { + title: "onDoubleClick", "onDoubleClick-rawScript": "console.log('double click')", + isTemplateDoc: true, isTemplateForField: "onDoubleClick", _width: 300, _height: 200 + }, "onDoubleClick"); + const onCheckedClick = Docs.Create.ScriptingDocument(undefined, { + title: "onCheckedClick", "onCheckedClick-rawScript": "console.log(heading + checked + containingTreeView)", "onCheckedClick-params": new List(["heading", "checked", "containingTreeView"]), isTemplateDoc: true, isTemplateForField: "onCheckedClick", _width: 300, _height: 200 + }, "onCheckedClick"); + doc.clickFuncs = Docs.Create.TreeDocument([onClick, onDoubleClick, onCheckedClick], { title: "onClick funcs" }); + } + PromiseValue(Cast(doc.clickFuncs, Doc)).then(func => func && PromiseValue(func.data).then(DocListCast)); + + return doc.clickFuncs as Doc; + } + + static async updateUserDocument(doc: Doc) { + new InkingControl(); + doc.title = Doc.CurrentUserEmail; + doc.activePen = doc; + doc.inkColor = StrCast(doc.backgroundColor, ""); + doc.fontSize = NumCast(doc.fontSize, 12); + doc["constants-snapThreshold"] = NumCast(doc["constants-snapThreshold"], 10); // + doc["constants-dragThreshold"] = NumCast(doc["constants-dragThreshold"], 4); // + Utils.DRAG_THRESHOLD = NumCast(doc["constants-dragThreshold"]); + this.setupDefaultIconTemplates(doc); // creates a set of icon templates triggered by the document deoration icon + this.setupDocTemplates(doc); // sets up the template menu of templates + this.setupRightSidebar(doc); // sets up the right sidebar collection for mobile upload documents and sharing + this.setupOverlays(doc); // documents in overlay layer + this.setupDockedButtons(doc); // the bottom bar of font icons + this.setupDefaultPresentation(doc); // presentation that's initially triggered + await this.setupSidebarButtons(doc); // the pop-out left sidebar of tools/panels + doc.globalLinkDatabase = Docs.Prototypes.MainLinkDocument(); + + // setup reactions to change the highlights on the undo/redo buttons -- would be better to encode this in the undo/redo buttons, but the undo/redo stacks are not wired up that way yet + doc["dockedBtn-undo"] && reaction(() => UndoManager.undoStack.slice(), () => Doc.GetProto(doc["dockedBtn-undo"] as Doc).opacity = UndoManager.CanUndo() ? 1 : 0.4, { fireImmediately: true }); + doc["dockedBtn-redo"] && reaction(() => UndoManager.redoStack.slice(), () => Doc.GetProto(doc["dockedBtn-redo"] as Doc).opacity = UndoManager.CanRedo() ? 1 : 0.4, { fireImmediately: true }); + + return doc; + } + public static async loadCurrentUser() { + return rp.get(Utils.prepend("/getCurrentUser")).then(response => { + if (response) { + const result: { id: string, email: string } = JSON.parse(response); + return result; + } else { + throw new Error("There should be a user! Why does Dash think there isn't one?"); + } + }); + } + + public static async loadUserDocument({ id, email }: { id: string, email: string }) { + this.curr_id = id; + Doc.CurrentUserEmail = email; + await rp.get(Utils.prepend("/getUserDocumentId")).then(id => { + if (id && id !== "guest") { + return DocServer.GetRefField(id).then(async field => + Doc.SetUserDoc(await this.updateUserDocument(field instanceof Doc ? field : new Doc(id, true)))); + } else { + throw new Error("There should be a user id! Why does Dash think there isn't one?"); + } + }); + } +} + +Scripting.addGlobal(function setupMobileInkingDoc(userDoc: Doc) { return CurrentUserUtils.setupMobileInkingDoc(userDoc); }); +Scripting.addGlobal(function setupMobileUploadDoc(userDoc: Doc) { return CurrentUserUtils.setupMobileUploadDoc(userDoc); }); +Scripting.addGlobal(function createNewWorkspace() { return MainView.Instance.createNewWorkspace(); }); \ No newline at end of file diff --git a/src/client/util/SettingsManager.tsx b/src/client/util/SettingsManager.tsx index e20434461..0e15197c4 100644 --- a/src/client/util/SettingsManager.tsx +++ b/src/client/util/SettingsManager.tsx @@ -8,7 +8,7 @@ import { SelectionManager } from "./SelectionManager"; import "./SettingsManager.scss"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { Networking } from "../Network"; -import { CurrentUserUtils } from "../../server/authentication/models/current_user_utils"; +import { CurrentUserUtils } from "./CurrentUserUtils"; import { Utils } from "../../Utils"; library.add(fa.faWindowClose); diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx index 4f8f9ed69..812ff3b93 100644 --- a/src/client/views/GestureOverlay.tsx +++ b/src/client/views/GestureOverlay.tsx @@ -13,7 +13,7 @@ import { DocUtils, Docs } from "../documents/Documents"; import { undoBatch } from "../util/UndoManager"; import { Scripting } from "../util/Scripting"; import { FieldValue, Cast, NumCast, BoolCast } from "../../new_fields/Types"; -import { CurrentUserUtils } from "../../server/authentication/models/current_user_utils"; +import { CurrentUserUtils } from "../util/CurrentUserUtils"; import HorizontalPalette from "./Palette"; import { Utils, emptyPath, emptyFunction, returnFalse, returnOne, returnEmptyString, returnTrue, numberRange, returnZero } from "../../Utils"; import { DocumentView } from "./nodes/DocumentView"; diff --git a/src/client/views/InkingControl.tsx b/src/client/views/InkingControl.tsx index 81d99e009..af9c4a562 100644 --- a/src/client/views/InkingControl.tsx +++ b/src/client/views/InkingControl.tsx @@ -3,7 +3,7 @@ import { ColorState } from 'react-color'; import { Doc } from "../../new_fields/Doc"; import { InkTool } from "../../new_fields/InkField"; import { FieldValue, NumCast, StrCast } from "../../new_fields/Types"; -import { CurrentUserUtils } from "../../server/authentication/models/current_user_utils"; +import { CurrentUserUtils } from "../util/CurrentUserUtils"; import { Scripting } from "../util/Scripting"; import { SelectionManager } from "../util/SelectionManager"; import { undoBatch } from "../util/UndoManager"; diff --git a/src/client/views/Main.tsx b/src/client/views/Main.tsx index b21eb9c8f..17c001971 100644 --- a/src/client/views/Main.tsx +++ b/src/client/views/Main.tsx @@ -1,6 +1,6 @@ import { MainView } from "./MainView"; import { Docs } from "../documents/Documents"; -import { CurrentUserUtils } from "../../server/authentication/models/current_user_utils"; +import { CurrentUserUtils } from "../util/CurrentUserUtils"; import * as ReactDOM from 'react-dom'; import * as React from 'react'; import { DocServer } from "../DocServer"; diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 9bfef06b4..9bc08de3e 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -19,7 +19,7 @@ import { List } from '../../new_fields/List'; import { listSpec } from '../../new_fields/Schema'; import { BoolCast, Cast, FieldValue, StrCast } from '../../new_fields/Types'; import { TraceMobx } from '../../new_fields/util'; -import { CurrentUserUtils } from '../../server/authentication/models/current_user_utils'; +import { CurrentUserUtils } from '../util/CurrentUserUtils'; import { emptyFunction, emptyPath, returnFalse, returnOne, returnZero, returnTrue, Utils } from '../../Utils'; import GoogleAuthenticationManager from '../apis/GoogleAuthenticationManager'; import { DocServer } from '../DocServer'; diff --git a/src/client/views/collections/CollectionMapView.tsx b/src/client/views/collections/CollectionMapView.tsx index 13c06b0a3..618285293 100644 --- a/src/client/views/collections/CollectionMapView.tsx +++ b/src/client/views/collections/CollectionMapView.tsx @@ -1,4 +1,4 @@ -import { GoogleApiWrapper, Map as GeoMap, IMapProps, Marker } from "google-maps-react"; +import { GoogleApiWrapper, Map as GeoMap, MapProps as IMapProps, Marker } from "google-maps-react"; import { observer } from "mobx-react"; import { Doc, Opt, DocListCast, FieldResult, Field } from "../../../new_fields/Doc"; import { documentSchema } from "../../../new_fields/documentSchemas"; @@ -47,7 +47,7 @@ class CollectionMapView extends CollectionSubView private _cancelAddrReq = new Map(); private _cancelLocReq = new Map(); private _initialLookupPending = new Map(); - private responders: { location: Lambda, address: Lambda }[] = []; + private responders: { locationDisposer: Lambda, addressDisposer: Lambda }[] = []; /** * Note that all the uses of runInAction below are not included @@ -176,13 +176,16 @@ class CollectionMapView extends CollectionSubView } @computed get reactiveContents() { - this.responders.forEach(({ location, address }) => { location(); address(); }); + this.responders.forEach(({ locationDisposer, addressDisposer }) => { + locationDisposer(); + addressDisposer(); + }); this.responders = []; return this.childLayoutPairs.map(({ layout }) => { const fieldKey = Doc.LayoutFieldKey(layout); const id = layout[Id]; this.responders.push({ - location: computed(() => ({ lat: layout[`${fieldKey}-lat`], lng: layout[`${fieldKey}-lng`] })) + locationDisposer: computed(() => ({ lat: layout[`${fieldKey}-lat`], lng: layout[`${fieldKey}-lng`] })) .observe(({ oldValue, newValue }) => { if (this._cancelLocReq.get(id)) { this._cancelLocReq.set(id, false); @@ -190,7 +193,7 @@ class CollectionMapView extends CollectionSubView this.respondToLocationChange(layout, fieldKey, newValue, oldValue); } }), - address: computed(() => Cast(layout[`${fieldKey}-address`], "string", null)) + addressDisposer: computed(() => Cast(layout[`${fieldKey}-address`], "string", null)) .observe(({ oldValue, newValue }) => { if (this._cancelAddrReq.get(id)) { this._cancelAddrReq.set(id, false); diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 8b50bd8fc..bff6d121b 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -8,7 +8,7 @@ import { listSpec } from "../../../new_fields/Schema"; import { ScriptField } from "../../../new_fields/ScriptField"; import { Cast, ScriptCast } from "../../../new_fields/Types"; import { GestureUtils } from "../../../pen-gestures/GestureUtils"; -import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils"; +import { CurrentUserUtils } from "../../util/CurrentUserUtils"; import { Upload } from "../../../server/SharedMediaTypes"; import { Utils } from "../../../Utils"; import { GooglePhotos } from "../../apis/google_docs/GooglePhotosClientUtils"; diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 0f239d385..4b3b2e234 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -35,7 +35,7 @@ import { CollectionTimeView } from './CollectionTimeView'; import { CollectionTreeView } from "./CollectionTreeView"; import './CollectionView.scss'; import { CollectionViewBaseChrome } from './CollectionViewChromes'; -import { CurrentUserUtils } from '../../../server/authentication/models/current_user_utils'; +import { CurrentUserUtils } from '../../util/CurrentUserUtils'; import { Id } from '../../../new_fields/FieldSymbols'; import { listSpec } from '../../../new_fields/Schema'; import { Docs } from '../../documents/Documents'; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx index 92fa2781c..9a5b2c27c 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx @@ -3,7 +3,7 @@ import * as mobxUtils from 'mobx-utils'; import CursorField from "../../../../new_fields/CursorField"; import { listSpec } from "../../../../new_fields/Schema"; import { Cast } from "../../../../new_fields/Types"; -import { CurrentUserUtils } from "../../../../server/authentication/models/current_user_utils"; +import { CurrentUserUtils } from "../../../util/CurrentUserUtils"; import { CollectionViewProps } from "../CollectionSubView"; import "./CollectionFreeFormView.scss"; import React = require("react"); diff --git a/src/client/views/nodes/ColorBox.tsx b/src/client/views/nodes/ColorBox.tsx index 7ab6d99c2..bc84204b9 100644 --- a/src/client/views/nodes/ColorBox.tsx +++ b/src/client/views/nodes/ColorBox.tsx @@ -4,7 +4,7 @@ import { SketchPicker } from 'react-color'; import { documentSchema } from "../../../new_fields/documentSchemas"; import { makeInterface } from "../../../new_fields/Schema"; import { StrCast } from "../../../new_fields/Types"; -import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils"; +import { CurrentUserUtils } from "../../util/CurrentUserUtils"; import { SelectionManager } from "../../util/SelectionManager"; import { ViewBoxBaseComponent } from "../DocComponent"; import { InkingControl } from "../InkingControl"; diff --git a/src/mobile/ImageUpload.tsx b/src/mobile/ImageUpload.tsx index 295e82142..f30e9869a 100644 --- a/src/mobile/ImageUpload.tsx +++ b/src/mobile/ImageUpload.tsx @@ -12,8 +12,7 @@ import { observer } from 'mobx-react'; import { observable } from 'mobx'; import { Utils } from '../Utils'; import MobileInterface from './MobileInterface'; -import { CurrentUserUtils } from '../server/authentication/models/current_user_utils'; -import { Scripting } from '../client/util/Scripting'; +import { CurrentUserUtils } from '../client/util/CurrentUserUtils'; diff --git a/src/mobile/MobileInterface.tsx b/src/mobile/MobileInterface.tsx index 69a80e1b4..9d4d58ad1 100644 --- a/src/mobile/MobileInterface.tsx +++ b/src/mobile/MobileInterface.tsx @@ -10,7 +10,6 @@ import { DocumentManager } from '../client/util/DocumentManager'; import RichTextMenu from '../client/views/nodes/formattedText/RichTextMenu'; import { Scripting } from '../client/util/Scripting'; import { Transform } from '../client/util/Transform'; -import { CollectionView } from '../client/views/collections/CollectionView'; import { DocumentDecorations } from '../client/views/DocumentDecorations'; import GestureOverlay from '../client/views/GestureOverlay'; import { InkingControl } from '../client/views/InkingControl'; @@ -23,9 +22,10 @@ import { InkTool } from '../new_fields/InkField'; import { listSpec } from '../new_fields/Schema'; import { Cast, FieldValue } from '../new_fields/Types'; import { WebField } from "../new_fields/URLField"; -import { CurrentUserUtils } from '../server/authentication/models/current_user_utils'; +import { CurrentUserUtils } from '../client/util/CurrentUserUtils'; import { emptyFunction, emptyPath, returnEmptyString, returnFalse, returnOne, returnTrue, returnZero } from '../Utils'; import "./MobileInterface.scss"; +import { CollectionView } from '../client/views/collections/CollectionView'; library.add(faLongArrowAltLeft); diff --git a/src/server/ApiManagers/ApiManager.ts b/src/server/ApiManagers/ApiManager.ts index e2b01d585..27e9de065 100644 --- a/src/server/ApiManagers/ApiManager.ts +++ b/src/server/ApiManagers/ApiManager.ts @@ -1,4 +1,4 @@ -import RouteManager, { RouteInitializer } from "../RouteManager"; +import { RouteInitializer } from "../RouteManager"; export type Registration = (initializer: RouteInitializer) => void; diff --git a/src/server/ApiManagers/DeleteManager.ts b/src/server/ApiManagers/DeleteManager.ts index bd80d6500..7fbb37658 100644 --- a/src/server/ApiManagers/DeleteManager.ts +++ b/src/server/ApiManagers/DeleteManager.ts @@ -1,6 +1,6 @@ import ApiManager, { Registration } from "./ApiManager"; import { Method, _permission_denied } from "../RouteManager"; -import { WebSocket } from "../Websocket/Websocket"; +import { WebSocket } from "../websocket"; import { Database } from "../database"; import rimraf = require("rimraf"); import { filesDirectory } from ".."; diff --git a/src/server/ApiManagers/GeneralGoogleManager.ts b/src/server/ApiManagers/GeneralGoogleManager.ts index 17968cc7d..f94b77cac 100644 --- a/src/server/ApiManagers/GeneralGoogleManager.ts +++ b/src/server/ApiManagers/GeneralGoogleManager.ts @@ -38,7 +38,7 @@ export default class GeneralGoogleManager extends ApiManager { method: Method.GET, subscription: "/revokeGoogleAccessToken", secureHandler: async ({ user, res }) => { - await Database.Auxiliary.GoogleAuthenticationToken.Revoke(user.id); + await Database.Auxiliary.GoogleAccessToken.Revoke(user.id); res.send(); } }); diff --git a/src/server/DashSession/DashSessionAgent.ts b/src/server/DashSession/DashSessionAgent.ts index ef9b88541..ab3dfffcc 100644 --- a/src/server/DashSession/DashSessionAgent.ts +++ b/src/server/DashSession/DashSessionAgent.ts @@ -2,7 +2,7 @@ import { Email, pathFromRoot } from "../ActionUtilities"; import { red, yellow, green, cyan } from "colors"; import { get } from "request-promise"; import { Utils } from "../../Utils"; -import { WebSocket } from "../Websocket/Websocket"; +import { WebSocket } from "../websocket"; import { MessageStore } from "../Message"; import { launchServer, onWindows } from ".."; import { readdirSync, statSync, createWriteStream, readFileSync, unlinkSync } from "fs"; diff --git a/src/server/RouteManager.ts b/src/server/RouteManager.ts index 80e4a6741..b23215996 100644 --- a/src/server/RouteManager.ts +++ b/src/server/RouteManager.ts @@ -1,5 +1,5 @@ import RouteSubscriber from "./RouteSubscriber"; -import { DashUserModel } from "./authentication/models/user_model"; +import { DashUserModel } from "./authentication/DashUserModel"; import { Request, Response, Express } from 'express'; import { cyan, red, green } from 'colors'; diff --git a/src/server/Websocket/Websocket.ts b/src/server/Websocket/Websocket.ts deleted file mode 100644 index 844535056..000000000 --- a/src/server/Websocket/Websocket.ts +++ /dev/null @@ -1,305 +0,0 @@ -import { Utils } from "../../Utils"; -import { MessageStore, Transferable, Types, Diff, YoutubeQueryInput, YoutubeQueryTypes, GestureContent, MobileInkOverlayContent, UpdateMobileInkOverlayPositionContent, MobileDocumentUploadContent, RoomMessage } from "../Message"; -import { Client } from "../Client"; -import { Socket } from "socket.io"; -import { Database } from "../database"; -import { Search } from "../Search"; -import * as io from 'socket.io'; -import YoutubeApi from "../apis/youtube/youtubeApiSample"; -import { GoogleCredentialsLoader } from "../credentials/CredentialsLoader"; -import { logPort } from "../ActionUtilities"; -import { timeMap } from "../ApiManagers/UserManager"; -import { green } from "colors"; -import { networkInterfaces } from "os"; -import executeImport from "../../scraping/buxton/final/BuxtonImporter"; -import { DocumentsCollection } from "../IDatabase"; - -export namespace WebSocket { - - export let _socket: Socket; - const clients: { [key: string]: Client } = {}; - export const socketMap = new Map(); - export let disconnect: Function; - - - export async function start(isRelease: boolean) { - await preliminaryFunctions(); - initialize(isRelease); - } - - async function preliminaryFunctions() { - } - function initialize(isRelease: boolean) { - const endpoint = io(); - endpoint.on("connection", function (socket: Socket) { - _socket = socket; - - socket.use((_packet, next) => { - const userEmail = socketMap.get(socket); - if (userEmail) { - timeMap[userEmail] = Date.now(); - } - next(); - }); - - // convenience function to log server messages on the client - function log(message?: any, ...optionalParams: any[]) { - socket.emit('log', ['Message from server:', message, ...optionalParams]); - } - - socket.on('message', function (message, room) { - console.log('Client said: ', message); - socket.in(room).emit('message', message); - }); - - socket.on('create or join', function (room) { - console.log('Received request to create or join room ' + room); - - const clientsInRoom = socket.adapter.rooms[room]; - const numClients = clientsInRoom ? Object.keys(clientsInRoom.sockets).length : 0; - console.log('Room ' + room + ' now has ' + numClients + ' client(s)'); - - if (numClients === 0) { - socket.join(room); - console.log('Client ID ' + socket.id + ' created room ' + room); - socket.emit('created', room, socket.id); - - } else if (numClients === 1) { - console.log('Client ID ' + socket.id + ' joined room ' + room); - socket.in(room).emit('join', room); - socket.join(room); - socket.emit('joined', room, socket.id); - socket.in(room).emit('ready'); - } else { // max two clients - socket.emit('full', room); - } - }); - - socket.on('ipaddr', function () { - const ifaces = networkInterfaces(); - for (const dev in ifaces) { - ifaces[dev].forEach(function (details) { - if (details.family === 'IPv4' && details.address !== '127.0.0.1') { - socket.emit('ipaddr', details.address); - } - }); - } - }); - - socket.on('bye', function () { - console.log('received bye'); - }); - - Utils.Emit(socket, MessageStore.Foo, "handshooken"); - - Utils.AddServerHandler(socket, MessageStore.Bar, guid => barReceived(socket, guid)); - Utils.AddServerHandler(socket, MessageStore.SetField, (args) => setField(socket, args)); - Utils.AddServerHandlerCallback(socket, MessageStore.GetField, getField); - Utils.AddServerHandlerCallback(socket, MessageStore.GetFields, getFields); - if (isRelease) { - Utils.AddServerHandler(socket, MessageStore.DeleteAll, () => doDelete(false)); - } - - Utils.AddServerHandler(socket, MessageStore.CreateField, CreateField); - Utils.AddServerHandlerCallback(socket, MessageStore.YoutubeApiQuery, HandleYoutubeQuery); - Utils.AddServerHandler(socket, MessageStore.UpdateField, diff => UpdateField(socket, diff)); - Utils.AddServerHandler(socket, MessageStore.DeleteField, id => DeleteField(socket, id)); - Utils.AddServerHandler(socket, MessageStore.DeleteFields, ids => DeleteFields(socket, ids)); - Utils.AddServerHandler(socket, MessageStore.GesturePoints, content => processGesturePoints(socket, content)); - Utils.AddServerHandler(socket, MessageStore.MobileInkOverlayTrigger, content => processOverlayTrigger(socket, content)); - Utils.AddServerHandler(socket, MessageStore.UpdateMobileInkOverlayPosition, content => processUpdateOverlayPosition(socket, content)); - Utils.AddServerHandler(socket, MessageStore.MobileDocumentUpload, content => processMobileDocumentUpload(socket, content)); - Utils.AddServerHandlerCallback(socket, MessageStore.GetRefField, GetRefField); - Utils.AddServerHandlerCallback(socket, MessageStore.GetRefFields, GetRefFields); - - /** - * Whenever we receive the go-ahead, invoke the import script and pass in - * as an emitter and a terminator the functions that simply broadcast a result - * or indicate termination to the client via the web socket - */ - Utils.AddServerHandler(socket, MessageStore.BeginBuxtonImport, () => { - executeImport( - deviceOrError => Utils.Emit(socket, MessageStore.BuxtonDocumentResult, deviceOrError), - results => Utils.Emit(socket, MessageStore.BuxtonImportComplete, results) - ); - }); - - disconnect = () => { - socket.broadcast.emit("connection_terminated", Date.now()); - socket.disconnect(true); - }; - }); - - const socketPort = isRelease ? Number(process.env.socketPort) : 4321; - endpoint.listen(socketPort); - logPort("websocket", socketPort); - } - - function processGesturePoints(socket: Socket, content: GestureContent) { - socket.broadcast.emit("receiveGesturePoints", content); - } - - function processOverlayTrigger(socket: Socket, content: MobileInkOverlayContent) { - socket.broadcast.emit("receiveOverlayTrigger", content); - } - - function processUpdateOverlayPosition(socket: Socket, content: UpdateMobileInkOverlayPositionContent) { - socket.broadcast.emit("receiveUpdateOverlayPosition", content); - } - - function processMobileDocumentUpload(socket: Socket, content: MobileDocumentUploadContent) { - socket.broadcast.emit("receiveMobileDocumentUpload", content); - } - - function HandleYoutubeQuery([query, callback]: [YoutubeQueryInput, (result?: any[]) => void]) { - const { ProjectCredentials } = GoogleCredentialsLoader; - switch (query.type) { - case YoutubeQueryTypes.Channels: - YoutubeApi.authorizedGetChannel(ProjectCredentials); - break; - case YoutubeQueryTypes.SearchVideo: - YoutubeApi.authorizedGetVideos(ProjectCredentials, query.userInput, callback); - case YoutubeQueryTypes.VideoDetails: - YoutubeApi.authorizedGetVideoDetails(ProjectCredentials, query.videoIds, callback); - } - } - - export async function doDelete(onlyFields = true) { - const target: string[] = []; - onlyFields && target.push(DocumentsCollection); - await Database.Instance.dropSchema(...target); - if (process.env.DISABLE_SEARCH !== "true") { - await Search.clear(); - } - } - - function barReceived(socket: SocketIO.Socket, userEmail: string) { - clients[userEmail] = new Client(userEmail.toString()); - console.log(green(`user ${userEmail} has connected to the web socket`)); - socketMap.set(socket, userEmail); - } - - function getField([id, callback]: [string, (result?: Transferable) => void]) { - Database.Instance.getDocument(id, (result?: Transferable) => - callback(result ? result : undefined)); - } - - function getFields([ids, callback]: [string[], (result: Transferable[]) => void]) { - Database.Instance.getDocuments(ids, callback); - } - - function setField(socket: Socket, newValue: Transferable) { - Database.Instance.update(newValue.id, newValue, () => - socket.broadcast.emit(MessageStore.SetField.Message, newValue)); - if (newValue.type === Types.Text) { // if the newValue has sring type, then it's suitable for searching -- pass it to SOLR - Search.updateDocument({ id: newValue.id, data: (newValue as any).data }); - } - } - - function GetRefField([id, callback]: [string, (result?: Transferable) => void]) { - Database.Instance.getDocument(id, callback); - } - - function GetRefFields([ids, callback]: [string[], (result?: Transferable[]) => void]) { - Database.Instance.getDocuments(ids, callback); - } - - const suffixMap: { [type: string]: (string | [string, string | ((json: any) => any)]) } = { - "number": "_n", - "string": "_t", - "boolean": "_b", - "image": ["_t", "url"], - "video": ["_t", "url"], - "pdf": ["_t", "url"], - "audio": ["_t", "url"], - "web": ["_t", "url"], - "script": ["_t", value => value.script.originalScript], - "RichTextField": ["_t", value => value.Text], - "date": ["_d", value => new Date(value.date).toISOString()], - "proxy": ["_i", "fieldId"], - "list": ["_l", list => { - const results = []; - for (const value of list.fields) { - const term = ToSearchTerm(value); - if (term) { - results.push(term.value); - } - } - return results.length ? results : null; - }] - }; - - function ToSearchTerm(val: any): { suffix: string, value: any } | undefined { - if (val === null || val === undefined) { - return; - } - const type = val.__type || typeof val; - let suffix = suffixMap[type]; - if (!suffix) { - return; - } - - if (Array.isArray(suffix)) { - const accessor = suffix[1]; - if (typeof accessor === "function") { - val = accessor(val); - } else { - val = val[accessor]; - } - suffix = suffix[0]; - } - - return { suffix, value: val }; - } - - function getSuffix(value: string | [string, any]): string { - return typeof value === "string" ? value : value[0]; - } - - function UpdateField(socket: Socket, diff: Diff) { - Database.Instance.update(diff.id, diff.diff, - () => socket.broadcast.emit(MessageStore.UpdateField.Message, diff), false); - const docfield = diff.diff.$set || diff.diff.$unset; - if (!docfield) { - return; - } - const update: any = { id: diff.id }; - let dynfield = false; - for (let key in docfield) { - if (!key.startsWith("fields.")) continue; - dynfield = true; - const val = docfield[key]; - key = key.substring(7); - Object.values(suffixMap).forEach(suf => update[key + getSuffix(suf)] = { set: null }); - const term = ToSearchTerm(val); - if (term !== undefined) { - const { suffix, value } = term; - update[key + suffix] = { set: value }; - } - } - if (dynfield) { - Search.updateDocument(update); - } - } - - function DeleteField(socket: Socket, id: string) { - Database.Instance.delete({ _id: id }).then(() => { - socket.broadcast.emit(MessageStore.DeleteField.Message, id); - }); - - Search.deleteDocuments([id]); - } - - function DeleteFields(socket: Socket, ids: string[]) { - Database.Instance.delete({ _id: { $in: ids } }).then(() => { - socket.broadcast.emit(MessageStore.DeleteFields.Message, ids); - }); - Search.deleteDocuments(ids); - } - - function CreateField(newValue: any) { - Database.Instance.insert(newValue); - } - -} - diff --git a/src/server/apis/google/CredentialsLoader.ts b/src/server/apis/google/CredentialsLoader.ts new file mode 100644 index 000000000..e3f4d167b --- /dev/null +++ b/src/server/apis/google/CredentialsLoader.ts @@ -0,0 +1,29 @@ +import { readFile } from "fs"; + +export namespace GoogleCredentialsLoader { + + export interface InstalledCredentials { + client_id: string; + project_id: string; + auth_uri: string; + token_uri: string; + auth_provider_x509_cert_url: string; + client_secret: string; + redirect_uris: string[]; + } + + export let ProjectCredentials: InstalledCredentials; + + export async function loadCredentials() { + ProjectCredentials = await new Promise(resolve => { + readFile(__dirname + '/google_project_credentials.json', function processClientSecrets(err, content) { + if (err) { + console.log('Error loading client secret file: ' + err); + return; + } + resolve(JSON.parse(content.toString()).installed); + }); + }); + } + +} diff --git a/src/server/apis/google/GoogleApiServerUtils.ts b/src/server/apis/google/GoogleApiServerUtils.ts index 48a8da89f..2e4811c86 100644 --- a/src/server/apis/google/GoogleApiServerUtils.ts +++ b/src/server/apis/google/GoogleApiServerUtils.ts @@ -3,9 +3,9 @@ import { OAuth2Client, Credentials, OAuth2ClientOptions } from "google-auth-libr import { Opt } from "../../../new_fields/Doc"; import { GaxiosResponse } from "gaxios"; import request = require('request-promise'); -import * as qs from 'query-string'; +import * as qs from "query-string"; import { Database } from "../../database"; -import { GoogleCredentialsLoader } from "../../credentials/CredentialsLoader"; +import { GoogleCredentialsLoader } from "./CredentialsLoader"; /** * Scopes give Google users fine granularity of control @@ -224,7 +224,7 @@ export namespace GoogleApiServerUtils { }); }); const enriched = injectUserInfo(credentials); - await Database.Auxiliary.GoogleAuthenticationToken.Write(userId, enriched); + await Database.Auxiliary.GoogleAccessToken.Write(userId, enriched); return enriched; } @@ -280,7 +280,7 @@ export namespace GoogleApiServerUtils { * and a flag indicating whether or not they were refreshed during retrieval */ export async function retrieveCredentials(userId: string): Promise<{ credentials: Opt, refreshed: boolean }> { - let credentials = await Database.Auxiliary.GoogleAuthenticationToken.Fetch(userId); + let credentials = await Database.Auxiliary.GoogleAccessToken.Fetch(userId); let refreshed = false; if (!credentials) { return { credentials: undefined, refreshed }; @@ -318,7 +318,7 @@ export namespace GoogleApiServerUtils { }); // expires_in is in seconds, but we're building the new expiry date in milliseconds const expiry_date = new Date().getTime() + (expires_in * 1000); - await Database.Auxiliary.GoogleAuthenticationToken.Update(userId, access_token, expiry_date); + await Database.Auxiliary.GoogleAccessToken.Update(userId, access_token, expiry_date); // update the relevant properties credentials.access_token = access_token; credentials.expiry_date = expiry_date; diff --git a/src/server/apis/google/google_project_credentials.json b/src/server/apis/google/google_project_credentials.json new file mode 100644 index 000000000..955c5a3c1 --- /dev/null +++ b/src/server/apis/google/google_project_credentials.json @@ -0,0 +1,11 @@ +{ + "installed": { + "client_id": "343179513178-ud6tvmh275r2fq93u9eesrnc66t6akh9.apps.googleusercontent.com", + "project_id": "quickstart-1565056383187", + "auth_uri": "https://accounts.google.com/o/oauth2/auth", + "token_uri": "https://oauth2.googleapis.com/token", + "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", + "client_secret": "w8KIFSc0MQpmUYHed4qEzn8b", + "redirect_uris": ["urn:ietf:wg:oauth:2.0:oob", "http://localhost"] + } +} \ No newline at end of file diff --git a/src/server/apis/youtube/youtubeApiSample.js b/src/server/apis/youtube/youtubeApiSample.js index 50b3c7b38..d535bd9ff 100644 --- a/src/server/apis/youtube/youtubeApiSample.js +++ b/src/server/apis/youtube/youtubeApiSample.js @@ -1,6 +1,8 @@ const fs = require('fs'); const readline = require('readline'); -const { google } = require('googleapis'); +const { + google +} = require('googleapis'); const OAuth2 = google.auth.OAuth2; @@ -19,21 +21,27 @@ module.exports.readApiKey = (callback) => { } callback(content); }); -} +}; module.exports.authorizedGetChannel = (apiKey) => { //this didnt get called // Authorize a client with the loaded credentials, then call the YouTube API. authorize(JSON.parse(apiKey), getChannel); -} +}; module.exports.authorizedGetVideos = (apiKey, userInput, callBack) => { - authorize(JSON.parse(apiKey), getVideos, { userInput: userInput, callBack: callBack }); -} + authorize(JSON.parse(apiKey), getVideos, { + userInput: userInput, + callBack: callBack + }); +}; module.exports.authorizedGetVideoDetails = (apiKey, videoIds, callBack) => { - authorize(JSON.parse(apiKey), getVideoDetails, { videoIds: videoIds, callBack: callBack }); -} + authorize(JSON.parse(apiKey), getVideoDetails, { + videoIds: videoIds, + callBack: callBack + }); +}; /** diff --git a/src/server/authentication/AuthenticationManager.ts b/src/server/authentication/AuthenticationManager.ts new file mode 100644 index 000000000..00f1fe44e --- /dev/null +++ b/src/server/authentication/AuthenticationManager.ts @@ -0,0 +1,268 @@ +import { default as User, DashUserModel } from "./DashUserModel"; +import { Request, Response, NextFunction } from "express"; +import * as passport from "passport"; +import { IVerifyOptions } from "passport-local"; +import "./Passport"; +import flash = require("express-flash"); +import * as async from 'async'; +import * as nodemailer from 'nodemailer'; +import c = require("crypto"); +import { Utils } from "../../Utils"; +import { MailOptions } from "nodemailer/lib/stream-transport"; + +/** + * GET /signup + * Directs user to the signup page + * modeled by signup.pug in views + */ +export let getSignup = (req: Request, res: Response) => { + if (req.user) { + return res.redirect("/home"); + } + res.render("signup.pug", { + title: "Sign Up", + user: req.user, + }); +}; + +/** + * POST /signup + * Create a new local account. + */ +export let postSignup = (req: Request, res: Response, next: NextFunction) => { + req.assert("email", "Email is not valid").isEmail(); + req.assert("password", "Password must be at least 4 characters long").len({ min: 4 }); + req.assert("confirmPassword", "Passwords do not match").equals(req.body.password); + req.sanitize("email").normalizeEmail({ gmail_remove_dots: false }); + + const errors = req.validationErrors(); + + if (errors) { + return res.redirect("/signup"); + } + + const email = req.body.email as String; + const password = req.body.password; + + const model = { + email, + password, + userDocumentId: Utils.GenerateGuid() + } as Partial; + + const user = new User(model); + + User.findOne({ email }, (err, existingUser) => { + if (err) { return next(err); } + if (existingUser) { + return res.redirect("/login"); + } + user.save((err: any) => { + if (err) { return next(err); } + req.logIn(user, (err) => { + if (err) { return next(err); } + tryRedirectToTarget(req, res); + }); + }); + }); + +}; + +const tryRedirectToTarget = (req: Request, res: Response) => { + if (req.session && req.session.target) { + const target = req.session.target; + req.session.target = undefined; + res.redirect(target); + } else { + res.redirect("/home"); + } +}; + + +/** + * GET /login + * Login page. + */ +export let getLogin = (req: Request, res: Response) => { + if (req.user) { + req.session!.target = undefined; + return res.redirect("/home"); + } + res.render("login.pug", { + title: "Log In", + user: req.user + }); +}; + +/** + * POST /login + * Sign in using email and password. + * On failure, redirect to signup page + */ +export let postLogin = (req: Request, res: Response, next: NextFunction) => { + req.assert("email", "Email is not valid").isEmail(); + req.assert("password", "Password cannot be blank").notEmpty(); + req.sanitize("email").normalizeEmail({ gmail_remove_dots: false }); + + const errors = req.validationErrors(); + + if (errors) { + req.flash("errors", "Unable to login at this time. Please try again."); + return res.redirect("/signup"); + } + + passport.authenticate("local", (err: Error, user: DashUserModel, _info: IVerifyOptions) => { + if (err) { next(err); return; } + if (!user) { + return res.redirect("/signup"); + } + req.logIn(user, (err) => { + if (err) { next(err); return; } + tryRedirectToTarget(req, res); + }); + })(req, res, next); +}; + +/** + * GET /logout + * Invokes the logout function on the request + * and destroys the user's current session. + */ +export let getLogout = (req: Request, res: Response) => { + req.logout(); + const sess = req.session; + if (sess) { + sess.destroy((err) => { if (err) { console.log(err); } }); + } + res.redirect("/login"); +}; + +export let getForgot = function (req: Request, res: Response) { + res.render("forgot.pug", { + title: "Recover Password", + user: req.user, + }); +}; + +export let postForgot = function (req: Request, res: Response, next: NextFunction) { + const email = req.body.email; + async.waterfall([ + function (done: any) { + c.randomBytes(20, function (err: any, buffer: Buffer) { + if (err) { + done(null); + return; + } + done(null, buffer.toString('hex')); + }); + }, + function (token: string, done: any) { + User.findOne({ email }, function (err, user: DashUserModel) { + if (!user) { + // NO ACCOUNT WITH SUBMITTED EMAIL + res.redirect("/forgotPassword"); + return; + } + user.passwordResetToken = token; + user.passwordResetExpires = new Date(Date.now() + 3600000); // 1 HOUR + user.save(function (err: any) { + done(null, token, user); + }); + }); + }, + function (token: Uint16Array, user: DashUserModel, done: any) { + const smtpTransport = nodemailer.createTransport({ + service: 'Gmail', + auth: { + user: 'brownptcdash@gmail.com', + pass: 'browngfx1' + } + }); + const mailOptions = { + to: user.email, + from: 'brownptcdash@gmail.com', + subject: 'Dash Password Reset', + text: 'You are receiving this because you (or someone else) have requested the reset of the password for your account.\n\n' + + 'Please click on the following link, or paste this into your browser to complete the process:\n\n' + + 'http://' + req.headers.host + '/resetPassword/' + token + '\n\n' + + 'If you did not request this, please ignore this email and your password will remain unchanged.\n' + } as MailOptions; + smtpTransport.sendMail(mailOptions, function (err: Error | null) { + // req.flash('info', 'An e-mail has been sent to ' + user.email + ' with further instructions.'); + done(null, err, 'done'); + }); + } + ], function (err) { + if (err) return next(err); + res.redirect("/forgotPassword"); + }); +}; + +export let getReset = function (req: Request, res: Response) { + User.findOne({ passwordResetToken: req.params.token, passwordResetExpires: { $gt: Date.now() } }, function (err, user: DashUserModel) { + if (!user || err) { + return res.redirect("/forgotPassword"); + } + res.render("reset.pug", { + title: "Reset Password", + user: req.user, + }); + }); +}; + +export let postReset = function (req: Request, res: Response) { + async.waterfall([ + function (done: any) { + User.findOne({ passwordResetToken: req.params.token, passwordResetExpires: { $gt: Date.now() } }, function (err, user: DashUserModel) { + if (!user || err) { + return res.redirect('back'); + } + + req.assert("password", "Password must be at least 4 characters long").len({ min: 4 }); + req.assert("confirmPassword", "Passwords do not match").equals(req.body.password); + + if (req.validationErrors()) { + return res.redirect('back'); + } + + user.password = req.body.password; + user.passwordResetToken = undefined; + user.passwordResetExpires = undefined; + + user.save(function (err) { + if (err) { + res.redirect("/login"); + return; + } + req.logIn(user, function (err) { + if (err) { + return; + } + }); + done(null, user); + }); + }); + }, + function (user: DashUserModel, done: any) { + const smtpTransport = nodemailer.createTransport({ + service: 'Gmail', + auth: { + user: 'brownptcdash@gmail.com', + pass: 'browngfx1' + } + }); + const mailOptions = { + to: user.email, + from: 'brownptcdash@gmail.com', + subject: 'Your password has been changed', + text: 'Hello,\n\n' + + 'This is a confirmation that the password for your account ' + user.email + ' has just been changed.\n' + } as MailOptions; + smtpTransport.sendMail(mailOptions, function (err) { + done(null, err); + }); + } + ], function (err) { + res.redirect("/login"); + }); +}; \ No newline at end of file diff --git a/src/server/authentication/DashUserModel.ts b/src/server/authentication/DashUserModel.ts new file mode 100644 index 000000000..51d920a8f --- /dev/null +++ b/src/server/authentication/DashUserModel.ts @@ -0,0 +1,86 @@ +//@ts-ignore +import * as bcrypt from "bcrypt-nodejs"; +//@ts-ignore +import * as mongoose from 'mongoose'; + +export type DashUserModel = mongoose.Document & { + email: String, + password: string, + passwordResetToken?: string, + passwordResetExpires?: Date, + + userDocumentId: string; + + profile: { + name: string, + gender: string, + location: string, + website: string, + picture: string + }, + + comparePassword: comparePasswordFunction, +}; + +type comparePasswordFunction = (candidatePassword: string, cb: (err: any, isMatch: any) => {}) => void; + +export type AuthToken = { + accessToken: string, + kind: string +}; + +const userSchema = new mongoose.Schema({ + email: String, + password: String, + passwordResetToken: String, + passwordResetExpires: Date, + + userDocumentId: String, + + facebook: String, + twitter: String, + google: String, + + profile: { + name: String, + gender: String, + location: String, + website: String, + picture: String + } +}, { timestamps: true }); + +/** + * Password hash middleware. + */ +userSchema.pre("save", function save(next) { + const user = this as DashUserModel; + if (!user.isModified("password")) { + return next(); + } + bcrypt.genSalt(10, (err: any, salt: string) => { + if (err) { + return next(err); + } + bcrypt.hash(user.password, salt, () => void {}, (err: mongoose.Error, hash: string) => { + if (err) { + return next(err); + } + user.password = hash; + next(); + }); + }); +}); + +const comparePassword: comparePasswordFunction = function (this: DashUserModel, candidatePassword, cb) { + // Choose one of the following bodies for authentication logic. + // secure (expected, default) + bcrypt.compare(candidatePassword, this.password, cb); + // bypass password (debugging) + // cb(undefined, true); +}; + +userSchema.methods.comparePassword = comparePassword; + +const User = mongoose.model("User", userSchema); +export default User; \ No newline at end of file diff --git a/src/server/authentication/Passport.ts b/src/server/authentication/Passport.ts new file mode 100644 index 000000000..9b0069414 --- /dev/null +++ b/src/server/authentication/Passport.ts @@ -0,0 +1,29 @@ +import * as passport from 'passport'; +import * as passportLocal from 'passport-local'; +import { default as User } from './DashUserModel'; + +const LocalStrategy = passportLocal.Strategy; + +passport.serializeUser((user, done) => { + done(undefined, user.id); +}); + +passport.deserializeUser((id, done) => { + User.findById(id, (err, user) => { + done(err, user); + }); +}); + +// AUTHENTICATE JUST WITH EMAIL AND PASSWORD +passport.use(new LocalStrategy({ usernameField: 'email', passReqToCallback: true }, (req, email, password, done) => { + User.findOne({ email: email.toLowerCase() }, (error: any, user: any) => { + if (error) return done(error); + if (!user) return done(undefined, false, { message: "Invalid email or password" }); // invalid email + user.comparePassword(password, (error: Error, isMatch: boolean) => { + if (error) return done(error); + if (!isMatch) return done(undefined, false, { message: "Invalid email or password" }); // invalid password + // valid authentication HERE + return done(undefined, user); + }); + }); +})); \ No newline at end of file diff --git a/src/server/authentication/config/passport.ts b/src/server/authentication/config/passport.ts deleted file mode 100644 index 286209b20..000000000 --- a/src/server/authentication/config/passport.ts +++ /dev/null @@ -1,29 +0,0 @@ -import * as passport from 'passport'; -import * as passportLocal from 'passport-local'; -import { default as User } from '../models/user_model'; - -const LocalStrategy = passportLocal.Strategy; - -passport.serializeUser((user, done) => { - done(undefined, user.id); -}); - -passport.deserializeUser((id, done) => { - User.findById(id, (err, user) => { - done(err, user); - }); -}); - -// AUTHENTICATE JUST WITH EMAIL AND PASSWORD -passport.use(new LocalStrategy({ usernameField: 'email', passReqToCallback: true }, (req, email, password, done) => { - User.findOne({ email: email.toLowerCase() }, (error: any, user: any) => { - if (error) return done(error); - if (!user) return done(undefined, false, { message: "Invalid email or password" }); // invalid email - user.comparePassword(password, (error: Error, isMatch: boolean) => { - if (error) return done(error); - if (!isMatch) return done(undefined, false, { message: "Invalid email or password" }); // invalid password - // valid authentication HERE - return done(undefined, user); - }); - }); -})); \ No newline at end of file diff --git a/src/server/authentication/controllers/user_controller.ts b/src/server/authentication/controllers/user_controller.ts deleted file mode 100644 index f0086d4ea..000000000 --- a/src/server/authentication/controllers/user_controller.ts +++ /dev/null @@ -1,268 +0,0 @@ -import { default as User, DashUserModel, AuthToken } from "../models/user_model"; -import { Request, Response, NextFunction } from "express"; -import * as passport from "passport"; -import { IVerifyOptions } from "passport-local"; -import "../config/passport"; -import flash = require("express-flash"); -import * as async from 'async'; -import * as nodemailer from 'nodemailer'; -import c = require("crypto"); -import { Utils } from "../../../Utils"; -import { MailOptions } from "nodemailer/lib/stream-transport"; - -/** - * GET /signup - * Directs user to the signup page - * modeled by signup.pug in views - */ -export let getSignup = (req: Request, res: Response) => { - if (req.user) { - return res.redirect("/home"); - } - res.render("signup.pug", { - title: "Sign Up", - user: req.user, - }); -}; - -/** - * POST /signup - * Create a new local account. - */ -export let postSignup = (req: Request, res: Response, next: NextFunction) => { - req.assert("email", "Email is not valid").isEmail(); - req.assert("password", "Password must be at least 4 characters long").len({ min: 4 }); - req.assert("confirmPassword", "Passwords do not match").equals(req.body.password); - req.sanitize("email").normalizeEmail({ gmail_remove_dots: false }); - - const errors = req.validationErrors(); - - if (errors) { - return res.redirect("/signup"); - } - - const email = req.body.email as String; - const password = req.body.password; - - const model = { - email, - password, - userDocumentId: Utils.GenerateGuid() - } as Partial; - - const user = new User(model); - - User.findOne({ email }, (err, existingUser) => { - if (err) { return next(err); } - if (existingUser) { - return res.redirect("/login"); - } - user.save((err: any) => { - if (err) { return next(err); } - req.logIn(user, (err) => { - if (err) { return next(err); } - tryRedirectToTarget(req, res); - }); - }); - }); - -}; - -const tryRedirectToTarget = (req: Request, res: Response) => { - if (req.session && req.session.target) { - const target = req.session.target; - req.session.target = undefined; - res.redirect(target); - } else { - res.redirect("/home"); - } -}; - - -/** - * GET /login - * Login page. - */ -export let getLogin = (req: Request, res: Response) => { - if (req.user) { - req.session!.target = undefined; - return res.redirect("/home"); - } - res.render("login.pug", { - title: "Log In", - user: req.user - }); -}; - -/** - * POST /login - * Sign in using email and password. - * On failure, redirect to signup page - */ -export let postLogin = (req: Request, res: Response, next: NextFunction) => { - req.assert("email", "Email is not valid").isEmail(); - req.assert("password", "Password cannot be blank").notEmpty(); - req.sanitize("email").normalizeEmail({ gmail_remove_dots: false }); - - const errors = req.validationErrors(); - - if (errors) { - req.flash("errors", "Unable to login at this time. Please try again."); - return res.redirect("/signup"); - } - - passport.authenticate("local", (err: Error, user: DashUserModel, info: IVerifyOptions) => { - if (err) { next(err); return; } - if (!user) { - return res.redirect("/signup"); - } - req.logIn(user, (err) => { - if (err) { next(err); return; } - tryRedirectToTarget(req, res); - }); - })(req, res, next); -}; - -/** - * GET /logout - * Invokes the logout function on the request - * and destroys the user's current session. - */ -export let getLogout = (req: Request, res: Response) => { - req.logout(); - const sess = req.session; - if (sess) { - sess.destroy((err) => { if (err) { console.log(err); } }); - } - res.redirect("/login"); -}; - -export let getForgot = function (req: Request, res: Response) { - res.render("forgot.pug", { - title: "Recover Password", - user: req.user, - }); -}; - -export let postForgot = function (req: Request, res: Response, next: NextFunction) { - const email = req.body.email; - async.waterfall([ - function (done: any) { - c.randomBytes(20, function (err: any, buffer: Buffer) { - if (err) { - done(null); - return; - } - done(null, buffer.toString('hex')); - }); - }, - function (token: string, done: any) { - User.findOne({ email }, function (err, user: DashUserModel) { - if (!user) { - // NO ACCOUNT WITH SUBMITTED EMAIL - res.redirect("/forgotPassword"); - return; - } - user.passwordResetToken = token; - user.passwordResetExpires = new Date(Date.now() + 3600000); // 1 HOUR - user.save(function (err: any) { - done(null, token, user); - }); - }); - }, - function (token: Uint16Array, user: DashUserModel, done: any) { - const smtpTransport = nodemailer.createTransport({ - service: 'Gmail', - auth: { - user: 'brownptcdash@gmail.com', - pass: 'browngfx1' - } - }); - const mailOptions = { - to: user.email, - from: 'brownptcdash@gmail.com', - subject: 'Dash Password Reset', - text: 'You are receiving this because you (or someone else) have requested the reset of the password for your account.\n\n' + - 'Please click on the following link, or paste this into your browser to complete the process:\n\n' + - 'http://' + req.headers.host + '/resetPassword/' + token + '\n\n' + - 'If you did not request this, please ignore this email and your password will remain unchanged.\n' - } as MailOptions; - smtpTransport.sendMail(mailOptions, function (err: Error | null) { - // req.flash('info', 'An e-mail has been sent to ' + user.email + ' with further instructions.'); - done(null, err, 'done'); - }); - } - ], function (err) { - if (err) return next(err); - res.redirect("/forgotPassword"); - }); -}; - -export let getReset = function (req: Request, res: Response) { - User.findOne({ passwordResetToken: req.params.token, passwordResetExpires: { $gt: Date.now() } }, function (err, user: DashUserModel) { - if (!user || err) { - return res.redirect("/forgotPassword"); - } - res.render("reset.pug", { - title: "Reset Password", - user: req.user, - }); - }); -}; - -export let postReset = function (req: Request, res: Response) { - async.waterfall([ - function (done: any) { - User.findOne({ passwordResetToken: req.params.token, passwordResetExpires: { $gt: Date.now() } }, function (err, user: DashUserModel) { - if (!user || err) { - return res.redirect('back'); - } - - req.assert("password", "Password must be at least 4 characters long").len({ min: 4 }); - req.assert("confirmPassword", "Passwords do not match").equals(req.body.password); - - if (req.validationErrors()) { - return res.redirect('back'); - } - - user.password = req.body.password; - user.passwordResetToken = undefined; - user.passwordResetExpires = undefined; - - user.save(function (err) { - if (err) { - res.redirect("/login"); - return; - } - req.logIn(user, function (err) { - if (err) { - return; - } - }); - done(null, user); - }); - }); - }, - function (user: DashUserModel, done: any) { - const smtpTransport = nodemailer.createTransport({ - service: 'Gmail', - auth: { - user: 'brownptcdash@gmail.com', - pass: 'browngfx1' - } - }); - const mailOptions = { - to: user.email, - from: 'brownptcdash@gmail.com', - subject: 'Your password has been changed', - text: 'Hello,\n\n' + - 'This is a confirmation that the password for your account ' + user.email + ' has just been changed.\n' - } as MailOptions; - smtpTransport.sendMail(mailOptions, function (err) { - done(null, err); - }); - } - ], function (err) { - res.redirect("/login"); - }); -}; \ No newline at end of file diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts deleted file mode 100644 index b6ff10bab..000000000 --- a/src/server/authentication/models/current_user_utils.ts +++ /dev/null @@ -1,738 +0,0 @@ -import { action, computed, observable, reaction } from "mobx"; -import * as rp from 'request-promise'; -import { Utils } from "../../../Utils"; -import { DocServer } from "../../../client/DocServer"; -import { Docs, DocumentOptions } from "../../../client/documents/Documents"; -import { UndoManager } from "../../../client/util/UndoManager"; -import { Doc, DocListCast, DocListCastAsync } from "../../../new_fields/Doc"; -import { List } from "../../../new_fields/List"; -import { listSpec } from "../../../new_fields/Schema"; -import { ScriptField, ComputedField } from "../../../new_fields/ScriptField"; -import { Cast, PromiseValue, StrCast, NumCast } from "../../../new_fields/Types"; -import { nullAudio, ImageField } from "../../../new_fields/URLField"; -import { DragManager } from "../../../client/util/DragManager"; -import { InkingControl } from "../../../client/views/InkingControl"; -import { Scripting, CompileScript } from "../../../client/util/Scripting"; -import { CollectionViewType } from "../../../client/views/collections/CollectionView"; -import { makeTemplate } from "../../../client/util/DropConverter"; -import { RichTextField } from "../../../new_fields/RichTextField"; -import { PrefetchProxy } from "../../../new_fields/Proxy"; -import { FormattedTextBox } from "../../../client/views/nodes/formattedText/FormattedTextBox"; -import { MainView } from "../../../client/views/MainView"; -import { DocumentType } from "../../../client/documents/DocumentTypes"; -import { SchemaHeaderField } from "../../../new_fields/SchemaHeaderField"; -import { DimUnit } from "../../../client/views/collections/collectionMulticolumn/CollectionMulticolumnView"; - -export class CurrentUserUtils { - private static curr_id: string; - //TODO tfs: these should be temporary... - private static mainDocId: string | undefined; - - public static get id() { return this.curr_id; } - public static get MainDocId() { return this.mainDocId; } - public static set MainDocId(id: string | undefined) { this.mainDocId = id; } - @computed public static get UserDocument() { return Doc.UserDoc(); } - @computed public static get ActivePen() { return Doc.UserDoc().activePen instanceof Doc && (Doc.UserDoc().activePen as Doc).inkPen as Doc; } - - @observable public static GuestTarget: Doc | undefined; - @observable public static GuestWorkspace: Doc | undefined; - @observable public static GuestMobile: Doc | undefined; - - // sets up the default User Templates - slideView, queryView, descriptionView - static setupUserTemplateButtons(doc: Doc) { - if (doc["template-button-query"] === undefined) { - const queryTemplate = Docs.Create.MulticolumnDocument( - [ - Docs.Create.QueryDocument({ title: "query", _height: 200 }), - Docs.Create.FreeformDocument([], { title: "data", _height: 100, _LODdisable: true }) - ], - { _width: 400, _height: 300, title: "queryView", _chromeStatus: "disabled", _xMargin: 3, _yMargin: 3, hideFilterView: true } - ); - queryTemplate.isTemplateDoc = makeTemplate(queryTemplate); - doc["template-button-query"] = CurrentUserUtils.ficon({ - onDragStart: ScriptField.MakeFunction('getCopy(this.dragFactory, true)'), - dragFactory: new PrefetchProxy(queryTemplate) as any as Doc, - removeDropProperties: new List(["dropAction"]), title: "query view", icon: "question-circle" - }); - } - - if (doc["template-button-slides"] === undefined) { - const slideTemplate = Docs.Create.MultirowDocument( - [ - Docs.Create.MulticolumnDocument([], { title: "data", _height: 200 }), - Docs.Create.TextDocument("", { title: "text", _height: 100 }) - ], - { _width: 400, _height: 300, title: "slideView", _chromeStatus: "disabled", _xMargin: 3, _yMargin: 3, hideFilterView: true } - ); - slideTemplate.isTemplateDoc = makeTemplate(slideTemplate); - doc["template-button-slides"] = CurrentUserUtils.ficon({ - onDragStart: ScriptField.MakeFunction('getCopy(this.dragFactory, true)'), - dragFactory: new PrefetchProxy(slideTemplate) as any as Doc, - removeDropProperties: new List(["dropAction"]), title: "presentation slide", icon: "address-card" - }); - } - - if (doc["template-button-description"] === undefined) { - const descriptionTemplate = Docs.Create.TextDocument(" ", { title: "header", _height: 100 }, "header"); // text needs to be a space to allow templateText to be created - Doc.GetProto(descriptionTemplate).layout = - "
" + - "
"; - descriptionTemplate.isTemplateDoc = makeTemplate(descriptionTemplate, true, "descriptionView"); - - doc["template-button-description"] = CurrentUserUtils.ficon({ - onDragStart: ScriptField.MakeFunction('makeDelegate(this.dragFactory)'), - dragFactory: new PrefetchProxy(descriptionTemplate) as any as Doc, - removeDropProperties: new List(["dropAction"]), title: "description view", icon: "window-maximize" - }); - } - - if (doc["template-button-switch"] === undefined) { - const { FreeformDocument, MulticolumnDocument, TextDocument } = Docs.Create; - - const yes = FreeformDocument([], { title: "yes", _height: 35, _width: 50, _LODdisable: true, _dimUnit: DimUnit.Pixel, _dimMagnitude: 40 }); - const name = TextDocument("name", { title: "name", _height: 35, _width: 70, _dimMagnitude: 1 }); - const no = FreeformDocument([], { title: "no", _height: 100, _width: 100, _LODdisable: true }); - const labelTemplate = { - doc: { - type: "doc", content: [{ - type: "paragraph", - content: [{ type: "dashField", attrs: { fieldKey: "PARAMS", hideKey: true } }] - }] - }, - selection: { type: "text", anchor: 1, head: 1 }, - storedMarks: [] - }; - Doc.GetProto(name).text = new RichTextField(JSON.stringify(labelTemplate), "PARAMS"); - Doc.GetProto(yes).backgroundColor = ComputedField.MakeFunction("self[this.PARAMS] ? 'green':'red'"); - // Doc.GetProto(no).backgroundColor = ComputedField.MakeFunction("!self[this.PARAMS] ? 'red':'white'"); - // Doc.GetProto(yes).onClick = ScriptField.MakeScript("self[this.PARAMS] = true"); - Doc.GetProto(yes).onClick = ScriptField.MakeScript("self[this.PARAMS] = !self[this.PARAMS]"); - // Doc.GetProto(no).onClick = ScriptField.MakeScript("self[this.PARAMS] = false"); - const box = MulticolumnDocument([/*no, */ yes, name], { title: "value", _width: 120, _height: 35, }); - box.isTemplateDoc = makeTemplate(box, true, "switch"); - - doc["template-button-switch"] = CurrentUserUtils.ficon({ - onDragStart: ScriptField.MakeFunction('getCopy(this.dragFactory, true)'), - dragFactory: new PrefetchProxy(box) as any as Doc, - removeDropProperties: new List(["dropAction"]), title: "data switch", icon: "toggle-on" - }); - } - - if (doc["template-button-detail"] === undefined) { - const { TextDocument, MasonryDocument, CarouselDocument } = Docs.Create; - - const openInTarget = ScriptField.MakeScript("openOnRight(self.doubleClickView)"); - const carousel = CarouselDocument([], { - title: "data", _height: 350, _itemIndex: 0, "_carousel-caption-xMargin": 10, "_carousel-caption-yMargin": 10, - onChildDoubleClick: openInTarget, backgroundColor: "#9b9b9b3F" - }); - - const details = TextDocument("", { title: "details", _height: 350, _autoHeight: true }); - const short = TextDocument("", { title: "shortDescription", treeViewOpen: true, treeViewExpandedView: "layout", _height: 100, _autoHeight: true }); - const long = TextDocument("", { title: "longDescription", treeViewOpen: false, treeViewExpandedView: "layout", _height: 350, _autoHeight: true }); - - const buxtonFieldKeys = ["year", "originalPrice", "degreesOfFreedom", "company", "attribute", "primaryKey", "secondaryKey", "dimensions"]; - const detailedTemplate = { - doc: { - type: "doc", content: buxtonFieldKeys.map(fieldKey => ({ - type: "paragraph", - content: [{ type: "dashField", attrs: { fieldKey } }] - })) - }, - selection: { type: "text", anchor: 1, head: 1 }, - storedMarks: [] - }; - details.text = new RichTextField(JSON.stringify(detailedTemplate), buxtonFieldKeys.join(" ")); - - const shared = { _chromeStatus: "disabled", _autoHeight: true, _xMargin: 0 }; - const detailViewOpts = { title: "detailView", _width: 300, _fontFamily: "Arial", _fontSize: 12 }; - const descriptionWrapperOpts = { title: "descriptions", _height: 300, columnWidth: -1, treeViewHideTitle: true, _pivotField: "title" }; - - const descriptionWrapper = MasonryDocument([details, short, long], { ...shared, ...descriptionWrapperOpts }); - descriptionWrapper.sectionHeaders = new List([ - new SchemaHeaderField("[A Short Description]", "dimGray", undefined, undefined, undefined, false), - new SchemaHeaderField("[Long Description]", "dimGray", undefined, undefined, undefined, true), - new SchemaHeaderField("[Details]", "dimGray", undefined, undefined, undefined, true), - ]); - const detailView = Docs.Create.StackingDocument([carousel, descriptionWrapper], { ...shared, ...detailViewOpts }); - detailView.isTemplateDoc = makeTemplate(detailView); - - details.title = "Details"; - short.title = "A Short Description"; - long.title = "Long Description"; - - doc["template-button-detail"] = CurrentUserUtils.ficon({ - onDragStart: ScriptField.MakeFunction('getCopy(this.dragFactory, true)'), - dragFactory: new PrefetchProxy(detailView) as any as Doc, - removeDropProperties: new List(["dropAction"]), title: "detail view", icon: "window-maximize" - }); - } - - if (doc["template-buttons"] === undefined) { - doc["template-buttons"] = new PrefetchProxy(Docs.Create.MasonryDocument([doc["template-button-slides"] as Doc, doc["template-button-description"] as Doc, - doc["template-button-query"] as Doc, doc["template-button-detail"] as Doc, doc["template-button-switch"] as Doc], { - title: "Advanced Item Prototypes", _xMargin: 0, _showTitle: "title", - _autoHeight: true, _width: 500, columnWidth: 35, ignoreClick: true, lockedPosition: true, _chromeStatus: "disabled", - dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }), - })); - } else { - const curButnTypes = Cast(doc["template-buttons"], Doc, null); - const requiredTypes = [doc["template-button-slides"] as Doc, doc["template-button-description"] as Doc, - doc["template-button-query"] as Doc, doc["template-button-detail"] as Doc, doc["template-button-switch"] as Doc]; - DocListCastAsync(curButnTypes.data).then(async curBtns => { - await Promise.all(curBtns!); - requiredTypes.map(btype => Doc.AddDocToList(curButnTypes, "data", btype)); - }); - } - return doc["template-buttons"] as Doc; - } - - // setup the different note type skins - static setupNoteTemplates(doc: Doc) { - if (doc["template-note-Note"] === undefined) { - const noteView = Docs.Create.TextDocument("", { title: "text", style: "Note", isTemplateDoc: true, backgroundColor: "yellow" }); - noteView.isTemplateDoc = makeTemplate(noteView, true, "Note"); - doc["template-note-Note"] = new PrefetchProxy(noteView); - } - if (doc["template-note-Idea"] === undefined) { - const noteView = Docs.Create.TextDocument("", { title: "text", style: "Idea", backgroundColor: "pink" }); - noteView.isTemplateDoc = makeTemplate(noteView, true, "Idea"); - doc["template-note-Idea"] = new PrefetchProxy(noteView); - } - if (doc["template-note-Topic"] === undefined) { - const noteView = Docs.Create.TextDocument("", { title: "text", style: "Topic", backgroundColor: "lightBlue" }); - noteView.isTemplateDoc = makeTemplate(noteView, true, "Topic"); - doc["template-note-Topic"] = new PrefetchProxy(noteView); - } - if (doc["template-note-Todo"] === undefined) { - const noteView = Docs.Create.TextDocument("", { - title: "text", style: "Todo", backgroundColor: "orange", _autoHeight: false, _height: 100, _showCaption: "caption", - layout: FormattedTextBox.LayoutString("Todo"), caption: RichTextField.DashField("taskStatus") - }); - noteView.isTemplateDoc = makeTemplate(noteView, true, "Todo"); - doc["template-note-Todo"] = new PrefetchProxy(noteView); - } - const taskStatusValues = [ - { title: "todo", _backgroundColor: "blue", color: "white" }, - { title: "in progress", _backgroundColor: "yellow", color: "black" }, - { title: "completed", _backgroundColor: "green", color: "white" } - ]; - if (doc.fieldTypes === undefined) { - doc.fieldTypes = Docs.Create.TreeDocument([], { title: "field enumerations" }); - Doc.addFieldEnumerations(Doc.GetProto(doc["template-note-Todo"] as any as Doc), "taskStatus", taskStatusValues); - } - - if (doc["template-notes"] === undefined) { - doc["template-notes"] = new PrefetchProxy(Docs.Create.TreeDocument([doc["template-note-Note"] as any as Doc, - doc["template-note-Idea"] as any as Doc, doc["template-note-Topic"] as any as Doc, doc["template-note-Todo"] as any as Doc], - { title: "Note Layouts", _height: 75 })); - } else { - const curNoteTypes = Cast(doc["template-notes"], Doc, null); - const requiredTypes = [doc["template-note-Note"] as any as Doc, doc["template-note-Idea"] as any as Doc, - doc["template-note-Topic"] as any as Doc, doc["template-note-Todo"] as any as Doc]; - DocListCastAsync(curNoteTypes.data).then(async curNotes => { - await Promise.all(curNotes!); - requiredTypes.map(ntype => Doc.AddDocToList(curNoteTypes, "data", ntype)); - }); - } - - return doc["template-notes"] as Doc; - } - - // creates Note templates, and initial "user" templates - static setupDocTemplates(doc: Doc) { - const noteTemplates = CurrentUserUtils.setupNoteTemplates(doc); - const userTemplateBtns = CurrentUserUtils.setupUserTemplateButtons(doc); - const clickTemplates = CurrentUserUtils.setupClickEditorTemplates(doc); - if (doc.templateDocs === undefined) { - doc.templateDocs = new PrefetchProxy(Docs.Create.TreeDocument([noteTemplates, userTemplateBtns, clickTemplates], { - title: "template layouts", _xPadding: 0, - dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }) - })); - } - } - - // setup templates for different document types when they are iconified from Document Decorations - static setupDefaultIconTemplates(doc: Doc) { - if (doc["template-icon-view"] === undefined) { - const iconView = Docs.Create.TextDocument("", { - title: "icon", _width: 150, _height: 30, isTemplateDoc: true, onDoubleClick: ScriptField.MakeScript("deiconifyView(self)") - }); - Doc.GetProto(iconView).icon = new RichTextField('{"doc":{"type":"doc","content":[{"type":"paragraph","attrs":{"align":null,"color":null,"id":null,"indent":null,"inset":null,"lineSpacing":null,"paddingBottom":null,"paddingTop":null},"content":[{"type":"dashField","attrs":{"fieldKey":"title","docid":""}}]}]},"selection":{"type":"text","anchor":2,"head":2},"storedMarks":[]}', ""); - iconView.isTemplateDoc = makeTemplate(iconView); - doc["template-icon-view"] = new PrefetchProxy(iconView); - } - if (doc["template-icon-view-rtf"] === undefined) { - const iconRtfView = Docs.Create.LabelDocument({ - title: "icon_" + DocumentType.RTF, textTransform: "unset", letterSpacing: "unset", - _width: 150, _height: 70, _xPadding: 10, _yPadding: 10, isTemplateDoc: true, onDoubleClick: ScriptField.MakeScript("deiconifyView(self)") - }); - iconRtfView.isTemplateDoc = makeTemplate(iconRtfView, true, "icon_" + DocumentType.RTF); - doc["template-icon-view-rtf"] = new PrefetchProxy(iconRtfView); - } - if (doc["template-icon-view-img"] === undefined) { - const iconImageView = Docs.Create.ImageDocument("http://www.cs.brown.edu/~bcz/face.gif", { - title: "data", _width: 50, isTemplateDoc: true, onDoubleClick: ScriptField.MakeScript("deiconifyView(self)") - }); - iconImageView.isTemplateDoc = makeTemplate(iconImageView, true, "icon_" + DocumentType.IMG); - doc["template-icon-view-img"] = new PrefetchProxy(iconImageView); - } - if (doc["template-icon-view-col"] === undefined) { - const iconColView = Docs.Create.TreeDocument([], { title: "data", _width: 180, _height: 80, onDoubleClick: ScriptField.MakeScript("deiconifyView(self)") }); - iconColView.isTemplateDoc = makeTemplate(iconColView, true, "icon_" + DocumentType.COL); - doc["template-icon-view-col"] = new PrefetchProxy(iconColView); - } - if (doc["template-icons"] === undefined) { - doc["template-icons"] = new PrefetchProxy(Docs.Create.TreeDocument([doc["template-icon-view"] as Doc, doc["template-icon-view-img"] as Doc, - doc["template-icon-view-col"] as Doc, doc["template-icon-view-rtf"] as Doc], { title: "icon templates", _height: 75 })); - } else { - const templateIconsDoc = Cast(doc["template-icons"], Doc, null); - const requiredTypes = [doc["template-icon-view"] as Doc, doc["template-icon-view-img"] as Doc, - doc["template-icon-view-col"] as Doc, doc["template-icon-view-rtf"] as Doc]; - DocListCastAsync(templateIconsDoc.data).then(async curIcons => { - await Promise.all(curIcons!); - requiredTypes.map(ntype => Doc.AddDocToList(templateIconsDoc, "data", ntype)); - }); - } - return doc["template-icons"] as Doc; - } - - static creatorBtnDescriptors(doc: Doc): { - title: string, label: string, icon: string, drag?: string, ignoreClick?: boolean, - click?: string, ischecked?: string, activePen?: Doc, backgroundColor?: string, dragFactory?: Doc - }[] { - if (doc.emptyPresentation === undefined) { - doc.emptyPresentation = Docs.Create.PresDocument(new List(), - { title: "Presentation", _viewType: CollectionViewType.Stacking, targetDropAction: "alias", _LODdisable: true, _chromeStatus: "replaced", _showTitle: "title", boxShadow: "0 0" }); - } - if (doc.emptyCollection === undefined) { - doc.emptyCollection = Docs.Create.FreeformDocument([], - { _nativeWidth: undefined, _nativeHeight: undefined, _LODdisable: true, _width: 150, _height: 100, title: "freeform" }); - } - if (doc.emptyDocHolder === undefined) { - doc.emptyDocHolder = Docs.Create.DocumentDocument( - ComputedField.MakeFunction("selectedDocs(this,this.excludeCollections,[_last_])?.[0]") as any, - { _width: 250, _height: 250, title: "container" }); - } - if (doc.emptyWebpage === undefined) { - doc.emptyWebpage = Docs.Create.WebDocument("", { title: "New Webpage", _width: 600, UseCors: true }); - } - return [ - { title: "Drag a collection", label: "Col", icon: "folder", click: 'openOnRight(getCopy(this.dragFactory, true))', drag: 'getCopy(this.dragFactory, true)', dragFactory: doc.emptyCollection as Doc }, - { title: "Drag a web page", label: "Web", icon: "globe-asia", click: 'openOnRight(getCopy(this.dragFactory, true))', drag: 'getCopy(this.dragFactory, true)', dragFactory: doc.emptyWebpage as Doc }, - { title: "Drag a cat image", label: "Img", icon: "cat", ignoreClick: true, drag: 'Docs.Create.ImageDocument("https://upload.wikimedia.org/wikipedia/commons/thumb/3/3a/Cat03.jpg/1200px-Cat03.jpg", { _width: 250, _nativeWidth:250, title: "an image of a cat" })' }, - { title: "Drag a screenshot", label: "Grab", icon: "photo-video", ignoreClick: true, drag: 'Docs.Create.ScreenshotDocument("", { _width: 400, _height: 200, title: "screen snapshot" })' }, - { title: "Drag a webcam", label: "Cam", icon: "video", ignoreClick: true, drag: 'Docs.Create.WebCamDocument("", { _width: 400, _height: 400, title: "a test cam" })' }, - { title: "Drag a audio recorder", label: "Audio", icon: "microphone", ignoreClick: true, drag: `Docs.Create.AudioDocument("${nullAudio}", { _width: 200, title: "ready to record audio" })` }, - { title: "Drag a clickable button", label: "Btn", icon: "bolt", ignoreClick: true, drag: 'Docs.Create.ButtonDocument({ _width: 150, _height: 50, _xPadding:10, _yPadding: 10, title: "Button" })' }, - { title: "Drag a presentation view", label: "Prezi", icon: "tv", click: 'openOnRight(Doc.UserDoc().activePresentation = getCopy(this.dragFactory, true))', drag: `Doc.UserDoc().activePresentation = getCopy(this.dragFactory,true)`, dragFactory: doc.emptyPresentation as Doc }, - { title: "Drag a search box", label: "Query", icon: "search", ignoreClick: true, drag: 'Docs.Create.QueryDocument({ _width: 200, title: "an image of a cat" })' }, - { title: "Drag a scripting box", label: "Script", icon: "terminal", ignoreClick: true, drag: 'Docs.Create.ScriptingDocument(undefined, { _width: 200, _height: 250 title: "untitled script" })' }, - { title: "Drag an import folder", label: "Load", icon: "cloud-upload-alt", ignoreClick: true, drag: 'Docs.Create.DirectoryImportDocument({ title: "Directory Import", _width: 400, _height: 400 })' }, - { title: "Drag a mobile view", label: "Phone", icon: "phone", ignoreClick: true, drag: 'Doc.UserDoc().activeMobile' }, - { title: "Drag an instance of the device collection", label: "Buxton", icon: "globe-asia", ignoreClick: true, drag: 'Docs.Create.Buxton()' }, - // { title: "use pen", icon: "pen-nib", click: 'activatePen(this.activePen.inkPen = sameDocs(this.activePen.inkPen, this) ? undefined : this,2, this.backgroundColor)', backgroundColor: "blue", ischecked: `sameDocs(this.activePen.inkPen, this)`, activePen: doc }, - // { title: "use highlighter", icon: "highlighter", click: 'activateBrush(this.activePen.inkPen = sameDocs(this.activePen.inkPen, this) ? undefined : this,20,this.backgroundColor)', backgroundColor: "yellow", ischecked: `sameDocs(this.activePen.inkPen, this)`, activePen: doc }, - // { title: "use stamp", icon: "stamp", click: 'activateStamp(this.activePen.inkPen = sameDocs(this.activePen.inkPen, this) ? undefined : this)', backgroundColor: "orange", ischecked: `sameDocs(this.activePen.inkPen, this)`, activePen: doc }, - // { title: "use eraser", icon: "eraser", click: 'activateEraser(this.activePen.inkPen = sameDocs(this.activePen.inkPen, this) ? undefined : this);', ischecked: `sameDocs(this.activePen.inkPen, this)`, backgroundColor: "pink", activePen: doc }, - // { title: "use drag", icon: "mouse-pointer", click: 'deactivateInk();this.activePen.inkPen = this;', ischecked: `sameDocs(this.activePen.inkPen, this)`, backgroundColor: "white", activePen: doc }, - { title: "Drag a document previewer", label: "Prev", icon: "expand", click: 'openOnRight(getCopy(this.dragFactory, true))', drag: 'getCopy(this.dragFactory,true)', dragFactory: doc.emptyDocHolder as Doc }, - { title: "Toggle a Calculator REPL", label: "repl", icon: "calculator", click: 'addOverlayWindow("ScriptingRepl", { x: 300, y: 100, width: 200, height: 200, title: "Scripting REPL" })' }, - { title: "Connect a Google Account", label: "Google Account", icon: "external-link-alt", click: 'GoogleAuthenticationManager.Instance.fetchOrGenerateAccessToken(true)' }, - ]; - - } - - // setup the "creator" buttons for the sidebar-- eg. the default set of draggable document creation tools - static async setupCreatorButtons(doc: Doc) { - let alreadyCreatedButtons: string[] = []; - const dragCreatorSet = await Cast(doc.myItemCreators, Doc, null); - if (dragCreatorSet) { - const dragCreators = await Cast(dragCreatorSet.data, listSpec(Doc)); - if (dragCreators) { - const dragDocs = await Promise.all(dragCreators); - alreadyCreatedButtons = dragDocs.map(d => StrCast(d.title)); - } - } - const buttons = CurrentUserUtils.creatorBtnDescriptors(doc).filter(d => !alreadyCreatedButtons?.includes(d.title)); - const creatorBtns = buttons.map(({ title, label, icon, ignoreClick, drag, click, ischecked, activePen, backgroundColor, dragFactory }) => Docs.Create.FontIconDocument({ - _nativeWidth: 100, _nativeHeight: 100, _width: 100, _height: 100, - icon, - title, - label, - ignoreClick, - dropAction: "copy", - onDragStart: drag ? ScriptField.MakeFunction(drag) : undefined, - onClick: click ? ScriptField.MakeScript(click) : undefined, - ischecked: ischecked ? ComputedField.MakeFunction(ischecked) : undefined, - activePen, - backgroundColor, - removeDropProperties: new List(["dropAction"]), - dragFactory, - })); - - if (dragCreatorSet === undefined) { - doc.myItemCreators = new PrefetchProxy(Docs.Create.MasonryDocument(creatorBtns, { - title: "Basic Item Creators", _showTitle: "title", _xMargin: 0, - _autoHeight: true, _width: 500, columnWidth: 35, ignoreClick: true, lockedPosition: true, _chromeStatus: "disabled", - dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }), - })); - } else { - creatorBtns.forEach(nb => Doc.AddDocToList(doc.myItemCreators as Doc, "data", nb)); - } - return doc.myItemCreators as Doc; - } - - static setupMobileButtons(doc: Doc, buttons?: string[]) { - const docProtoData: { title: string, icon: string, drag?: string, ignoreClick?: boolean, click?: string, ischecked?: string, activePen?: Doc, backgroundColor?: string, dragFactory?: Doc }[] = [ - { title: "record", icon: "microphone", ignoreClick: true, click: "FILL" }, - { title: "use pen", icon: "pen-nib", click: 'activatePen(this.activePen.inkPen = sameDocs(this.activePen.inkPen, this) ? undefined : this,2, this.backgroundColor)', backgroundColor: "blue", ischecked: `sameDocs(this.activePen.inkPen, this)`, activePen: doc }, - { title: "use highlighter", icon: "highlighter", click: 'activateBrush(this.activePen.inkPen = sameDocs(this.activePen.inkPen, this) ? undefined : this,20,this.backgroundColor)', backgroundColor: "yellow", ischecked: `sameDocs(this.activePen.inkPen, this)`, activePen: doc }, - { title: "use eraser", icon: "eraser", click: 'activateEraser(this.activePen.inkPen = sameDocs(this.activePen.inkPen, this) ? undefined : this);', ischecked: `sameDocs(this.activePen.inkPen, this)`, backgroundColor: "pink", activePen: doc }, - { title: "use drag", icon: "mouse-pointer", click: 'deactivateInk();this.activePen.inkPen = this;', ischecked: `sameDocs(this.activePen.inkPen, this)`, backgroundColor: "white", activePen: doc }, - // { title: "draw", icon: "pen-nib", click: 'switchMobileView(setupMobileInkingDoc, renderMobileInking, onSwitchMobileInking);', ischecked: `sameDocs(this.activePen.inkPen, this)`, backgroundColor: "red", activePen: doc }, - { title: "upload", icon: "upload", click: 'switchMobileView(setupMobileUploadDoc, renderMobileUpload, onSwitchMobileUpload);', backgroundColor: "orange" }, - // { title: "upload", icon: "upload", click: 'uploadImageMobile();', backgroundColor: "cyan" }, - ]; - return docProtoData.filter(d => !buttons || !buttons.includes(d.title)).map(data => Docs.Create.FontIconDocument({ - _nativeWidth: 100, _nativeHeight: 100, _width: 100, _height: 100, dropAction: data.click ? "copy" : undefined, title: data.title, icon: data.icon, ignoreClick: data.ignoreClick, - onDragStart: data.drag ? ScriptField.MakeFunction(data.drag) : undefined, onClick: data.click ? ScriptField.MakeScript(data.click) : undefined, - ischecked: data.ischecked ? ComputedField.MakeFunction(data.ischecked) : undefined, activePen: data.activePen, - backgroundColor: data.backgroundColor, removeDropProperties: new List(["dropAction"]), dragFactory: data.dragFactory, - })); - } - - static setupThumbButtons(doc: Doc) { - const docProtoData: { title: string, icon: string, drag?: string, ignoreClick?: boolean, pointerDown?: string, pointerUp?: string, ischecked?: string, clipboard?: Doc, activePen?: Doc, backgroundColor?: string, dragFactory?: Doc }[] = [ - { title: "use pen", icon: "pen-nib", pointerUp: "resetPen()", pointerDown: 'setPen(2, this.backgroundColor)', backgroundColor: "blue", ischecked: `sameDocs(this.activePen.inkPen, this)`, activePen: doc }, - { title: "use highlighter", icon: "highlighter", pointerUp: "resetPen()", pointerDown: 'setPen(20, this.backgroundColor)', backgroundColor: "yellow", ischecked: `sameDocs(this.activePen.inkPen, this)`, activePen: doc }, - { title: "notepad", icon: "clipboard", pointerUp: "GestureOverlay.Instance.closeFloatingDoc()", pointerDown: 'GestureOverlay.Instance.openFloatingDoc(this.clipboard)', clipboard: Docs.Create.FreeformDocument([], { _width: 300, _height: 300 }), backgroundColor: "orange", ischecked: `sameDocs(this.activePen.inkPen, this)`, activePen: doc }, - { title: "interpret text", icon: "font", pointerUp: "setToolglass('none')", pointerDown: "setToolglass('inktotext')", backgroundColor: "orange", ischecked: `sameDocs(this.activePen.inkPen, this)`, activePen: doc }, - { title: "ignore gestures", icon: "signature", pointerUp: "setToolglass('none')", pointerDown: "setToolglass('ignoregesture')", backgroundColor: "green", ischecked: `sameDocs(this.activePen.inkPen, this)`, activePen: doc }, - ]; - return docProtoData.map(data => Docs.Create.FontIconDocument({ - _nativeWidth: 10, _nativeHeight: 10, _width: 10, _height: 10, title: data.title, icon: data.icon, - dropAction: data.pointerDown ? "copy" : undefined, ignoreClick: data.ignoreClick, - onDragStart: data.drag ? ScriptField.MakeFunction(data.drag) : undefined, - clipboard: data.clipboard, - onPointerUp: data.pointerUp ? ScriptField.MakeScript(data.pointerUp) : undefined, onPointerDown: data.pointerDown ? ScriptField.MakeScript(data.pointerDown) : undefined, - ischecked: data.ischecked ? ComputedField.MakeFunction(data.ischecked) : undefined, activePen: data.activePen, pointerHack: true, - backgroundColor: data.backgroundColor, removeDropProperties: new List(["dropAction"]), dragFactory: data.dragFactory, - })); - } - - static setupThumbDoc(userDoc: Doc) { - if (!userDoc.thumbDoc) { - const thumbDoc = Docs.Create.LinearDocument(CurrentUserUtils.setupThumbButtons(userDoc), { - _width: 100, _height: 50, ignoreClick: true, lockedPosition: true, _chromeStatus: "disabled", title: "buttons", - _autoHeight: true, _yMargin: 5, linearViewIsExpanded: true, backgroundColor: "white" - }); - thumbDoc.inkToTextDoc = Docs.Create.LinearDocument([], { - _width: 300, _height: 25, _autoHeight: true, _chromeStatus: "disabled", linearViewIsExpanded: true, flexDirection: "column" - }); - userDoc.thumbDoc = thumbDoc; - } - return Cast(userDoc.thumbDoc, Doc); - } - - static setupMobileDoc(userDoc: Doc) { - return userDoc.activeMoble ?? Docs.Create.MasonryDocument(CurrentUserUtils.setupMobileButtons(userDoc), { - columnWidth: 100, ignoreClick: true, lockedPosition: true, _chromeStatus: "disabled", title: "buttons", _autoHeight: true, _yMargin: 5 - }); - } - - static setupMobileInkingDoc(userDoc: Doc) { - return Docs.Create.FreeformDocument([], { title: "Mobile Inking", backgroundColor: "white" }); - } - - static setupMobileUploadDoc(userDoc: Doc) { - // const addButton = Docs.Create.FontIconDocument({ onDragStart: ScriptField.MakeScript('addWebToMobileUpload()'), title: "Add Web Doc to Upload Collection", icon: "plus", backgroundColor: "black" }) - const webDoc = Docs.Create.WebDocument("https://www.britannica.com/biography/Miles-Davis", { - title: "Upload Images From the Web", _chromeStatus: "enabled", lockedPosition: true - }); - const uploadDoc = Docs.Create.StackingDocument([], { - title: "Mobile Upload Collection", backgroundColor: "white", lockedPosition: true - }); - return Docs.Create.StackingDocument([webDoc, uploadDoc], { - _width: screen.width, lockedPosition: true, _chromeStatus: "disabled", title: "Upload", _autoHeight: true, _yMargin: 80, backgroundColor: "lightgray" - }); - } - - // setup the Creator button which will display the creator panel. This panel will include the drag creators and the color picker. - // when clicked, this panel will be displayed in the target container (ie, sidebarContainer) - static async setupToolsBtnPanel(doc: Doc, sidebarContainer: Doc) { - // setup a masonry view of all he creators - const creatorBtns = await CurrentUserUtils.setupCreatorButtons(doc); - const templateBtns = CurrentUserUtils.setupUserTemplateButtons(doc); - - if (doc.myCreators === undefined) { - doc.myCreators = new PrefetchProxy(Docs.Create.StackingDocument([creatorBtns, templateBtns], { - title: "all Creators", _yMargin: 0, _autoHeight: true, _xMargin: 0, - _width: 500, ignoreClick: true, lockedPosition: true, _chromeStatus: "disabled", - })); - } - // setup a color picker - if (doc.myColorPicker === undefined) { - const color = Docs.Create.ColorDocument({ - title: "color picker", _width: 300, dropAction: "alias", forceActive: true, removeDropProperties: new List(["dropAction", "forceActive"]) - }); - doc.myColorPicker = new PrefetchProxy(color); - } - - if (doc["tabs-button-tools"] === undefined) { - doc["tabs-button-tools"] = new PrefetchProxy(Docs.Create.ButtonDocument({ - _width: 35, _height: 25, title: "Tools", _fontSize: 10, - letterSpacing: "0px", textTransform: "unset", borderRounding: "5px 5px 0px 0px", boxShadow: "3px 3px 0px rgb(34, 34, 34)", - sourcePanel: new PrefetchProxy(Docs.Create.StackingDocument([doc.myCreators as Doc, doc.myColorPicker as Doc], { - _width: 500, lockedPosition: true, _chromeStatus: "disabled", title: "tools stack", forceActive: true - })) as any as Doc, - targetContainer: new PrefetchProxy(sidebarContainer) as any as Doc, - onClick: ScriptField.MakeScript("this.targetContainer.proto = this.sourcePanel"), - })); - } - (doc["tabs-button-tools"] as Doc).sourcePanel; // prefetch sourcePanel - return doc["tabs-button-tools"] as Doc; - } - - static setupWorkspaces(doc: Doc) { - // setup workspaces library item - if (doc.myWorkspaces === undefined) { - doc.myWorkspaces = new PrefetchProxy(Docs.Create.TreeDocument([], { - title: "WORKSPACES", _height: 100, forceActive: true, boxShadow: "0 0", lockedPosition: true, - })); - } - const newWorkspace = ScriptField.MakeScript(`createNewWorkspace()`); - (doc.myWorkspaces as Doc).contextMenuScripts = new List([newWorkspace!]); - (doc.myWorkspaces as Doc).contextMenuLabels = new List(["Create New Workspace"]); - - return doc.myWorkspaces as Doc; - } - static setupCatalog(doc: Doc) { - if (doc.myCatalog === undefined) { - doc.myCatalog = new PrefetchProxy(Docs.Create.TreeDocument([], { - title: "CATALOG", _height: 42, forceActive: true, boxShadow: "0 0", treeViewPreventOpen: false, lockedPosition: true, - })); - } - return doc.myCatalog as Doc; - } - static setupRecentlyClosed(doc: Doc) { - // setup Recently Closed library item - if (doc.myRecentlyClosed === undefined) { - doc.myRecentlyClosed = new PrefetchProxy(Docs.Create.TreeDocument([], { - title: "RECENTLY CLOSED", _height: 75, forceActive: true, boxShadow: "0 0", treeViewPreventOpen: true, lockedPosition: true, - })); - } - // this is equivalent to using PrefetchProxies to make sure the recentlyClosed doc is ready - PromiseValue(Cast(doc.myRecentlyClosed, Doc)).then(recent => recent && PromiseValue(recent.data).then(DocListCast)); - const clearAll = ScriptField.MakeScript(`self.data = new List([])`); - (doc.myRecentlyClosed as Doc).contextMenuScripts = new List([clearAll!]); - (doc.myRecentlyClosed as Doc).contextMenuLabels = new List(["Clear All"]); - - return doc.myRecentlyClosed as Doc; - } - // setup the Library button which will display the library panel. This panel includes a collection of workspaces, documents, and recently closed views - static setupLibraryPanel(doc: Doc, sidebarContainer: Doc) { - const workspaces = CurrentUserUtils.setupWorkspaces(doc); - const documents = CurrentUserUtils.setupCatalog(doc); - const recentlyClosed = CurrentUserUtils.setupRecentlyClosed(doc); - - if (doc["tabs-button-library"] === undefined) { - doc["tabs-button-library"] = new PrefetchProxy(Docs.Create.ButtonDocument({ - _width: 50, _height: 25, title: "Library", _fontSize: 10, - letterSpacing: "0px", textTransform: "unset", borderRounding: "5px 5px 0px 0px", boxShadow: "3px 3px 0px rgb(34, 34, 34)", - sourcePanel: new PrefetchProxy(Docs.Create.TreeDocument([workspaces, documents, recentlyClosed, doc], { - title: "Library", _xMargin: 5, _yMargin: 5, _gridGap: 5, forceActive: true, childDropAction: "alias", lockedPosition: true, boxShadow: "0 0", dontRegisterChildViews: true - })) as any as Doc, - targetContainer: new PrefetchProxy(sidebarContainer) as any as Doc, - onClick: ScriptField.MakeScript("this.targetContainer.proto = this.sourcePanel;") - })); - } - return doc["tabs-button-library"] as Doc; - } - - // setup the Search button which will display the search panel. - static setupSearchBtnPanel(doc: Doc, sidebarContainer: Doc) { - if (doc["tabs-button-search"] === undefined) { - doc["tabs-button-search"] = new PrefetchProxy(Docs.Create.ButtonDocument({ - _width: 50, _height: 25, title: "Search", _fontSize: 10, - letterSpacing: "0px", textTransform: "unset", borderRounding: "5px 5px 0px 0px", boxShadow: "3px 3px 0px rgb(34, 34, 34)", - sourcePanel: new PrefetchProxy(Docs.Create.QueryDocument({ title: "search stack", })) as any as Doc, - searchFileTypes: new List([DocumentType.RTF, DocumentType.IMG, DocumentType.PDF, DocumentType.VID, DocumentType.WEB, DocumentType.SCRIPTING]), - targetContainer: new PrefetchProxy(sidebarContainer) as any as Doc, - lockedPosition: true, - onClick: ScriptField.MakeScript("this.targetContainer.proto = this.sourcePanel") - })); - } - return doc["tabs-button-search"] as Doc; - } - - static setupSidebarContainer(doc: Doc) { - if (doc["tabs-panelContainer"] === undefined) { - const sidebarContainer = new Doc(); - sidebarContainer._chromeStatus = "disabled"; - sidebarContainer.onClick = ScriptField.MakeScript("freezeSidebar()"); - doc["tabs-panelContainer"] = new PrefetchProxy(sidebarContainer); - } - return doc["tabs-panelContainer"] as Doc; - } - - // setup the list of sidebar mode buttons which determine what is displayed in the sidebar - static async setupSidebarButtons(doc: Doc) { - const sidebarContainer = CurrentUserUtils.setupSidebarContainer(doc); - const toolsBtn = await CurrentUserUtils.setupToolsBtnPanel(doc, sidebarContainer); - const libraryBtn = CurrentUserUtils.setupLibraryPanel(doc, sidebarContainer); - const searchBtn = CurrentUserUtils.setupSearchBtnPanel(doc, sidebarContainer); - - // Finally, setup the list of buttons to display in the sidebar - if (doc["tabs-buttons"] === undefined) { - doc["tabs-buttons"] = new PrefetchProxy(Docs.Create.StackingDocument([searchBtn, libraryBtn, toolsBtn], { - _width: 500, _height: 80, boxShadow: "0 0", _pivotField: "title", hideHeadings: true, ignoreClick: true, _chromeStatus: "view-mode", - title: "sidebar btn row stack", backgroundColor: "dimGray", - })); - (toolsBtn.onClick as ScriptField).script.run({ this: toolsBtn }); - } - } - - static blist = (opts: DocumentOptions, docs: Doc[]) => new PrefetchProxy(Docs.Create.LinearDocument(docs, { - ...opts, - _gridGap: 5, _xMargin: 5, _yMargin: 5, _height: 42, _width: 100, boxShadow: "0 0", forceActive: true, - dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }), - backgroundColor: "black", treeViewPreventOpen: true, lockedPosition: true, _chromeStatus: "disabled", linearViewIsExpanded: true - })) as any as Doc - - static ficon = (opts: DocumentOptions) => new PrefetchProxy(Docs.Create.FontIconDocument({ - ...opts, - dropAction: "alias", removeDropProperties: new List(["dropAction"]), _nativeWidth: 100, _nativeHeight: 100, _width: 100, _height: 100 - })) as any as Doc - - /// sets up the default list of buttons to be shown in the expanding button menu at the bottom of the Dash window - static setupDockedButtons(doc: Doc) { - if (doc["dockedBtn-pen"] === undefined) { - doc["dockedBtn-pen"] = CurrentUserUtils.ficon({ - onClick: ScriptField.MakeScript("activatePen(this.activePen.inkPen = sameDocs(this.activePen.inkPen, this) ? undefined : this,2, this.backgroundColor)"), - author: "systemTemplates", title: "ink mode", icon: "pen-nib", ischecked: ComputedField.MakeFunction(`sameDocs(this.activePen.inkPen, this)`), activePen: doc - }); - } - if (doc["dockedBtn-undo"] === undefined) { - doc["dockedBtn-undo"] = CurrentUserUtils.ficon({ onClick: ScriptField.MakeScript("undo()"), title: "undo button", icon: "undo-alt" }); - } - if (doc["dockedBtn-redo"] === undefined) { - doc["dockedBtn-redo"] = CurrentUserUtils.ficon({ onClick: ScriptField.MakeScript("redo()"), title: "redo button", icon: "redo-alt" }); - } - if (doc.dockedBtns === undefined) { - doc.dockedBtns = CurrentUserUtils.blist({ title: "docked buttons", ignoreClick: true }, [doc["dockedBtn-undo"] as Doc, doc["dockedBtn-redo"] as Doc, doc["dockedBtn-pen"] as Doc]); - } - } - // sets up the default set of documents to be shown in the Overlay layer - static setupOverlays(doc: Doc) { - if (doc.myOverlayDocuments === undefined) { - doc.myOverlayDocuments = new PrefetchProxy(Docs.Create.FreeformDocument([], { title: "overlay documents", backgroundColor: "#aca3a6" })); - } - } - - // the initial presentation Doc to use - static setupDefaultPresentation(doc: Doc) { - if (doc.activePresentation === undefined) { - doc.activePresentation = Docs.Create.PresDocument(new List(), { - title: "Presentation", _viewType: CollectionViewType.Stacking, targetDropAction: "alias", - _LODdisable: true, _chromeStatus: "replaced", _showTitle: "title", boxShadow: "0 0" - }); - } - } - - static setupRightSidebar(doc: Doc) { - if (doc.rightSidebarCollection === undefined) { - doc.rightSidebarCollection = new PrefetchProxy(Docs.Create.StackingDocument([], { title: "Right Sidebar" })); - } - } - - static setupClickEditorTemplates(doc: Doc) { - if (doc["clickFuncs-child"] === undefined) { - const openInTarget = Docs.Create.ScriptingDocument(ScriptField.MakeScript( - "docCast(thisContainer.target).then((target) => {" + - " target && docCast(this.source).then((source) => { " + - " target.proto.data = new List([source || this]); " + - " }); " + - "})", - { target: Doc.name }), { title: "Click to open in target", _width: 300, _height: 200, targetScriptKey: "onChildClick" }); - - const openDetail = Docs.Create.ScriptingDocument(ScriptField.MakeScript( - "openOnRight(self.doubleClickView)", - { target: Doc.name }), { title: "Double click to open doubleClickView", _width: 300, _height: 200, targetScriptKey: "onChildDoubleClick" }); - - doc["clickFuncs-child"] = Docs.Create.TreeDocument([openInTarget, openDetail], { title: "on Child Click function templates" }); - } - // this is equivalent to using PrefetchProxies to make sure all the childClickFuncs have been retrieved. - PromiseValue(Cast(doc["clickFuncs-child"], Doc)).then(func => func && PromiseValue(func.data).then(DocListCast)); - - if (doc.clickFuncs === undefined) { - const onClick = Docs.Create.ScriptingDocument(undefined, { - title: "onClick", "onClick-rawScript": "console.log('click')", - isTemplateDoc: true, isTemplateForField: "onClick", _width: 300, _height: 200 - }, "onClick"); - const onDoubleClick = Docs.Create.ScriptingDocument(undefined, { - title: "onDoubleClick", "onDoubleClick-rawScript": "console.log('double click')", - isTemplateDoc: true, isTemplateForField: "onDoubleClick", _width: 300, _height: 200 - }, "onDoubleClick"); - const onCheckedClick = Docs.Create.ScriptingDocument(undefined, { - title: "onCheckedClick", "onCheckedClick-rawScript": "console.log(heading + checked + containingTreeView)", "onCheckedClick-params": new List(["heading", "checked", "containingTreeView"]), isTemplateDoc: true, isTemplateForField: "onCheckedClick", _width: 300, _height: 200 - }, "onCheckedClick"); - doc.clickFuncs = Docs.Create.TreeDocument([onClick, onDoubleClick, onCheckedClick], { title: "onClick funcs" }); - } - PromiseValue(Cast(doc.clickFuncs, Doc)).then(func => func && PromiseValue(func.data).then(DocListCast)); - - return doc.clickFuncs as Doc; - } - - static async updateUserDocument(doc: Doc) { - new InkingControl(); - doc.title = Doc.CurrentUserEmail; - doc.activePen = doc; - doc.inkColor = StrCast(doc.backgroundColor, ""); - doc.fontSize = NumCast(doc.fontSize, 12); - doc["constants-snapThreshold"] = NumCast(doc["constants-snapThreshold"], 10); // - doc["constants-dragThreshold"] = NumCast(doc["constants-dragThreshold"], 4); // - Utils.DRAG_THRESHOLD = NumCast(doc["constants-dragThreshold"]); - this.setupDefaultIconTemplates(doc); // creates a set of icon templates triggered by the document deoration icon - this.setupDocTemplates(doc); // sets up the template menu of templates - this.setupRightSidebar(doc); // sets up the right sidebar collection for mobile upload documents and sharing - this.setupOverlays(doc); // documents in overlay layer - this.setupDockedButtons(doc); // the bottom bar of font icons - this.setupDefaultPresentation(doc); // presentation that's initially triggered - await this.setupSidebarButtons(doc); // the pop-out left sidebar of tools/panels - doc.globalLinkDatabase = Docs.Prototypes.MainLinkDocument(); - - // setup reactions to change the highlights on the undo/redo buttons -- would be better to encode this in the undo/redo buttons, but the undo/redo stacks are not wired up that way yet - doc["dockedBtn-undo"] && reaction(() => UndoManager.undoStack.slice(), () => Doc.GetProto(doc["dockedBtn-undo"] as Doc).opacity = UndoManager.CanUndo() ? 1 : 0.4, { fireImmediately: true }); - doc["dockedBtn-redo"] && reaction(() => UndoManager.redoStack.slice(), () => Doc.GetProto(doc["dockedBtn-redo"] as Doc).opacity = UndoManager.CanRedo() ? 1 : 0.4, { fireImmediately: true }); - - return doc; - } - public static async loadCurrentUser() { - return rp.get(Utils.prepend("/getCurrentUser")).then(response => { - if (response) { - const result: { id: string, email: string } = JSON.parse(response); - return result; - } else { - throw new Error("There should be a user! Why does Dash think there isn't one?"); - } - }); - } - - public static async loadUserDocument({ id, email }: { id: string, email: string }) { - this.curr_id = id; - Doc.CurrentUserEmail = email; - await rp.get(Utils.prepend("/getUserDocumentId")).then(id => { - if (id && id !== "guest") { - return DocServer.GetRefField(id).then(async field => - Doc.SetUserDoc(await this.updateUserDocument(field instanceof Doc ? field : new Doc(id, true)))); - } else { - throw new Error("There should be a user id! Why does Dash think there isn't one?"); - } - }); - } -} - -Scripting.addGlobal(function setupMobileInkingDoc(userDoc: Doc) { return CurrentUserUtils.setupMobileInkingDoc(userDoc); }); -Scripting.addGlobal(function setupMobileUploadDoc(userDoc: Doc) { return CurrentUserUtils.setupMobileUploadDoc(userDoc); }); -Scripting.addGlobal(function createNewWorkspace() { return MainView.Instance.createNewWorkspace(); }); \ No newline at end of file diff --git a/src/server/authentication/models/user_model.ts b/src/server/authentication/models/user_model.ts deleted file mode 100644 index a0b688328..000000000 --- a/src/server/authentication/models/user_model.ts +++ /dev/null @@ -1,86 +0,0 @@ -//@ts-ignore -import * as bcrypt from "bcrypt-nodejs"; -//@ts-ignore -import * as mongoose from 'mongoose'; - -export type DashUserModel = mongoose.Document & { - email: String, - password: string, - passwordResetToken?: string, - passwordResetExpires?: Date, - - userDocumentId: string; - - profile: { - name: string, - gender: string, - location: string, - website: string, - picture: string - }, - - comparePassword: comparePasswordFunction, -}; - -type comparePasswordFunction = (candidatePassword: string, cb: (err: any, isMatch: any) => {}) => void; - -export type AuthToken = { - accessToken: string, - kind: string -}; - -const userSchema = new mongoose.Schema({ - email: String, - password: String, - passwordResetToken: String, - passwordResetExpires: Date, - - userDocumentId: String, - - facebook: String, - twitter: String, - google: String, - - profile: { - name: String, - gender: String, - location: String, - website: String, - picture: String - } -}, { timestamps: true }); - -/** - * Password hash middleware. - */ -userSchema.pre("save", function save(next) { - const user = this as DashUserModel; - if (!user.isModified("password")) { - return next(); - } - bcrypt.genSalt(10, (err, salt) => { - if (err) { - return next(err); - } - bcrypt.hash(user.password, salt, () => void {}, (err: mongoose.Error, hash) => { - if (err) { - return next(err); - } - user.password = hash; - next(); - }); - }); -}); - -const comparePassword: comparePasswordFunction = function (this: DashUserModel, candidatePassword, cb) { - // Choose one of the following bodies for authentication logic. - // secure (expected, default) - bcrypt.compare(candidatePassword, this.password, cb); - // bypass password (debugging) - // cb(undefined, true); -}; - -userSchema.methods.comparePassword = comparePassword; - -const User = mongoose.model("User", userSchema); -export default User; \ No newline at end of file diff --git a/src/server/credentials/CredentialsLoader.ts b/src/server/credentials/CredentialsLoader.ts deleted file mode 100644 index e3f4d167b..000000000 --- a/src/server/credentials/CredentialsLoader.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { readFile } from "fs"; - -export namespace GoogleCredentialsLoader { - - export interface InstalledCredentials { - client_id: string; - project_id: string; - auth_uri: string; - token_uri: string; - auth_provider_x509_cert_url: string; - client_secret: string; - redirect_uris: string[]; - } - - export let ProjectCredentials: InstalledCredentials; - - export async function loadCredentials() { - ProjectCredentials = await new Promise(resolve => { - readFile(__dirname + '/google_project_credentials.json', function processClientSecrets(err, content) { - if (err) { - console.log('Error loading client secret file: ' + err); - return; - } - resolve(JSON.parse(content.toString()).installed); - }); - }); - } - -} diff --git a/src/server/credentials/google_project_credentials.json b/src/server/credentials/google_project_credentials.json deleted file mode 100644 index 955c5a3c1..000000000 --- a/src/server/credentials/google_project_credentials.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "installed": { - "client_id": "343179513178-ud6tvmh275r2fq93u9eesrnc66t6akh9.apps.googleusercontent.com", - "project_id": "quickstart-1565056383187", - "auth_uri": "https://accounts.google.com/o/oauth2/auth", - "token_uri": "https://oauth2.googleapis.com/token", - "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", - "client_secret": "w8KIFSc0MQpmUYHed4qEzn8b", - "redirect_uris": ["urn:ietf:wg:oauth:2.0:oob", "http://localhost"] - } -} \ No newline at end of file diff --git a/src/server/database.ts b/src/server/database.ts index 580f7f919..ed9a246e3 100644 --- a/src/server/database.ts +++ b/src/server/database.ts @@ -293,13 +293,26 @@ export namespace Database { export const Instance = getDatabase(); + /** + * Provides definitions and apis for working with + * portions of the database not dedicated to storing documents + * or Dash-internal user data. + */ export namespace Auxiliary { + /** + * All the auxiliary MongoDB collections (schemas) + */ export enum AuxiliaryCollections { GooglePhotosUploadHistory = "uploadedFromGooglePhotos", - GoogleAuthentication = "googleAuthentication" + GoogleAccess = "googleAuthentication" } + /** + * Searches for the @param query in the specified @param collection, + * and returns at most the first @param cap results. If @param removeId is true, + * as it is by default, each object will be stripped of its database id. + */ const SanitizedCappedQuery = async (query: { [key: string]: any }, collection: string, cap: number, removeId = true) => { const cursor = await Instance.query(query, undefined, collection); const results = await cursor.toArray(); @@ -310,52 +323,89 @@ export namespace Database { }) : slice; }; + /** + * Searches for the @param query in the specified @param collection, + * and returns at most the first result. If @param removeId is true, + * as it is by default, each object will be stripped of its database id. + * Worth the special case since it converts the Array return type to a single + * object of the specified type. + */ const SanitizedSingletonQuery = async (query: { [key: string]: any }, collection: string, removeId = true): Promise> => { const results = await SanitizedCappedQuery(query, collection, 1, removeId); return results.length ? results[0] : undefined; }; + /** + * Checks to see if an image with the given @param contentSize + * already exists in the aux database, i.e. has already been downloaded from Google Photos. + */ export const QueryUploadHistory = async (contentSize: number) => { return SanitizedSingletonQuery({ contentSize }, AuxiliaryCollections.GooglePhotosUploadHistory); }; - export namespace GoogleAuthenticationToken { + /** + * Records the uploading of the image with the given @param information, + * using the given content size as a seed for the database id. + */ + export const LogUpload = async (information: Upload.ImageInformation) => { + const bundle = { + _id: Utils.GenerateDeterministicGuid(String(information.contentSize)), + ...information + }; + return Instance.insert(bundle, AuxiliaryCollections.GooglePhotosUploadHistory); + }; + + /** + * Manages the storage, retrieval and updating of the access token that + * facilitates interactions with all their APIs for a given account. + */ + export namespace GoogleAccessToken { + /** + * Format stored in database. + */ type StoredCredentials = GoogleApiServerUtils.EnrichedCredentials & { _id: string }; + /** + * Retrieves the credentials associaed with @param userId + * and optionally removes their database id according to @param removeId. + */ export const Fetch = async (userId: string, removeId = true): Promise> => { - return SanitizedSingletonQuery({ userId }, AuxiliaryCollections.GoogleAuthentication, removeId); + return SanitizedSingletonQuery({ userId }, AuxiliaryCollections.GoogleAccess, removeId); }; + /** + * Writes the @param enrichedCredentials to the database, associated + * with @param userId for later retrieval and updating. + */ export const Write = async (userId: string, enrichedCredentials: GoogleApiServerUtils.EnrichedCredentials) => { - return Instance.insert({ userId, canAccess: [], ...enrichedCredentials }, AuxiliaryCollections.GoogleAuthentication); + return Instance.insert({ userId, canAccess: [], ...enrichedCredentials }, AuxiliaryCollections.GoogleAccess); }; + /** + * Updates the @param access_token and @param expiry_date fields + * in the stored credentials associated with @param userId. + */ export const Update = async (userId: string, access_token: string, expiry_date: number) => { const entry = await Fetch(userId, false); if (entry) { const parameters = { $set: { access_token, expiry_date } }; - return Instance.update(entry._id, parameters, emptyFunction, true, AuxiliaryCollections.GoogleAuthentication); + return Instance.update(entry._id, parameters, emptyFunction, true, AuxiliaryCollections.GoogleAccess); } }; + /** + * Revokes the credentials associated with @param userId. + */ export const Revoke = async (userId: string) => { const entry = await Fetch(userId, false); if (entry) { - Instance.delete({ _id: entry._id }, AuxiliaryCollections.GoogleAuthentication); + Instance.delete({ _id: entry._id }, AuxiliaryCollections.GoogleAccess); } }; } - export const LogUpload = async (information: Upload.ImageInformation) => { - const bundle = { - _id: Utils.GenerateDeterministicGuid(String(information.contentSize)), - ...information - }; - return Instance.insert(bundle, AuxiliaryCollections.GooglePhotosUploadHistory); - }; - } } diff --git a/src/server/index.ts b/src/server/index.ts index f26c8a6ab..af8f95a5e 100644 --- a/src/server/index.ts +++ b/src/server/index.ts @@ -11,9 +11,9 @@ import * as qs from 'query-string'; import UtilManager from './ApiManagers/UtilManager'; import { SearchManager } from './ApiManagers/SearchManager'; import UserManager from './ApiManagers/UserManager'; -import { WebSocket } from './Websocket/Websocket'; +import { WebSocket } from './websocket'; import DownloadManager from './ApiManagers/DownloadManager'; -import { GoogleCredentialsLoader } from './credentials/CredentialsLoader'; +import { GoogleCredentialsLoader } from './apis/google/CredentialsLoader'; import DeleteManager from "./ApiManagers/DeleteManager"; import PDFManager from "./ApiManagers/PDFManager"; import UploadManager from "./ApiManagers/UploadManager"; @@ -25,7 +25,6 @@ import { yellow } from "colors"; import { DashSessionAgent } from "./DashSession/DashSessionAgent"; import SessionManager from "./ApiManagers/SessionManager"; import { AppliedSessionAgent } from "./DashSession/Session/agents/applied_session_agent"; -import { Utils } from "../Utils"; export const onWindows = process.platform === "win32"; export let sessionAgent: AppliedSessionAgent; @@ -125,7 +124,7 @@ function routeSetter({ isRelease, addSupervisedRoute, logRegistrationOutcome }: // initialize the web socket (bidirectional communication: if a user changes // a field on one client, that change must be broadcast to all other clients) - WebSocket.start(isRelease); + WebSocket.initialize(isRelease); } diff --git a/src/server/server_Initialization.ts b/src/server/server_Initialization.ts index add607761..4b3094616 100644 --- a/src/server/server_Initialization.ts +++ b/src/server/server_Initialization.ts @@ -7,7 +7,7 @@ import * as cookieParser from 'cookie-parser'; import expressFlash = require('express-flash'); import flash = require('connect-flash'); import { Database } from './database'; -import { getForgot, getLogin, getLogout, getReset, getSignup, postForgot, postLogin, postReset, postSignup } from './authentication/controllers/user_controller'; +import { getForgot, getLogin, getLogout, getReset, getSignup, postForgot, postLogin, postReset, postSignup } from './authentication/AuthenticationManager'; const MongoStore = require('connect-mongo')(session); import RouteManager from './RouteManager'; import * as webpack from 'webpack'; @@ -94,6 +94,8 @@ function determineEnvironment() { const label = isRelease ? "release" : "development"; console.log(`\nrunning server in ${color(label)} mode`); + // swilkins: I don't think we need to read from ClientUtils.RELEASE anymore. Should be able to invoke process.env.RELEASE + // on the client side, thanks to dotenv in webpack.config.js let clientUtils = fs.readFileSync("./src/client/util/ClientUtils.ts.temp", "utf8"); clientUtils = `//AUTO-GENERATED FILE: DO NOT EDIT\n${clientUtils.replace('"mode"', String(isRelease))}`; fs.writeFileSync("./src/client/util/ClientUtils.ts", clientUtils, "utf8"); diff --git a/src/server/websocket.ts b/src/server/websocket.ts new file mode 100644 index 000000000..7278bdc32 --- /dev/null +++ b/src/server/websocket.ts @@ -0,0 +1,297 @@ +import { Utils } from "../Utils"; +import { MessageStore, Transferable, Types, Diff, YoutubeQueryInput, YoutubeQueryTypes, GestureContent, MobileInkOverlayContent, UpdateMobileInkOverlayPositionContent, MobileDocumentUploadContent, RoomMessage } from "./Message"; +import { Client } from "./Client"; +import { Socket } from "socket.io"; +import { Database } from "./database"; +import { Search } from "./Search"; +import * as io from 'socket.io'; +import YoutubeApi from "./apis/youtube/youtubeApiSample"; +import { GoogleCredentialsLoader } from "./apis/google/CredentialsLoader"; +import { logPort } from "./ActionUtilities"; +import { timeMap } from "./ApiManagers/UserManager"; +import { green } from "colors"; +import { networkInterfaces } from "os"; +import executeImport from "../scraping/buxton/final/BuxtonImporter"; +import { DocumentsCollection } from "./IDatabase"; + +export namespace WebSocket { + + export let _socket: Socket; + const clients: { [key: string]: Client } = {}; + export const socketMap = new Map(); + export let disconnect: Function; + + export function initialize(isRelease: boolean) { + const endpoint = io(); + endpoint.on("connection", function (socket: Socket) { + _socket = socket; + + socket.use((_packet, next) => { + const userEmail = socketMap.get(socket); + if (userEmail) { + timeMap[userEmail] = Date.now(); + } + next(); + }); + + // convenience function to log server messages on the client + function log(message?: any, ...optionalParams: any[]) { + socket.emit('log', ['Message from server:', message, ...optionalParams]); + } + + socket.on('message', function (message, room) { + console.log('Client said: ', message); + socket.in(room).emit('message', message); + }); + + socket.on('create or join', function (room) { + console.log('Received request to create or join room ' + room); + + const clientsInRoom = socket.adapter.rooms[room]; + const numClients = clientsInRoom ? Object.keys(clientsInRoom.sockets).length : 0; + console.log('Room ' + room + ' now has ' + numClients + ' client(s)'); + + if (numClients === 0) { + socket.join(room); + console.log('Client ID ' + socket.id + ' created room ' + room); + socket.emit('created', room, socket.id); + + } else if (numClients === 1) { + console.log('Client ID ' + socket.id + ' joined room ' + room); + socket.in(room).emit('join', room); + socket.join(room); + socket.emit('joined', room, socket.id); + socket.in(room).emit('ready'); + } else { // max two clients + socket.emit('full', room); + } + }); + + socket.on('ipaddr', function () { + const ifaces = networkInterfaces(); + for (const dev in ifaces) { + ifaces[dev].forEach(function (details) { + if (details.family === 'IPv4' && details.address !== '127.0.0.1') { + socket.emit('ipaddr', details.address); + } + }); + } + }); + + socket.on('bye', function () { + console.log('received bye'); + }); + + Utils.Emit(socket, MessageStore.Foo, "handshooken"); + + Utils.AddServerHandler(socket, MessageStore.Bar, guid => barReceived(socket, guid)); + Utils.AddServerHandler(socket, MessageStore.SetField, (args) => setField(socket, args)); + Utils.AddServerHandlerCallback(socket, MessageStore.GetField, getField); + Utils.AddServerHandlerCallback(socket, MessageStore.GetFields, getFields); + if (isRelease) { + Utils.AddServerHandler(socket, MessageStore.DeleteAll, () => doDelete(false)); + } + + Utils.AddServerHandler(socket, MessageStore.CreateField, CreateField); + Utils.AddServerHandlerCallback(socket, MessageStore.YoutubeApiQuery, HandleYoutubeQuery); + Utils.AddServerHandler(socket, MessageStore.UpdateField, diff => UpdateField(socket, diff)); + Utils.AddServerHandler(socket, MessageStore.DeleteField, id => DeleteField(socket, id)); + Utils.AddServerHandler(socket, MessageStore.DeleteFields, ids => DeleteFields(socket, ids)); + Utils.AddServerHandler(socket, MessageStore.GesturePoints, content => processGesturePoints(socket, content)); + Utils.AddServerHandler(socket, MessageStore.MobileInkOverlayTrigger, content => processOverlayTrigger(socket, content)); + Utils.AddServerHandler(socket, MessageStore.UpdateMobileInkOverlayPosition, content => processUpdateOverlayPosition(socket, content)); + Utils.AddServerHandler(socket, MessageStore.MobileDocumentUpload, content => processMobileDocumentUpload(socket, content)); + Utils.AddServerHandlerCallback(socket, MessageStore.GetRefField, GetRefField); + Utils.AddServerHandlerCallback(socket, MessageStore.GetRefFields, GetRefFields); + + /** + * Whenever we receive the go-ahead, invoke the import script and pass in + * as an emitter and a terminator the functions that simply broadcast a result + * or indicate termination to the client via the web socket + */ + Utils.AddServerHandler(socket, MessageStore.BeginBuxtonImport, () => { + executeImport( + deviceOrError => Utils.Emit(socket, MessageStore.BuxtonDocumentResult, deviceOrError), + results => Utils.Emit(socket, MessageStore.BuxtonImportComplete, results) + ); + }); + + disconnect = () => { + socket.broadcast.emit("connection_terminated", Date.now()); + socket.disconnect(true); + }; + }); + + const socketPort = isRelease ? Number(process.env.socketPort) : 4321; + endpoint.listen(socketPort); + logPort("websocket", socketPort); + } + + function processGesturePoints(socket: Socket, content: GestureContent) { + socket.broadcast.emit("receiveGesturePoints", content); + } + + function processOverlayTrigger(socket: Socket, content: MobileInkOverlayContent) { + socket.broadcast.emit("receiveOverlayTrigger", content); + } + + function processUpdateOverlayPosition(socket: Socket, content: UpdateMobileInkOverlayPositionContent) { + socket.broadcast.emit("receiveUpdateOverlayPosition", content); + } + + function processMobileDocumentUpload(socket: Socket, content: MobileDocumentUploadContent) { + socket.broadcast.emit("receiveMobileDocumentUpload", content); + } + + function HandleYoutubeQuery([query, callback]: [YoutubeQueryInput, (result?: any[]) => void]) { + const { ProjectCredentials } = GoogleCredentialsLoader; + switch (query.type) { + case YoutubeQueryTypes.Channels: + YoutubeApi.authorizedGetChannel(ProjectCredentials); + break; + case YoutubeQueryTypes.SearchVideo: + YoutubeApi.authorizedGetVideos(ProjectCredentials, query.userInput, callback); + case YoutubeQueryTypes.VideoDetails: + YoutubeApi.authorizedGetVideoDetails(ProjectCredentials, query.videoIds, callback); + } + } + + export async function doDelete(onlyFields = true) { + const target: string[] = []; + onlyFields && target.push(DocumentsCollection); + await Database.Instance.dropSchema(...target); + if (process.env.DISABLE_SEARCH !== "true") { + await Search.clear(); + } + } + + function barReceived(socket: SocketIO.Socket, userEmail: string) { + clients[userEmail] = new Client(userEmail.toString()); + console.log(green(`user ${userEmail} has connected to the web socket`)); + socketMap.set(socket, userEmail); + } + + function getField([id, callback]: [string, (result?: Transferable) => void]) { + Database.Instance.getDocument(id, (result?: Transferable) => + callback(result ? result : undefined)); + } + + function getFields([ids, callback]: [string[], (result: Transferable[]) => void]) { + Database.Instance.getDocuments(ids, callback); + } + + function setField(socket: Socket, newValue: Transferable) { + Database.Instance.update(newValue.id, newValue, () => + socket.broadcast.emit(MessageStore.SetField.Message, newValue)); + if (newValue.type === Types.Text) { // if the newValue has sring type, then it's suitable for searching -- pass it to SOLR + Search.updateDocument({ id: newValue.id, data: (newValue as any).data }); + } + } + + function GetRefField([id, callback]: [string, (result?: Transferable) => void]) { + Database.Instance.getDocument(id, callback); + } + + function GetRefFields([ids, callback]: [string[], (result?: Transferable[]) => void]) { + Database.Instance.getDocuments(ids, callback); + } + + const suffixMap: { [type: string]: (string | [string, string | ((json: any) => any)]) } = { + "number": "_n", + "string": "_t", + "boolean": "_b", + "image": ["_t", "url"], + "video": ["_t", "url"], + "pdf": ["_t", "url"], + "audio": ["_t", "url"], + "web": ["_t", "url"], + "script": ["_t", value => value.script.originalScript], + "RichTextField": ["_t", value => value.Text], + "date": ["_d", value => new Date(value.date).toISOString()], + "proxy": ["_i", "fieldId"], + "list": ["_l", list => { + const results = []; + for (const value of list.fields) { + const term = ToSearchTerm(value); + if (term) { + results.push(term.value); + } + } + return results.length ? results : null; + }] + }; + + function ToSearchTerm(val: any): { suffix: string, value: any } | undefined { + if (val === null || val === undefined) { + return; + } + const type = val.__type || typeof val; + let suffix = suffixMap[type]; + if (!suffix) { + return; + } + + if (Array.isArray(suffix)) { + const accessor = suffix[1]; + if (typeof accessor === "function") { + val = accessor(val); + } else { + val = val[accessor]; + } + suffix = suffix[0]; + } + + return { suffix, value: val }; + } + + function getSuffix(value: string | [string, any]): string { + return typeof value === "string" ? value : value[0]; + } + + function UpdateField(socket: Socket, diff: Diff) { + Database.Instance.update(diff.id, diff.diff, + () => socket.broadcast.emit(MessageStore.UpdateField.Message, diff), false); + const docfield = diff.diff.$set || diff.diff.$unset; + if (!docfield) { + return; + } + const update: any = { id: diff.id }; + let dynfield = false; + for (let key in docfield) { + if (!key.startsWith("fields.")) continue; + dynfield = true; + const val = docfield[key]; + key = key.substring(7); + Object.values(suffixMap).forEach(suf => update[key + getSuffix(suf)] = { set: null }); + const term = ToSearchTerm(val); + if (term !== undefined) { + const { suffix, value } = term; + update[key + suffix] = { set: value }; + } + } + if (dynfield) { + Search.updateDocument(update); + } + } + + function DeleteField(socket: Socket, id: string) { + Database.Instance.delete({ _id: id }).then(() => { + socket.broadcast.emit(MessageStore.DeleteField.Message, id); + }); + + Search.deleteDocuments([id]); + } + + function DeleteFields(socket: Socket, ids: string[]) { + Database.Instance.delete({ _id: { $in: ids } }).then(() => { + socket.broadcast.emit(MessageStore.DeleteFields.Message, ids); + }); + Search.deleteDocuments(ids); + } + + function CreateField(newValue: any) { + Database.Instance.insert(newValue); + } + +} + diff --git a/webpack.config.js b/webpack.config.js index 6265883fd..67d492e1f 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -16,22 +16,21 @@ const plugins = [ new webpack.HotModuleReplacementPlugin(), ]; -const dotenv = require('dotenv'); - -function transferEnvironmentVariables() { +(function transferEnvironmentVariables() { const prefix = "_CLIENT_"; - const env = dotenv.config().parsed; - if (env) { - plugins.push(new webpack.DefinePlugin(Object.keys(env).reduce((mapping, envKey) => { - if (envKey.startsWith(prefix)) { - mapping[`process.env.${envKey.replace(prefix, "")}`] = JSON.stringify(env[envKey]); - } - return mapping; - }, {}))); + const { + parsed + } = require('dotenv').config(); + if (!parsed) { + return; } -} - -transferEnvironmentVariables(); + plugins.push(new webpack.DefinePlugin(Object.keys(parsed).reduce((mapping, envKey) => { + if (envKey.startsWith(prefix)) { + mapping[`process.env.${envKey.replace(prefix, "")}`] = JSON.stringify(parsed[envKey]); + } + return mapping; + }, {}))); +})(); module.exports = { mode: 'development', -- cgit v1.2.3-70-g09d2 From f6a55c0d613787f60e4a40b728a1acbc6c39c552 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Thu, 14 May 2020 16:33:40 -0400 Subject: added setter scripts for fields. fixed color selection --- src/client/views/InkingControl.tsx | 2 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 1 + src/new_fields/ScriptField.ts | 30 +++++++++++++++++----- src/new_fields/util.ts | 5 ++++ 4 files changed, 30 insertions(+), 8 deletions(-) (limited to 'src/client/views/collections') diff --git a/src/client/views/InkingControl.tsx b/src/client/views/InkingControl.tsx index 81d99e009..7bea69fb1 100644 --- a/src/client/views/InkingControl.tsx +++ b/src/client/views/InkingControl.tsx @@ -35,7 +35,7 @@ export class InkingControl { @undoBatch switchColor = action((color: ColorState): void => { Doc.UserDoc().backgroundColor = color.hex.startsWith("#") ? - color.hex + (color.rgb.a !== undefined ? this.decimalToHexString(Math.round(color.rgb.a * 255)) : "ff") : color.hex; + color.hex + (color.rgb.a ? this.decimalToHexString(Math.round(color.rgb.a * 255)) : "ff") : color.hex; if (InkingControl.Instance.selectedTool === InkTool.None) { const selected = SelectionManager.SelectedDocuments(); diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index cfa1a046f..6c4660c39 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -945,6 +945,7 @@ export class CollectionFreeFormView extends CollectionSubView; - constructor(script: CompiledScript) { + constructor(script: CompiledScript, setterscript?: CompileResult) { super(); - if (script && script.options.capturedVariables) { + if (script?.options.capturedVariables) { const doc = Doc.assign(new Doc, script.options.capturedVariables); this.captures = new ProxyField(doc); } - + this.setterscript = setterscript?.compiled ? setterscript : undefined; this.script = script; } @@ -136,13 +138,27 @@ export class ComputedField extends ScriptField { //TODO maybe add an observable cache based on what is passed in for doc, considering there shouldn't really be that many possible values for doc value = computedFn((doc: Doc) => this._valueOutsideReaction(doc)); _valueOutsideReaction = (doc: Doc) => this._lastComputedResult = this.script.run({ this: doc, self: Cast(doc.rootDocument, Doc, null) || doc, _last_: this._lastComputedResult }, console.log).result; + + + constructor(script: CompiledScript, setterscript?: CompiledScript) { + super(script, + !setterscript && script?.originalScript.includes("self.timecode") ? + ScriptField.CompileScript("self['x' + self.timecode] = value", { value: "any" }, true) : setterscript); + } + public static MakeScript(script: string, params: object = {}) { const compiled = ScriptField.CompileScript(script, params, false); return compiled.compiled ? new ComputedField(compiled) : undefined; } - public static MakeFunction(script: string, params: object = {}, capturedVariables?: { [name: string]: Field }) { + public static MakeFunction(script: string, params: object = {}, capturedVariables?: { [name: string]: Field }, setterScript?: string) { const compiled = ScriptField.CompileScript(script, params, true, capturedVariables); - return compiled.compiled ? new ComputedField(compiled) : undefined; + const setCompiled = setterScript ? ScriptField.CompileScript(setterScript, params, true, capturedVariables) : undefined; + return compiled.compiled ? new ComputedField(compiled, setCompiled?.compiled ? setCompiled : undefined) : undefined; + } + public static MakeInterpolated(fieldKey: string, interpolatorKey: string) { + const getField = ScriptField.CompileScript(`(self['${fieldKey}-indexed'])[self.${interpolatorKey}]`, {}, true, {}); + const setField = ScriptField.CompileScript(`(self['${fieldKey}-indexed'])[self.${interpolatorKey}] = value`, { value: "any" }, true, {}); + return getField.compiled ? new ComputedField(getField, setField?.compiled ? setField : undefined) : undefined; } } diff --git a/src/new_fields/util.ts b/src/new_fields/util.ts index 8c719ccd8..a287b0210 100644 --- a/src/new_fields/util.ts +++ b/src/new_fields/util.ts @@ -7,6 +7,8 @@ import { ObjectField } from "./ObjectField"; import { action, trace } from "mobx"; import { Parent, OnUpdate, Update, Id, SelfProxy, Self } from "./FieldSymbols"; import { DocServer } from "../client/DocServer"; +import { ComputedField } from "./ScriptField"; +import { ScriptCast } from "./Types"; function _readOnlySetter(): never { throw new Error("Documents can't be modified in read-only mode"); @@ -114,6 +116,9 @@ export function setter(target: any, in_prop: string | symbol | number, value: an return true; } } + if (target.__fields[prop] instanceof ComputedField && target.__fields[prop].setterscript) { + return ScriptCast(target.__fields[prop])?.setterscript?.run({ self: target[SelfProxy], this: target[SelfProxy], value }).success ? true : false; + } return _setter(target, prop, value, receiver); } -- cgit v1.2.3-70-g09d2 From e1ba2357ad8afd460fd8a24bff3353b84488b7e8 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Thu, 14 May 2020 19:34:10 -0400 Subject: added frame animation for colelction views. --- src/client/util/DragManager.ts | 10 ++--- src/client/views/DocumentDecorations.tsx | 14 +++--- src/client/views/collections/CollectionMapView.tsx | 2 +- src/client/views/collections/CollectionSubView.tsx | 14 +++--- .../collectionFreeForm/CollectionFreeFormView.tsx | 52 ++++++++++++++++++++-- 5 files changed, 70 insertions(+), 22 deletions(-) (limited to 'src/client/views/collections') diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index d1d7f2a8a..c997cf744 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -263,16 +263,16 @@ export namespace DragManager { const denominator = ((y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1)); if (denominator === 0) return undefined; // Lines are parallel - let ua = ((x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3)) / denominator; + const ua = ((x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3)) / denominator; // let ub = ((x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3)) / denominator; //if (ua < 0 || ua > 1 || ub < 0 || ub > 1) return undefined; // is the intersection along the segments // Return a object with the x and y coordinates of the intersection - let x = x1 + ua * (x2 - x1) - let y = y1 + ua * (y2 - y1) + const x = x1 + ua * (x2 - x1); + const y = y1 + ua * (y2 - y1); const dist = Math.sqrt((dragx - x) * (dragx - x) + (dragy - y) * (dragy - y)); - return { pt: [x, y], dist } - } + return { pt: [x, y], dist }; + }; SnappingManager.vertSnapLines().forEach((xCoord, i) => { const pt = intersect(dragPt[0], dragPt[1], dragPt[0] + snapAspect, dragPt[1] + 1, xCoord, -1, xCoord, 1, dragPt[0], dragPt[1]); if (pt && pt.dist < closest) { diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 313d8be23..481431428 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -266,16 +266,16 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> const fixedAspect = first.layoutDoc._nativeWidth ? NumCast(first.layoutDoc._nativeWidth) / NumCast(first.layoutDoc._nativeHeight) : 0; if (fixedAspect && (this._resizeHdlId === "documentDecorations-bottomRightResizer" || this._resizeHdlId === "documentDecorations-topLeftResizer")) { // need to generalize for bl and tr drag handles const project = (p: number[], a: number[], b: number[]) => { - var atob = [b[0] - a[0], b[1] - a[1]]; - var atop = [p[0] - a[0], p[1] - a[1]]; - var len = atob[0] * atob[0] + atob[1] * atob[1]; - var dot = atop[0] * atob[0] + atop[1] * atob[1]; - var t = dot / len; + const atob = [b[0] - a[0], b[1] - a[1]]; + const atop = [p[0] - a[0], p[1] - a[1]]; + const len = atob[0] * atob[0] + atob[1] * atob[1]; + let dot = atop[0] * atob[0] + atop[1] * atob[1]; + const t = dot / len; dot = (b[0] - a[0]) * (p[1] - a[1]) - (b[1] - a[1]) * (p[0] - a[0]); return [a[0] + atob[0] * t, a[1] + atob[1] * t]; - } + }; const tl = first.props.ScreenToLocalTransform().inverse().transformPoint(0, 0); - const drag = project([e.clientX + this._offX, e.clientY + this._offY], tl, [tl[0] + fixedAspect, tl[1] + 1]) + const drag = project([e.clientX + this._offX, e.clientY + this._offY], tl, [tl[0] + fixedAspect, tl[1] + 1]); thisPt = DragManager.snapDragAspect(drag, fixedAspect); } else { thisPt = DragManager.snapDrag(e, -this._offX, -this._offY, this._offX, this._offY); diff --git a/src/client/views/collections/CollectionMapView.tsx b/src/client/views/collections/CollectionMapView.tsx index 618285293..67a2d9d6a 100644 --- a/src/client/views/collections/CollectionMapView.tsx +++ b/src/client/views/collections/CollectionMapView.tsx @@ -1,4 +1,4 @@ -import { GoogleApiWrapper, Map as GeoMap, MapProps as IMapProps, Marker } from "google-maps-react"; +import { GoogleApiWrapper, Map as GeoMap, IMapProps, Marker } from "google-maps-react"; import { observer } from "mobx-react"; import { Doc, Opt, DocListCast, FieldResult, Field } from "../../../new_fields/Doc"; import { documentSchema } from "../../../new_fields/documentSchemas"; diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index bff6d121b..07e94b6ae 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -206,6 +206,8 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T, moreProps?: } } + addDocument = (doc: Doc | Doc[]) => this.props.addDocument(doc); + @undoBatch @action protected onInternalDrop(e: Event, de: DragManager.DropEvent): boolean { @@ -214,21 +216,21 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T, moreProps?: if (docDragData) { let added = false; if (docDragData.dropAction || docDragData.userDropAction) { - added = this.props.addDocument(docDragData.droppedDocuments); + added = this.addDocument(docDragData.droppedDocuments); } else if (docDragData.moveDocument) { const movedDocs = docDragData.droppedDocuments.filter((d, i) => docDragData.draggedDocuments[i] === d); const addedDocs = docDragData.droppedDocuments.filter((d, i) => docDragData.draggedDocuments[i] !== d); - const res = addedDocs.length ? this.props.addDocument(addedDocs) : true; - added = movedDocs.length ? docDragData.moveDocument(movedDocs, this.props.Document, this.props.addDocument) : res; + const res = addedDocs.length ? this.addDocument(addedDocs) : true; + added = movedDocs.length ? docDragData.moveDocument(movedDocs, this.props.Document, this.addDocument) : res; } else { - added = this.props.addDocument(docDragData.droppedDocuments); + added = this.addDocument(docDragData.droppedDocuments); } e.stopPropagation(); return added; } else if (de.complete.annoDragData) { e.stopPropagation(); - return this.props.addDocument(de.complete.annoDragData.dropDocument); + return this.addDocument(de.complete.annoDragData.dropDocument); } return false; } @@ -265,7 +267,7 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T, moreProps?: e.stopPropagation(); e.preventDefault(); - const { addDocument } = this.props; + const { addDocument } = this; if (!addDocument) { alert("this.props.addDocument does not exist. Aborting drop operation."); return; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 6c4660c39..3a55e805e 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -11,11 +11,11 @@ import { InkData, InkField, InkTool, PointData } from "../../../../new_fields/In import { List } from "../../../../new_fields/List"; import { RichTextField } from "../../../../new_fields/RichTextField"; import { createSchema, listSpec, makeInterface } from "../../../../new_fields/Schema"; -import { ScriptField } from "../../../../new_fields/ScriptField"; -import { BoolCast, Cast, FieldValue, NumCast, ScriptCast, StrCast } from "../../../../new_fields/Types"; +import { ScriptField, ComputedField } from "../../../../new_fields/ScriptField"; +import { BoolCast, Cast, FieldValue, NumCast, ScriptCast, StrCast, PromiseValue } from "../../../../new_fields/Types"; import { TraceMobx } from "../../../../new_fields/util"; import { GestureUtils } from "../../../../pen-gestures/GestureUtils"; -import { aggregateBounds, intersectRect, returnOne, Utils, returnZero, returnFalse } from "../../../../Utils"; +import { aggregateBounds, intersectRect, returnOne, Utils, returnZero, returnFalse, numberRange } from "../../../../Utils"; import { CognitiveServices } from "../../../cognitive_services/CognitiveServices"; import { DocServer } from "../../../DocServer"; import { Docs } from "../../../documents/Documents"; @@ -124,6 +124,17 @@ export class CollectionFreeFormView extends CollectionSubView { + const timecode = Cast(this.props.Document.timecode, "number", null); + if (timecode !== undefined) { + ((newBox instanceof Doc) ? [newBox] : newBox).map(doc => { + doc["x-indexed"] = new List(numberRange(timecode + 1).map(i => NumCast(doc.x))); + doc["x-indexed"] = new List(numberRange(timecode + 1).map(i => NumCast(doc.y))); + doc.timecode = ComputedField.MakeFunction("collection.timecode", {}, { collection: this.props.Document }); + doc.x = ComputedField.MakeInterpolated("x", "timecode"); + doc.y = ComputedField.MakeInterpolated("y", "timecode"); + }); + } + if (newBox instanceof Doc) { const added = this.props.addDocument(newBox); added && this.bringToFront(newBox); @@ -1132,6 +1143,39 @@ export class CollectionFreeFormView extends CollectionSubView { + if (this.props.Document.timecode === undefined) { + this.childDocs.map(doc => { + this.props.Document.timecode = 0; + doc["x-indexed"] = new List([NumCast(doc.x)]); + doc["y-indexed"] = new List([NumCast(doc.y)]); + doc.timecode = ComputedField.MakeFunction("collection.timecode", {}, { collection: this.props.Document }); + doc.x = ComputedField.MakeInterpolated("x", "timecode"); + doc.y = ComputedField.MakeInterpolated("y", "timecode"); + }); + } + const timecode = NumCast(this.props.Document.timecode); + this.childDocs.map(doc => { + const xindexed = Cast(doc['x-indexed'], listSpec("number"), null); + const yindexed = Cast(doc['y-indexed'], listSpec("number"), null); + xindexed.length <= timecode && xindexed.push(NumCast(doc.x)); + yindexed.length <= timecode && yindexed.push(NumCast(doc.y)); + }); + this.childDocs.map(doc => doc.transition = "transform 1s"); + this.props.Document.timecode = Math.max(0, timecode + 1); + setTimeout(() => this.childDocs.map(doc => doc.transition = undefined), 1010); + } + @undoBatch + @action + backupInterpolated = (): void => { + this.childDocs.map(doc => doc.transition = "transform 1s"); + this.props.Document.timecode = Math.max(0, NumCast(this.props.Document.timecode) - 1); + setTimeout(() => this.childDocs.map(doc => doc.transition = undefined), 1010); + } + + private thumbIdentifier?: number; onContextMenu = (e: React.MouseEvent) => { @@ -1142,6 +1186,8 @@ export class CollectionFreeFormView extends CollectionSubView Date: Thu, 14 May 2020 17:23:34 -0700 Subject: fixed colorbox and added width slider --- package-lock.json | 44 ++++++++++++++++------ src/client/documents/Documents.ts | 2 +- src/client/util/CurrentUserUtils.ts | 4 +- src/client/util/InteractionUtils.tsx | 8 ++-- src/client/views/GestureOverlay.tsx | 24 ++++++------ src/client/views/InkingControl.tsx | 11 +++--- src/client/views/InkingStroke.tsx | 2 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 3 +- .../collections/collectionFreeForm/MarqueeView.tsx | 14 ++++--- src/client/views/nodes/ColorBox.tsx | 4 ++ 10 files changed, 72 insertions(+), 44 deletions(-) (limited to 'src/client/views/collections') diff --git a/package-lock.json b/package-lock.json index 9ac02f404..e3f7fa018 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2895,7 +2895,8 @@ }, "ansi-regex": { "version": "2.1.1", - "bundled": true + "bundled": true, + "optional": true }, "aproba": { "version": "1.2.0", @@ -2913,11 +2914,13 @@ }, "balanced-match": { "version": "1.0.0", - "bundled": true + "bundled": true, + "optional": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, + "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -2930,15 +2933,18 @@ }, "code-point-at": { "version": "1.1.0", - "bundled": true + "bundled": true, + "optional": true }, "concat-map": { "version": "0.0.1", - "bundled": true + "bundled": true, + "optional": true }, "console-control-strings": { "version": "1.1.0", - "bundled": true + "bundled": true, + "optional": true }, "core-util-is": { "version": "1.0.2", @@ -3041,7 +3047,8 @@ }, "inherits": { "version": "2.0.4", - "bundled": true + "bundled": true, + "optional": true }, "ini": { "version": "1.3.5", @@ -3051,6 +3058,7 @@ "is-fullwidth-code-point": { "version": "1.0.0", "bundled": true, + "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -3063,17 +3071,20 @@ "minimatch": { "version": "3.0.4", "bundled": true, + "optional": true, "requires": { "brace-expansion": "^1.1.7" } }, "minimist": { "version": "1.2.5", - "bundled": true + "bundled": true, + "optional": true }, "minipass": { "version": "2.9.0", "bundled": true, + "optional": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -3090,6 +3101,7 @@ "mkdirp": { "version": "0.5.3", "bundled": true, + "optional": true, "requires": { "minimist": "^1.2.5" } @@ -3145,7 +3157,8 @@ }, "npm-normalize-package-bin": { "version": "1.0.1", - "bundled": true + "bundled": true, + "optional": true }, "npm-packlist": { "version": "1.4.8", @@ -3170,7 +3183,8 @@ }, "number-is-nan": { "version": "1.0.1", - "bundled": true + "bundled": true, + "optional": true }, "object-assign": { "version": "4.1.1", @@ -3180,6 +3194,7 @@ "once": { "version": "1.4.0", "bundled": true, + "optional": true, "requires": { "wrappy": "1" } @@ -3248,7 +3263,8 @@ }, "safe-buffer": { "version": "5.1.2", - "bundled": true + "bundled": true, + "optional": true }, "safer-buffer": { "version": "2.1.2", @@ -3278,6 +3294,7 @@ "string-width": { "version": "1.0.2", "bundled": true, + "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -3295,6 +3312,7 @@ "strip-ansi": { "version": "3.0.1", "bundled": true, + "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -3333,11 +3351,13 @@ }, "wrappy": { "version": "1.0.2", - "bundled": true + "bundled": true, + "optional": true }, "yallist": { "version": "3.1.1", - "bundled": true + "bundled": true, + "optional": true } } } diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 125a531f4..61df9fbd1 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -607,7 +607,7 @@ export namespace Docs { return doc; } - export function InkDocument(color: string, tool: number, strokeWidth: number, points: { X: number, Y: number }[], options: DocumentOptions = {}) { + export function InkDocument(color: string, tool: number, strokeWidth: string, points: { X: number, Y: number }[], options: DocumentOptions = {}) { const I = new Doc(); I.type = DocumentType.INK; I.layout = InkingStroke.LayoutString("data"); diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index b67c3ea60..92fffd512 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -611,7 +611,7 @@ export class CurrentUserUtils { static setupDockedButtons(doc: Doc) { if (doc["dockedBtn-pen"] === undefined) { doc["dockedBtn-pen"] = CurrentUserUtils.ficon({ - onClick: ScriptField.MakeScript("activatePen(this.activePen.inkPen = sameDocs(this.activePen.inkPen, this) ? undefined : this,2, this.backgroundColor)"), + onClick: ScriptField.MakeScript("activatePen(this.activePen.inkPen = sameDocs(this.activePen.inkPen, this) ? undefined : this, this.inkWidth, this.backgroundColor)"), author: "systemTemplates", title: "ink mode", icon: "pen-nib", ischecked: ComputedField.MakeFunction(`sameDocs(this.activePen.inkPen, this)`), activePen: doc }); } @@ -690,7 +690,7 @@ export class CurrentUserUtils { new InkingControl(); doc.title = Doc.CurrentUserEmail; doc.activePen = doc; - doc.inkColor = StrCast(doc.backgroundColor, ""); + doc.inkColor = StrCast(doc.backgroundColor, "rgb(0, 0, 0)"); doc.fontSize = NumCast(doc.fontSize, 12); doc["constants-snapThreshold"] = NumCast(doc["constants-snapThreshold"], 10); // doc["constants-dragThreshold"] = NumCast(doc["constants-dragThreshold"], 4); // diff --git a/src/client/util/InteractionUtils.tsx b/src/client/util/InteractionUtils.tsx index b1f136430..3a5345c80 100644 --- a/src/client/util/InteractionUtils.tsx +++ b/src/client/util/InteractionUtils.tsx @@ -87,15 +87,17 @@ export namespace InteractionUtils { return myTouches; } - export function CreatePolyline(points: { X: number, Y: number }[], left: number, top: number, color: string, width: number) { + export function CreatePolyline(points: { X: number, Y: number }[], left: number, top: number, color: string, width: string) { const pts = points.reduce((acc: string, pt: { X: number, Y: number }) => acc + `${pt.X - left},${pt.Y - top} `, ""); return ( ); diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx index 812ff3b93..b94fcde2d 100644 --- a/src/client/views/GestureOverlay.tsx +++ b/src/client/views/GestureOverlay.tsx @@ -38,10 +38,8 @@ import { SelectionManager } from "../util/SelectionManager"; export default class GestureOverlay extends Touchable { static Instance: GestureOverlay; - @observable public Color: string = "rgb(0, 0, 0)"; - @observable public Width: number = 2; @observable public SavedColor?: string; - @observable public SavedWidth?: number; + @observable public SavedWidth?: string; @observable public Tool: ToolglassTools = ToolglassTools.None; @observable private _thumbX?: number; @@ -711,12 +709,12 @@ export default class GestureOverlay extends Touchable { this._palette, [this._strokes.map(l => { const b = this.getBounds(l); - return - {InteractionUtils.CreatePolyline(l, b.left, b.top, GestureOverlay.Instance.Color, GestureOverlay.Instance.Width)} + return + {InteractionUtils.CreatePolyline(l, b.left, b.top, InkingControl.Instance.selectedColor, InkingControl.Instance.selectedWidth)} ; }), - this._points.length <= 1 ? (null) : - {InteractionUtils.CreatePolyline(this._points, B.left, B.top, GestureOverlay.Instance.Color, GestureOverlay.Instance.Width)} + this._points.length <= 1 ? (null) : + {InteractionUtils.CreatePolyline(this._points, B.left, B.top, InkingControl.Instance.selectedColor, InkingControl.Instance.selectedWidth)} ] ]; } @@ -806,16 +804,16 @@ Scripting.addGlobal(function setToolglass(tool: any) { }); Scripting.addGlobal(function setPen(width: any, color: any) { runInAction(() => { - GestureOverlay.Instance.SavedColor = GestureOverlay.Instance.Color; - GestureOverlay.Instance.Color = color; - GestureOverlay.Instance.SavedWidth = GestureOverlay.Instance.Width; - GestureOverlay.Instance.Width = width; + GestureOverlay.Instance.SavedColor = InkingControl.Instance.selectedColor; + InkingControl.Instance.updateSelectedColor(color); + GestureOverlay.Instance.SavedWidth = InkingControl.Instance.selectedWidth; + InkingControl.Instance.switchWidth(width); }); }); Scripting.addGlobal(function resetPen() { runInAction(() => { - GestureOverlay.Instance.Color = GestureOverlay.Instance.SavedColor ?? "rgb(0, 0, 0)"; - GestureOverlay.Instance.Width = GestureOverlay.Instance.SavedWidth ?? 2; + InkingControl.Instance.updateSelectedColor(GestureOverlay.Instance.SavedColor ?? "rgb(0, 0, 0)"); + InkingControl.Instance.switchWidth(GestureOverlay.Instance.SavedWidth ?? "2"); }); }); Scripting.addGlobal(function createText(text: any, x: any, y: any) { diff --git a/src/client/views/InkingControl.tsx b/src/client/views/InkingControl.tsx index 5115995b0..16ccefa42 100644 --- a/src/client/views/InkingControl.tsx +++ b/src/client/views/InkingControl.tsx @@ -13,8 +13,8 @@ import { FormattedTextBox } from "./nodes/formattedText/FormattedTextBox"; export class InkingControl { @observable static Instance: InkingControl; @computed private get _selectedTool(): InkTool { return FieldValue(NumCast(Doc.UserDoc().inkTool)) ?? InkTool.None; } - @computed private get _selectedColor(): string { return GestureOverlay.Instance.Color ?? FieldValue(StrCast(Doc.UserDoc().inkColor)) ?? "rgb(244, 67, 54)"; } - @computed private get _selectedWidth(): string { return GestureOverlay.Instance.Width?.toString() ?? FieldValue(StrCast(Doc.UserDoc().inkWidth)) ?? "5"; } + @computed private get _selectedColor(): string { return CurrentUserUtils.ActivePen ? FieldValue(StrCast(CurrentUserUtils.ActivePen.backgroundColor)) ?? "rgb(0, 0, 0)" : "rgb(0, 0, 0)"; } + @computed private get _selectedWidth(): string { return FieldValue(StrCast(Doc.UserDoc().inkWidth)) ?? "2"; } @observable public _open: boolean = false; constructor() { @@ -36,6 +36,7 @@ export class InkingControl { switchColor = action((color: ColorState): void => { Doc.UserDoc().backgroundColor = color.hex.startsWith("#") ? color.hex + (color.rgb.a ? this.decimalToHexString(Math.round(color.rgb.a * 255)) : "ff") : color.hex; + CurrentUserUtils.ActivePen && (CurrentUserUtils.ActivePen.backgroundColor = color.hex); if (InkingControl.Instance.selectedTool === InkTool.None) { const selected = SelectionManager.SelectedDocuments(); @@ -51,14 +52,14 @@ export class InkingControl { } } }); - } else { - CurrentUserUtils.ActivePen && (CurrentUserUtils.ActivePen.backgroundColor = this._selectedColor); } }); @action switchWidth = (width: string): void => { // this._selectedWidth = width; - Doc.UserDoc().inkWidth = width; + if (!isNaN(parseInt(width))) { + Doc.UserDoc().inkWidth = width; + } } @computed diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx index 7a318d5c2..98b8371af 100644 --- a/src/client/views/InkingStroke.tsx +++ b/src/client/views/InkingStroke.tsx @@ -40,7 +40,7 @@ export class InkingStroke extends ViewBoxBaseComponent Transform; @@ -164,12 +165,13 @@ export class MarqueeView extends React.Component { this._downX = this._lastX = e.clientX; this._downY = this._lastY = e.clientY; - if (e.button === 2 || (e.button === 0 && (e.altKey || MarqueeView.DragMarquee))) { - if (e.altKey || (MarqueeView.DragMarquee && this.props.active(true))) { - this.setPreviewCursor(e.clientX, e.clientY, true); - // (!e.altKey) && e.stopPropagation(); // bcz: removed so that you can alt-click on button in a collection to switch link following behaviors. - e.preventDefault(); - } + // allow marquee if right click OR alt+left click OR space bar + left click + if (e.button === 2 || (e.button === 0 && (e.altKey || (MarqueeView.DragMarquee && this.props.active(true))))) { + // if (e.altKey || (MarqueeView.DragMarquee && this.props.active(true))) { + this.setPreviewCursor(e.clientX, e.clientY, true); + // (!e.altKey) && e.stopPropagation(); // bcz: removed so that you can alt-click on button in a collection to switch link following behaviors. + e.preventDefault(); + // } // bcz: do we need this? it kills the context menu on the main collection if !altKey // e.stopPropagation(); } diff --git a/src/client/views/nodes/ColorBox.tsx b/src/client/views/nodes/ColorBox.tsx index bc84204b9..f899b6bc8 100644 --- a/src/client/views/nodes/ColorBox.tsx +++ b/src/client/views/nodes/ColorBox.tsx @@ -27,6 +27,10 @@ export class ColorBox extends ViewBoxBaseComponent +
+
{InkingControl.Instance.selectedWidth ?? 2}
+ ) => InkingControl.Instance.switchWidth(e.target.value)} /> +
; } } \ No newline at end of file -- cgit v1.2.3-70-g09d2 From 2b79008596351f6948d8de80c7887446d97b068c Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Fri, 15 May 2020 00:03:41 -0700 Subject: renamed new_fields to fields --- src/client/ClientRecommender.tsx | 16 +- src/client/DocServer.ts | 6 +- src/client/apis/GoogleAuthenticationManager.tsx | 2 +- src/client/apis/IBM_Recommender.ts | 2 +- .../apis/google_docs/GoogleApiClientUtils.ts | 2 +- .../apis/google_docs/GooglePhotosClientUtils.ts | 12 +- src/client/apis/youtube/YoutubeBox.tsx | 4 +- src/client/cognitive_services/CognitiveServices.ts | 8 +- src/client/documents/Documents.ts | 22 +- src/client/util/CurrentUserUtils.ts | 18 +- src/client/util/DictationManager.ts | 12 +- src/client/util/DocumentManager.ts | 6 +- src/client/util/DragManager.ts | 16 +- src/client/util/DropConverter.ts | 12 +- src/client/util/History.ts | 2 +- .../util/Import & Export/DirectoryImportBox.tsx | 12 +- src/client/util/Import & Export/ImageUtils.ts | 8 +- .../util/Import & Export/ImportMetadataEntry.tsx | 4 +- src/client/util/LinkManager.ts | 8 +- src/client/util/Scripting.ts | 2 +- src/client/util/SearchUtil.ts | 4 +- src/client/util/SelectionManager.ts | 4 +- src/client/util/SerializationHelper.ts | 2 +- src/client/util/SharingManager.tsx | 6 +- src/client/views/DocComponent.tsx | 14 +- src/client/views/DocumentButtonBar.tsx | 6 +- src/client/views/DocumentDecorations.tsx | 24 +- src/client/views/EditableView.tsx | 4 +- src/client/views/GestureOverlay.tsx | 12 +- src/client/views/GlobalKeyHandler.ts | 14 +- src/client/views/InkingControl.tsx | 6 +- src/client/views/InkingStroke.tsx | 10 +- src/client/views/MainView.tsx | 14 +- src/client/views/MainViewNotifs.tsx | 2 +- src/client/views/MetadataEntryMenu.tsx | 2 +- src/client/views/OverlayView.tsx | 6 +- src/client/views/Palette.tsx | 4 +- src/client/views/PreviewCursor.tsx | 4 +- src/client/views/RecommendationsBox.tsx | 8 +- src/client/views/ScriptBox.tsx | 6 +- src/client/views/SearchDocBox.tsx | 6 +- src/client/views/TemplateMenu.tsx | 8 +- src/client/views/animationtimeline/Keyframe.tsx | 8 +- src/client/views/animationtimeline/Timeline.tsx | 8 +- src/client/views/animationtimeline/Track.tsx | 12 +- .../views/collections/CollectionCarouselView.tsx | 10 +- .../views/collections/CollectionDockingView.tsx | 29 +- .../views/collections/CollectionLinearView.tsx | 10 +- src/client/views/collections/CollectionMapView.tsx | 10 +- .../collections/CollectionMasonryViewFieldRow.tsx | 8 +- .../views/collections/CollectionPileView.tsx | 6 +- .../views/collections/CollectionSchemaCells.tsx | 8 +- .../views/collections/CollectionSchemaHeaders.tsx | 2 +- .../CollectionSchemaMovableTableHOC.tsx | 6 +- .../views/collections/CollectionSchemaView.tsx | 14 +- .../views/collections/CollectionStackingView.tsx | 16 +- .../CollectionStackingViewFieldColumn.tsx | 16 +- .../views/collections/CollectionStaffView.tsx | 2 +- src/client/views/collections/CollectionSubView.tsx | 14 +- .../views/collections/CollectionTimeView.tsx | 12 +- .../views/collections/CollectionTreeView.tsx | 16 +- src/client/views/collections/CollectionView.tsx | 20 +- .../views/collections/CollectionViewChromes.tsx | 10 +- .../views/collections/ParentDocumentSelector.tsx | 6 +- .../CollectionFreeFormLayoutEngines.tsx | 14 +- .../CollectionFreeFormLinkView.tsx | 6 +- .../CollectionFreeFormLinksView.tsx | 4 +- .../CollectionFreeFormRemoteCursors.tsx | 10 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 23 +- .../collections/collectionFreeForm/MarqueeView.tsx | 12 +- .../CollectionMulticolumnView.tsx | 10 +- .../CollectionMultirowView.tsx | 10 +- .../collectionMulticolumn/MulticolumnResizer.tsx | 4 +- .../MulticolumnWidthLabel.tsx | 4 +- .../collectionMulticolumn/MultirowHeightLabel.tsx | 4 +- .../collectionMulticolumn/MultirowResizer.tsx | 4 +- src/client/views/linking/LinkEditor.tsx | 4 +- src/client/views/linking/LinkMenu.tsx | 2 +- src/client/views/linking/LinkMenuGroup.tsx | 6 +- src/client/views/linking/LinkMenuItem.tsx | 4 +- src/client/views/nodes/AudioBox.tsx | 16 +- .../views/nodes/CollectionFreeFormDocumentView.tsx | 8 +- src/client/views/nodes/ColorBox.tsx | 6 +- .../views/nodes/ContentFittingDocumentView.tsx | 6 +- src/client/views/nodes/DocHolderBox.tsx | 12 +- src/client/views/nodes/DocumentContentsView.tsx | 8 +- src/client/views/nodes/DocumentIcon.tsx | 2 +- src/client/views/nodes/DocumentView.tsx | 20 +- src/client/views/nodes/FaceRectangles.tsx | 6 +- src/client/views/nodes/FieldView.tsx | 10 +- src/client/views/nodes/FontIconBox.tsx | 8 +- src/client/views/nodes/ImageBox.tsx | 20 +- src/client/views/nodes/KeyValueBox.tsx | 14 +- src/client/views/nodes/KeyValuePair.tsx | 2 +- src/client/views/nodes/LabelBox.tsx | 10 +- src/client/views/nodes/LinkAnchorBox.tsx | 10 +- src/client/views/nodes/LinkBox.tsx | 6 +- src/client/views/nodes/PDFBox.tsx | 12 +- src/client/views/nodes/PresBox.tsx | 16 +- src/client/views/nodes/QueryBox.tsx | 10 +- src/client/views/nodes/ScreenshotBox.tsx | 8 +- src/client/views/nodes/ScriptingBox.tsx | 10 +- src/client/views/nodes/SliderBox.tsx | 8 +- src/client/views/nodes/VideoBox.tsx | 16 +- src/client/views/nodes/WebBox.tsx | 14 +- .../nodes/formattedText/DashDocCommentView.tsx | 16 +- .../views/nodes/formattedText/DashDocView.tsx | 10 +- .../views/nodes/formattedText/DashFieldView.tsx | 12 +- .../views/nodes/formattedText/FormattedTextBox.tsx | 24 +- .../formattedText/FormattedTextBoxComment.tsx | 4 +- .../views/nodes/formattedText/ImageResizeView.tsx | 2 +- .../formattedText/ProsemirrorExampleTransfer.ts | 6 +- .../views/nodes/formattedText/RichTextMenu.tsx | 6 +- .../views/nodes/formattedText/RichTextRules.ts | 10 +- .../views/nodes/formattedText/RichTextSchema.tsx | 16 +- src/client/views/nodes/formattedText/marks_rts.ts | 2 +- src/client/views/pdf/Annotation.tsx | 8 +- src/client/views/pdf/PDFMenu.tsx | 2 +- src/client/views/pdf/PDFViewer.tsx | 20 +- .../views/presentationview/PresElementBox.tsx | 10 +- src/client/views/search/FilterBox.tsx | 6 +- src/client/views/search/SearchBox.tsx | 8 +- src/client/views/search/SearchItem.tsx | 6 +- src/debug/Repl.tsx | 6 +- src/debug/Test.tsx | 2 +- src/debug/Viewer.tsx | 16 +- src/fields/CursorField.ts | 66 ++ src/fields/DateField.ts | 36 + src/fields/Doc.ts | 1109 ++++++++++++++++++++ src/fields/FieldSymbols.ts | 12 + src/fields/HtmlField.ts | 26 + src/fields/IconField.ts | 26 + src/fields/InkField.ts | 50 + src/fields/List.ts | 330 ++++++ src/fields/ListSpec.ts | 0 src/fields/ObjectField.ts | 20 + src/fields/PresField.ts | 6 + src/fields/Proxy.ts | 126 +++ src/fields/RefField.ts | 21 + src/fields/RichTextField.ts | 41 + src/fields/RichTextUtils.ts | 519 +++++++++ src/fields/Schema.ts | 120 +++ src/fields/SchemaHeaderField.ts | 122 +++ src/fields/ScriptField.ts | 193 ++++ src/fields/Types.ts | 108 ++ src/fields/URLField.ts | 53 + src/fields/documentSchemas.ts | 100 ++ src/fields/util.ts | 199 ++++ src/mobile/ImageUpload.tsx | 8 +- src/mobile/MobileInkOverlay.tsx | 6 +- src/mobile/MobileInterface.tsx | 12 +- src/new_fields/CursorField.ts | 66 -- src/new_fields/DateField.ts | 36 - src/new_fields/Doc.ts | 1109 -------------------- src/new_fields/FieldSymbols.ts | 12 - src/new_fields/HtmlField.ts | 26 - src/new_fields/IconField.ts | 26 - src/new_fields/InkField.ts | 50 - src/new_fields/List.ts | 330 ------ src/new_fields/ListSpec.ts | 0 src/new_fields/ObjectField.ts | 20 - src/new_fields/PresField.ts | 6 - src/new_fields/Proxy.ts | 126 --- src/new_fields/RefField.ts | 21 - src/new_fields/RichTextField.ts | 41 - src/new_fields/RichTextUtils.ts | 519 --------- src/new_fields/Schema.ts | 120 --- src/new_fields/SchemaHeaderField.ts | 122 --- src/new_fields/ScriptField.ts | 193 ---- src/new_fields/Types.ts | 108 -- src/new_fields/URLField.ts | 53 - src/new_fields/documentSchemas.ts | 100 -- src/new_fields/util.ts | 199 ---- src/pen-gestures/GestureUtils.ts | 6 +- src/server/ApiManagers/GooglePhotosManager.ts | 2 +- src/server/ApiManagers/UserManager.ts | 2 +- src/server/DashUploadUtils.ts | 2 +- src/server/Message.ts | 2 +- src/server/Recommender.ts | 6 +- src/server/apis/google/GoogleApiServerUtils.ts | 2 +- src/server/database.ts | 2 +- test/test.ts | 8 +- 182 files changed, 3889 insertions(+), 3889 deletions(-) create mode 100644 src/fields/CursorField.ts create mode 100644 src/fields/DateField.ts create mode 100644 src/fields/Doc.ts create mode 100644 src/fields/FieldSymbols.ts create mode 100644 src/fields/HtmlField.ts create mode 100644 src/fields/IconField.ts create mode 100644 src/fields/InkField.ts create mode 100644 src/fields/List.ts create mode 100644 src/fields/ListSpec.ts create mode 100644 src/fields/ObjectField.ts create mode 100644 src/fields/PresField.ts create mode 100644 src/fields/Proxy.ts create mode 100644 src/fields/RefField.ts create mode 100644 src/fields/RichTextField.ts create mode 100644 src/fields/RichTextUtils.ts create mode 100644 src/fields/Schema.ts create mode 100644 src/fields/SchemaHeaderField.ts create mode 100644 src/fields/ScriptField.ts create mode 100644 src/fields/Types.ts create mode 100644 src/fields/URLField.ts create mode 100644 src/fields/documentSchemas.ts create mode 100644 src/fields/util.ts delete mode 100644 src/new_fields/CursorField.ts delete mode 100644 src/new_fields/DateField.ts delete mode 100644 src/new_fields/Doc.ts delete mode 100644 src/new_fields/FieldSymbols.ts delete mode 100644 src/new_fields/HtmlField.ts delete mode 100644 src/new_fields/IconField.ts delete mode 100644 src/new_fields/InkField.ts delete mode 100644 src/new_fields/List.ts delete mode 100644 src/new_fields/ListSpec.ts delete mode 100644 src/new_fields/ObjectField.ts delete mode 100644 src/new_fields/PresField.ts delete mode 100644 src/new_fields/Proxy.ts delete mode 100644 src/new_fields/RefField.ts delete mode 100644 src/new_fields/RichTextField.ts delete mode 100644 src/new_fields/RichTextUtils.ts delete mode 100644 src/new_fields/Schema.ts delete mode 100644 src/new_fields/SchemaHeaderField.ts delete mode 100644 src/new_fields/ScriptField.ts delete mode 100644 src/new_fields/Types.ts delete mode 100644 src/new_fields/URLField.ts delete mode 100644 src/new_fields/documentSchemas.ts delete mode 100644 src/new_fields/util.ts (limited to 'src/client/views/collections') diff --git a/src/client/ClientRecommender.tsx b/src/client/ClientRecommender.tsx index 537e331ab..d18669b02 100644 --- a/src/client/ClientRecommender.tsx +++ b/src/client/ClientRecommender.tsx @@ -1,6 +1,6 @@ -import { Doc, FieldResult } from "../new_fields/Doc"; -import { StrCast, Cast } from "../new_fields/Types"; -import { List } from "../new_fields/List"; +import { Doc, FieldResult } from "../fields/Doc"; +import { StrCast, Cast } from "../fields/Types"; +import { List } from "../fields/List"; import { CognitiveServices, Confidence, Tag, Service } from "./cognitive_services/CognitiveServices"; import React = require("react"); import { observer } from "mobx-react"; @@ -11,11 +11,11 @@ import { observable, action, computed, reaction } from "mobx"; // var https = require('https'); import "./ClientRecommender.scss"; import { JSXElement } from "babel-types"; -import { RichTextField } from "../new_fields/RichTextField"; -import { ToPlainText } from "../new_fields/FieldSymbols"; -import { listSpec } from "../new_fields/Schema"; -import { ComputedField } from "../new_fields/ScriptField"; -import { ImageField } from "../new_fields/URLField"; +import { RichTextField } from "../fields/RichTextField"; +import { ToPlainText } from "../fields/FieldSymbols"; +import { listSpec } from "../fields/Schema"; +import { ComputedField } from "../fields/ScriptField"; +import { ImageField } from "../fields/URLField"; import { KeyphraseQueryView } from "./views/KeyphraseQueryView"; import { Networking } from "./Network"; diff --git a/src/client/DocServer.ts b/src/client/DocServer.ts index ae125694b..ac5b7a218 100644 --- a/src/client/DocServer.ts +++ b/src/client/DocServer.ts @@ -1,10 +1,10 @@ import * as OpenSocket from 'socket.io-client'; import { MessageStore, YoutubeQueryTypes, GestureContent, MobileInkOverlayContent, UpdateMobileInkOverlayPositionContent, MobileDocumentUploadContent } from "./../server/Message"; -import { Opt, Doc } from '../new_fields/Doc'; +import { Opt, Doc } from '../fields/Doc'; import { Utils, emptyFunction } from '../Utils'; import { SerializationHelper } from './util/SerializationHelper'; -import { RefField } from '../new_fields/RefField'; -import { Id, HandleUpdate } from '../new_fields/FieldSymbols'; +import { RefField } from '../fields/RefField'; +import { Id, HandleUpdate } from '../fields/FieldSymbols'; import GestureOverlay from './views/GestureOverlay'; import MobileInkOverlay from '../mobile/MobileInkOverlay'; import { runInAction } from 'mobx'; diff --git a/src/client/apis/GoogleAuthenticationManager.tsx b/src/client/apis/GoogleAuthenticationManager.tsx index 22d6fb582..bf4469aeb 100644 --- a/src/client/apis/GoogleAuthenticationManager.tsx +++ b/src/client/apis/GoogleAuthenticationManager.tsx @@ -2,7 +2,7 @@ import { observable, action, reaction, runInAction, IReactionDisposer } from "mo import { observer } from "mobx-react"; import * as React from "react"; import MainViewModal from "../views/MainViewModal"; -import { Opt } from "../../new_fields/Doc"; +import { Opt } from "../../fields/Doc"; import { Networking } from "../Network"; import "./GoogleAuthenticationManager.scss"; import { Scripting } from "../util/Scripting"; diff --git a/src/client/apis/IBM_Recommender.ts b/src/client/apis/IBM_Recommender.ts index 4e1c541c8..480b9cb1c 100644 --- a/src/client/apis/IBM_Recommender.ts +++ b/src/client/apis/IBM_Recommender.ts @@ -1,4 +1,4 @@ -// import { Opt } from "../../new_fields/Doc"; +// import { Opt } from "../../fields/Doc"; // const NaturalLanguageUnderstandingV1 = require('ibm-watson/natural-language-understanding/v1'); // const { IamAuthenticator } = require('ibm-watson/auth'); diff --git a/src/client/apis/google_docs/GoogleApiClientUtils.ts b/src/client/apis/google_docs/GoogleApiClientUtils.ts index 2f3cac8d3..551dca073 100644 --- a/src/client/apis/google_docs/GoogleApiClientUtils.ts +++ b/src/client/apis/google_docs/GoogleApiClientUtils.ts @@ -1,5 +1,5 @@ import { docs_v1 } from "googleapis"; -import { Opt } from "../../../new_fields/Doc"; +import { Opt } from "../../../fields/Doc"; import { isArray } from "util"; import { EditorState } from "prosemirror-state"; import { Networking } from "../../Network"; diff --git a/src/client/apis/google_docs/GooglePhotosClientUtils.ts b/src/client/apis/google_docs/GooglePhotosClientUtils.ts index 1e4c120bc..fef71ffeb 100644 --- a/src/client/apis/google_docs/GooglePhotosClientUtils.ts +++ b/src/client/apis/google_docs/GooglePhotosClientUtils.ts @@ -1,11 +1,11 @@ import { AssertionError } from "assert"; import { EditorState } from "prosemirror-state"; -import { Doc, DocListCastAsync, Opt } from "../../../new_fields/Doc"; -import { Id } from "../../../new_fields/FieldSymbols"; -import { RichTextField } from "../../../new_fields/RichTextField"; -import { RichTextUtils } from "../../../new_fields/RichTextUtils"; -import { Cast, StrCast } from "../../../new_fields/Types"; -import { ImageField } from "../../../new_fields/URLField"; +import { Doc, DocListCastAsync, Opt } from "../../../fields/Doc"; +import { Id } from "../../../fields/FieldSymbols"; +import { RichTextField } from "../../../fields/RichTextField"; +import { RichTextUtils } from "../../../fields/RichTextUtils"; +import { Cast, StrCast } from "../../../fields/Types"; +import { ImageField } from "../../../fields/URLField"; import { MediaItem, NewMediaItemResult } from "../../../server/apis/google/SharedTypes"; import { Utils } from "../../../Utils"; import { Docs, DocumentOptions } from "../../documents/Documents"; diff --git a/src/client/apis/youtube/YoutubeBox.tsx b/src/client/apis/youtube/YoutubeBox.tsx index 1575e53fc..ce7f49e64 100644 --- a/src/client/apis/youtube/YoutubeBox.tsx +++ b/src/client/apis/youtube/YoutubeBox.tsx @@ -1,7 +1,7 @@ import { action, observable, runInAction } from 'mobx'; import { observer } from "mobx-react"; -import { Doc, DocListCastAsync } from "../../../new_fields/Doc"; -import { Cast, NumCast, StrCast } from "../../../new_fields/Types"; +import { Doc, DocListCastAsync } from "../../../fields/Doc"; +import { Cast, NumCast, StrCast } from "../../../fields/Types"; import { Utils } from "../../../Utils"; import { DocServer } from "../../DocServer"; import { Docs } from "../../documents/Documents"; diff --git a/src/client/cognitive_services/CognitiveServices.ts b/src/client/cognitive_services/CognitiveServices.ts index 8c63ae906..d4df7ce57 100644 --- a/src/client/cognitive_services/CognitiveServices.ts +++ b/src/client/cognitive_services/CognitiveServices.ts @@ -1,12 +1,12 @@ import * as request from "request-promise"; -import { Doc, Field } from "../../new_fields/Doc"; -import { Cast } from "../../new_fields/Types"; +import { Doc, Field } from "../../fields/Doc"; +import { Cast } from "../../fields/Types"; import { Docs } from "../documents/Documents"; import { Utils } from "../../Utils"; -import { InkData } from "../../new_fields/InkField"; +import { InkData } from "../../fields/InkField"; import { UndoManager } from "../util/UndoManager"; import requestPromise = require("request-promise"); -import { List } from "../../new_fields/List"; +import { List } from "../../fields/List"; import { ClientRecommender } from "../ClientRecommender"; type APIManager = { converter: BodyConverter, requester: RequestExecutor }; diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 125a531f4..13687e4e8 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -9,14 +9,14 @@ import { ScriptingBox } from "../views/nodes/ScriptingBox"; import { VideoBox } from "../views/nodes/VideoBox"; import { WebBox } from "../views/nodes/WebBox"; import { OmitKeys, JSONUtils, Utils } from "../../Utils"; -import { Field, Doc, Opt, DocListCastAsync, FieldResult, DocListCast } from "../../new_fields/Doc"; -import { ImageField, VideoField, AudioField, PdfField, WebField, YoutubeField } from "../../new_fields/URLField"; -import { HtmlField } from "../../new_fields/HtmlField"; -import { List } from "../../new_fields/List"; -import { Cast, NumCast, StrCast } from "../../new_fields/Types"; +import { Field, Doc, Opt, DocListCastAsync, FieldResult, DocListCast } from "../../fields/Doc"; +import { ImageField, VideoField, AudioField, PdfField, WebField, YoutubeField } from "../../fields/URLField"; +import { HtmlField } from "../../fields/HtmlField"; +import { List } from "../../fields/List"; +import { Cast, NumCast, StrCast } from "../../fields/Types"; import { DocServer } from "../DocServer"; import { dropActionType } from "../util/DragManager"; -import { DateField } from "../../new_fields/DateField"; +import { DateField } from "../../fields/DateField"; import { YoutubeBox } from "../apis/youtube/YoutubeBox"; import { CollectionDockingView } from "../views/collections/CollectionDockingView"; import { LinkManager } from "../util/LinkManager"; @@ -26,10 +26,10 @@ import { Scripting } from "../util/Scripting"; import { LabelBox } from "../views/nodes/LabelBox"; import { SliderBox } from "../views/nodes/SliderBox"; import { FontIconBox } from "../views/nodes/FontIconBox"; -import { SchemaHeaderField } from "../../new_fields/SchemaHeaderField"; +import { SchemaHeaderField } from "../../fields/SchemaHeaderField"; import { PresBox } from "../views/nodes/PresBox"; -import { ComputedField, ScriptField } from "../../new_fields/ScriptField"; -import { ProxyField } from "../../new_fields/Proxy"; +import { ComputedField, ScriptField } from "../../fields/ScriptField"; +import { ProxyField } from "../../fields/Proxy"; import { DocumentType } from "./DocumentTypes"; import { RecommendationsBox } from "../views/RecommendationsBox"; import { PresElementBox } from "../views/presentationview/PresElementBox"; @@ -39,9 +39,9 @@ import { ColorBox } from "../views/nodes/ColorBox"; import { LinkAnchorBox } from "../views/nodes/LinkAnchorBox"; import { DocHolderBox } from "../views/nodes/DocHolderBox"; import { InkingStroke } from "../views/InkingStroke"; -import { InkField } from "../../new_fields/InkField"; +import { InkField } from "../../fields/InkField"; import { InkingControl } from "../views/InkingControl"; -import { RichTextField } from "../../new_fields/RichTextField"; +import { RichTextField } from "../../fields/RichTextField"; import { extname } from "path"; import { MessageStore } from "../../server/Message"; import { ContextMenuProps } from "../views/ContextMenuItem"; diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index b67c3ea60..d9faed36d 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -4,23 +4,23 @@ import { Utils } from "../../Utils"; import { DocServer } from "../DocServer"; import { Docs, DocumentOptions } from "../documents/Documents"; import { UndoManager } from "./UndoManager"; -import { Doc, DocListCast, DocListCastAsync } from "../../new_fields/Doc"; -import { List } from "../../new_fields/List"; -import { listSpec } from "../../new_fields/Schema"; -import { ScriptField, ComputedField } from "../../new_fields/ScriptField"; -import { Cast, PromiseValue, StrCast, NumCast } from "../../new_fields/Types"; -import { nullAudio } from "../../new_fields/URLField"; +import { Doc, DocListCast, DocListCastAsync } from "../../fields/Doc"; +import { List } from "../../fields/List"; +import { listSpec } from "../../fields/Schema"; +import { ScriptField, ComputedField } from "../../fields/ScriptField"; +import { Cast, PromiseValue, StrCast, NumCast } from "../../fields/Types"; +import { nullAudio } from "../../fields/URLField"; import { DragManager } from "./DragManager"; import { InkingControl } from "../views/InkingControl"; import { Scripting } from "./Scripting"; import { CollectionViewType } from "../views/collections/CollectionView"; import { makeTemplate } from "./DropConverter"; -import { RichTextField } from "../../new_fields/RichTextField"; -import { PrefetchProxy } from "../../new_fields/Proxy"; +import { RichTextField } from "../../fields/RichTextField"; +import { PrefetchProxy } from "../../fields/Proxy"; import { FormattedTextBox } from "../views/nodes/formattedText/FormattedTextBox"; import { MainView } from "../views/MainView"; import { DocumentType } from "../documents/DocumentTypes"; -import { SchemaHeaderField } from "../../new_fields/SchemaHeaderField"; +import { SchemaHeaderField } from "../../fields/SchemaHeaderField"; import { DimUnit } from "../views/collections/collectionMulticolumn/CollectionMulticolumnView"; export class CurrentUserUtils { diff --git a/src/client/util/DictationManager.ts b/src/client/util/DictationManager.ts index b3295ece0..e46225b4a 100644 --- a/src/client/util/DictationManager.ts +++ b/src/client/util/DictationManager.ts @@ -3,15 +3,15 @@ import { DocumentView } from "../views/nodes/DocumentView"; import { UndoManager } from "./UndoManager"; import * as interpreter from "words-to-numbers"; import { DocumentType } from "../documents/DocumentTypes"; -import { Doc, Opt } from "../../new_fields/Doc"; -import { List } from "../../new_fields/List"; +import { Doc, Opt } from "../../fields/Doc"; +import { List } from "../../fields/List"; import { Docs } from "../documents/Documents"; import { CollectionViewType } from "../views/collections/CollectionView"; -import { Cast, CastCtor } from "../../new_fields/Types"; -import { listSpec } from "../../new_fields/Schema"; -import { AudioField, ImageField } from "../../new_fields/URLField"; +import { Cast, CastCtor } from "../../fields/Types"; +import { listSpec } from "../../fields/Schema"; +import { AudioField, ImageField } from "../../fields/URLField"; import { Utils } from "../../Utils"; -import { RichTextField } from "../../new_fields/RichTextField"; +import { RichTextField } from "../../fields/RichTextField"; import { DictationOverlay } from "../views/DictationOverlay"; /** diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index 99d85125a..ab087335e 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -1,7 +1,7 @@ import { action, computed, observable } from 'mobx'; -import { Doc, DocListCastAsync, DocListCast, Opt } from '../../new_fields/Doc'; -import { Id } from '../../new_fields/FieldSymbols'; -import { Cast, NumCast, StrCast } from '../../new_fields/Types'; +import { Doc, DocListCastAsync, DocListCast, Opt } from '../../fields/Doc'; +import { Id } from '../../fields/FieldSymbols'; +import { Cast, NumCast, StrCast } from '../../fields/Types'; import { CollectionDockingView } from '../views/collections/CollectionDockingView'; import { CollectionView } from '../views/collections/CollectionView'; import { DocumentView, DocFocusFunc } from '../views/nodes/DocumentView'; diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index d1d7f2a8a..66c7ecf7d 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -1,12 +1,12 @@ import { action, observable, runInAction } from "mobx"; -import { DateField } from "../../new_fields/DateField"; -import { Doc, Field, Opt } from "../../new_fields/Doc"; -import { List } from "../../new_fields/List"; -import { PrefetchProxy } from "../../new_fields/Proxy"; -import { listSpec } from "../../new_fields/Schema"; -import { SchemaHeaderField } from "../../new_fields/SchemaHeaderField"; -import { ScriptField } from "../../new_fields/ScriptField"; -import { Cast, NumCast, ScriptCast, StrCast } from "../../new_fields/Types"; +import { DateField } from "../../fields/DateField"; +import { Doc, Field, Opt } from "../../fields/Doc"; +import { List } from "../../fields/List"; +import { PrefetchProxy } from "../../fields/Proxy"; +import { listSpec } from "../../fields/Schema"; +import { SchemaHeaderField } from "../../fields/SchemaHeaderField"; +import { ScriptField } from "../../fields/ScriptField"; +import { Cast, NumCast, ScriptCast, StrCast } from "../../fields/Types"; import { emptyFunction } from "../../Utils"; import { Docs, DocUtils } from "../documents/Documents"; import * as globalCssVariables from "../views/globalCssVariables.scss"; diff --git a/src/client/util/DropConverter.ts b/src/client/util/DropConverter.ts index d6db882b8..752c1cfc5 100644 --- a/src/client/util/DropConverter.ts +++ b/src/client/util/DropConverter.ts @@ -1,12 +1,12 @@ import { DragManager } from "./DragManager"; -import { Doc, DocListCast, Opt } from "../../new_fields/Doc"; +import { Doc, DocListCast, Opt } from "../../fields/Doc"; import { DocumentType } from "../documents/DocumentTypes"; -import { ObjectField } from "../../new_fields/ObjectField"; -import { StrCast } from "../../new_fields/Types"; +import { ObjectField } from "../../fields/ObjectField"; +import { StrCast } from "../../fields/Types"; import { Docs } from "../documents/Documents"; -import { ScriptField, ComputedField } from "../../new_fields/ScriptField"; -import { RichTextField } from "../../new_fields/RichTextField"; -import { ImageField } from "../../new_fields/URLField"; +import { ScriptField, ComputedField } from "../../fields/ScriptField"; +import { RichTextField } from "../../fields/RichTextField"; +import { ImageField } from "../../fields/URLField"; import { Scripting } from "./Scripting"; // diff --git a/src/client/util/History.ts b/src/client/util/History.ts index 2c53d7e52..7b7d4b835 100644 --- a/src/client/util/History.ts +++ b/src/client/util/History.ts @@ -1,4 +1,4 @@ -import { Doc } from "../../new_fields/Doc"; +import { Doc } from "../../fields/Doc"; import { DocServer } from "../DocServer"; import { MainView } from "../views/MainView"; import * as qs from 'query-string'; diff --git a/src/client/util/Import & Export/DirectoryImportBox.tsx b/src/client/util/Import & Export/DirectoryImportBox.tsx index 438904688..1e8f07049 100644 --- a/src/client/util/Import & Export/DirectoryImportBox.tsx +++ b/src/client/util/Import & Export/DirectoryImportBox.tsx @@ -1,6 +1,6 @@ import "fs"; import React = require("react"); -import { Doc, DocListCast, DocListCastAsync, Opt } from "../../../new_fields/Doc"; +import { Doc, DocListCast, DocListCastAsync, Opt } from "../../../fields/Doc"; import { action, observable, runInAction, computed, reaction, IReactionDisposer } from "mobx"; import { FieldViewProps, FieldView } from "../../views/nodes/FieldView"; import Measure, { ContentRect } from "react-measure"; @@ -12,12 +12,12 @@ import { observer } from "mobx-react"; import ImportMetadataEntry, { keyPlaceholder, valuePlaceholder } from "./ImportMetadataEntry"; import { Utils } from "../../../Utils"; import { DocumentManager } from "../DocumentManager"; -import { Id } from "../../../new_fields/FieldSymbols"; -import { List } from "../../../new_fields/List"; -import { Cast, BoolCast, NumCast } from "../../../new_fields/Types"; -import { listSpec } from "../../../new_fields/Schema"; +import { Id } from "../../../fields/FieldSymbols"; +import { List } from "../../../fields/List"; +import { Cast, BoolCast, NumCast } from "../../../fields/Types"; +import { listSpec } from "../../../fields/Schema"; import { GooglePhotos } from "../../apis/google_docs/GooglePhotosClientUtils"; -import { SchemaHeaderField } from "../../../new_fields/SchemaHeaderField"; +import { SchemaHeaderField } from "../../../fields/SchemaHeaderField"; import "./DirectoryImportBox.scss"; import { Networking } from "../../Network"; import { BatchedArray } from "array-batcher"; diff --git a/src/client/util/Import & Export/ImageUtils.ts b/src/client/util/Import & Export/ImageUtils.ts index c8d1530b3..072e5f58a 100644 --- a/src/client/util/Import & Export/ImageUtils.ts +++ b/src/client/util/Import & Export/ImageUtils.ts @@ -1,9 +1,9 @@ -import { Doc } from "../../../new_fields/Doc"; -import { ImageField } from "../../../new_fields/URLField"; -import { Cast, StrCast } from "../../../new_fields/Types"; +import { Doc } from "../../../fields/Doc"; +import { ImageField } from "../../../fields/URLField"; +import { Cast, StrCast } from "../../../fields/Types"; import { Docs } from "../../documents/Documents"; import { Networking } from "../../Network"; -import { Id } from "../../../new_fields/FieldSymbols"; +import { Id } from "../../../fields/FieldSymbols"; import { Utils } from "../../../Utils"; export namespace ImageUtils { diff --git a/src/client/util/Import & Export/ImportMetadataEntry.tsx b/src/client/util/Import & Export/ImportMetadataEntry.tsx index 8e1c50bea..dcb94e2e0 100644 --- a/src/client/util/Import & Export/ImportMetadataEntry.tsx +++ b/src/client/util/Import & Export/ImportMetadataEntry.tsx @@ -5,8 +5,8 @@ import { action, computed } from "mobx"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faPlus } from "@fortawesome/free-solid-svg-icons"; import { library } from '@fortawesome/fontawesome-svg-core'; -import { Doc } from "../../../new_fields/Doc"; -import { StrCast, BoolCast } from "../../../new_fields/Types"; +import { Doc } from "../../../fields/Doc"; +import { StrCast, BoolCast } from "../../../fields/Types"; interface KeyValueProps { Document: Doc; diff --git a/src/client/util/LinkManager.ts b/src/client/util/LinkManager.ts index e236c7f47..8e6ccf098 100644 --- a/src/client/util/LinkManager.ts +++ b/src/client/util/LinkManager.ts @@ -1,7 +1,7 @@ -import { Doc, DocListCast } from "../../new_fields/Doc"; -import { List } from "../../new_fields/List"; -import { listSpec } from "../../new_fields/Schema"; -import { Cast, StrCast } from "../../new_fields/Types"; +import { Doc, DocListCast } from "../../fields/Doc"; +import { List } from "../../fields/List"; +import { listSpec } from "../../fields/Schema"; +import { Cast, StrCast } from "../../fields/Types"; import { Docs } from "../documents/Documents"; import { Scripting } from "./Scripting"; diff --git a/src/client/util/Scripting.ts b/src/client/util/Scripting.ts index 8b7b9c9c7..ab577315c 100644 --- a/src/client/util/Scripting.ts +++ b/src/client/util/Scripting.ts @@ -9,7 +9,7 @@ export { ts }; // @ts-ignore import * as typescriptlib from '!!raw-loader!./type_decls.d'; -import { Doc, Field } from '../../new_fields/Doc'; +import { Doc, Field } from '../../fields/Doc'; export interface ScriptSucccess { success: true; diff --git a/src/client/util/SearchUtil.ts b/src/client/util/SearchUtil.ts index 6501da34a..5679c0a14 100644 --- a/src/client/util/SearchUtil.ts +++ b/src/client/util/SearchUtil.ts @@ -1,7 +1,7 @@ import * as rp from 'request-promise'; import { DocServer } from '../DocServer'; -import { Doc } from '../../new_fields/Doc'; -import { Id } from '../../new_fields/FieldSymbols'; +import { Doc } from '../../fields/Doc'; +import { Id } from '../../fields/FieldSymbols'; import { Utils } from '../../Utils'; import { DocumentType } from '../documents/DocumentTypes'; diff --git a/src/client/util/SelectionManager.ts b/src/client/util/SelectionManager.ts index 11d2cafb2..bd743c28e 100644 --- a/src/client/util/SelectionManager.ts +++ b/src/client/util/SelectionManager.ts @@ -1,8 +1,8 @@ import { observable, action, runInAction, ObservableMap } from "mobx"; -import { Doc } from "../../new_fields/Doc"; +import { Doc } from "../../fields/Doc"; import { DocumentView } from "../views/nodes/DocumentView"; import { computedFn } from "mobx-utils"; -import { List } from "../../new_fields/List"; +import { List } from "../../fields/List"; export namespace SelectionManager { diff --git a/src/client/util/SerializationHelper.ts b/src/client/util/SerializationHelper.ts index 1f6b939d3..ad0309fa7 100644 --- a/src/client/util/SerializationHelper.ts +++ b/src/client/util/SerializationHelper.ts @@ -1,5 +1,5 @@ import { PropSchema, serialize, deserialize, custom, setDefaultModelSchema, getDefaultModelSchema } from "serializr"; -import { Field } from "../../new_fields/Doc"; +import { Field } from "../../fields/Doc"; import { ClientUtils } from "./ClientUtils"; let serializing = 0; diff --git a/src/client/util/SharingManager.tsx b/src/client/util/SharingManager.tsx index 3ce6de80d..dc67145fc 100644 --- a/src/client/util/SharingManager.tsx +++ b/src/client/util/SharingManager.tsx @@ -1,13 +1,13 @@ import { observable, runInAction, action } from "mobx"; import * as React from "react"; import MainViewModal from "../views/MainViewModal"; -import { Doc, Opt, DocCastAsync } from "../../new_fields/Doc"; +import { Doc, Opt, DocCastAsync } from "../../fields/Doc"; import { DocServer } from "../DocServer"; -import { Cast, StrCast } from "../../new_fields/Types"; +import { Cast, StrCast } from "../../fields/Types"; import * as RequestPromise from "request-promise"; import { Utils } from "../../Utils"; import "./SharingManager.scss"; -import { Id } from "../../new_fields/FieldSymbols"; +import { Id } from "../../fields/FieldSymbols"; import { observer } from "mobx-react"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { library } from '@fortawesome/fontawesome-svg-core'; diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx index 6517f2fb9..1ba9fcc32 100644 --- a/src/client/views/DocComponent.tsx +++ b/src/client/views/DocComponent.tsx @@ -1,14 +1,14 @@ -import { Doc, Opt, DataSym, DocListCast } from '../../new_fields/Doc'; +import { Doc, Opt, DataSym, DocListCast } from '../../fields/Doc'; import { Touchable } from './Touchable'; import { computed, action, observable } from 'mobx'; -import { Cast, BoolCast, ScriptCast } from '../../new_fields/Types'; -import { listSpec } from '../../new_fields/Schema'; +import { Cast, BoolCast, ScriptCast } from '../../fields/Types'; +import { listSpec } from '../../fields/Schema'; import { InkingControl } from './InkingControl'; -import { InkTool } from '../../new_fields/InkField'; +import { InkTool } from '../../fields/InkField'; import { InteractionUtils } from '../util/InteractionUtils'; -import { List } from '../../new_fields/List'; -import { DateField } from '../../new_fields/DateField'; -import { ScriptField } from '../../new_fields/ScriptField'; +import { List } from '../../fields/List'; +import { DateField } from '../../fields/DateField'; +import { ScriptField } from '../../fields/ScriptField'; /// DocComponent returns a generic React base class used by views that don't have 'fieldKey' props (e.g.,CollectionFreeFormDocumentView, DocumentView) diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx index 10d9ec401..2db5cd3ba 100644 --- a/src/client/views/DocumentButtonBar.tsx +++ b/src/client/views/DocumentButtonBar.tsx @@ -3,9 +3,9 @@ import { faArrowAltCircleDown, faPhotoVideo, faArrowAltCircleUp, faArrowAltCircl import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { action, computed, observable, runInAction } from "mobx"; import { observer } from "mobx-react"; -import { Doc, DocListCast } from "../../new_fields/Doc"; -import { RichTextField } from '../../new_fields/RichTextField'; -import { NumCast, StrCast, Cast } from "../../new_fields/Types"; +import { Doc, DocListCast } from "../../fields/Doc"; +import { RichTextField } from '../../fields/RichTextField'; +import { NumCast, StrCast, Cast } from "../../fields/Types"; import { emptyFunction, setupMoveUpEvents } from "../../Utils"; import { Pulls, Pushes } from '../apis/google_docs/GoogleApiClientUtils'; import { UndoManager } from "../util/UndoManager"; diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 313d8be23..1f4f45f0e 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -3,10 +3,10 @@ import { faCaretUp, faFilePdf, faFilm, faImage, faObjectGroup, faStickyNote, faT import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { action, computed, observable, reaction, runInAction } from "mobx"; import { observer } from "mobx-react"; -import { Doc, DataSym, Field, WidthSym, HeightSym } from "../../new_fields/Doc"; -import { Document } from '../../new_fields/documentSchemas'; -import { ScriptField } from '../../new_fields/ScriptField'; -import { Cast, StrCast, NumCast } from "../../new_fields/Types"; +import { Doc, DataSym, Field, WidthSym, HeightSym } from "../../fields/Doc"; +import { Document } from '../../fields/documentSchemas'; +import { ScriptField } from '../../fields/ScriptField'; +import { Cast, StrCast, NumCast } from "../../fields/Types"; import { Utils, setupMoveUpEvents, emptyFunction, returnFalse, simulateMouseClick } from "../../Utils"; import { DocUtils } from "../documents/Documents"; import { DocumentType } from '../documents/DocumentTypes'; @@ -17,7 +17,7 @@ import { DocumentButtonBar } from './DocumentButtonBar'; import './DocumentDecorations.scss'; import { DocumentView } from "./nodes/DocumentView"; import React = require("react"); -import { Id } from '../../new_fields/FieldSymbols'; +import { Id } from '../../fields/FieldSymbols'; import e = require('express'); import { CollectionDockingView } from './collections/CollectionDockingView'; import { SnappingManager } from '../util/SnappingManager'; @@ -266,16 +266,16 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> const fixedAspect = first.layoutDoc._nativeWidth ? NumCast(first.layoutDoc._nativeWidth) / NumCast(first.layoutDoc._nativeHeight) : 0; if (fixedAspect && (this._resizeHdlId === "documentDecorations-bottomRightResizer" || this._resizeHdlId === "documentDecorations-topLeftResizer")) { // need to generalize for bl and tr drag handles const project = (p: number[], a: number[], b: number[]) => { - var atob = [b[0] - a[0], b[1] - a[1]]; - var atop = [p[0] - a[0], p[1] - a[1]]; - var len = atob[0] * atob[0] + atob[1] * atob[1]; - var dot = atop[0] * atob[0] + atop[1] * atob[1]; - var t = dot / len; + const atob = [b[0] - a[0], b[1] - a[1]]; + const atop = [p[0] - a[0], p[1] - a[1]]; + const len = atob[0] * atob[0] + atob[1] * atob[1]; + let dot = atop[0] * atob[0] + atop[1] * atob[1]; + const t = dot / len; dot = (b[0] - a[0]) * (p[1] - a[1]) - (b[1] - a[1]) * (p[0] - a[0]); return [a[0] + atob[0] * t, a[1] + atob[1] * t]; - } + }; const tl = first.props.ScreenToLocalTransform().inverse().transformPoint(0, 0); - const drag = project([e.clientX + this._offX, e.clientY + this._offY], tl, [tl[0] + fixedAspect, tl[1] + 1]) + const drag = project([e.clientX + this._offX, e.clientY + this._offY], tl, [tl[0] + fixedAspect, tl[1] + 1]); thisPt = DragManager.snapDragAspect(drag, fixedAspect); } else { thisPt = DragManager.snapDrag(e, -this._offX, -this._offY, this._offX, this._offY); diff --git a/src/client/views/EditableView.tsx b/src/client/views/EditableView.tsx index c51173ad3..e0e205df9 100644 --- a/src/client/views/EditableView.tsx +++ b/src/client/views/EditableView.tsx @@ -2,8 +2,8 @@ import React = require('react'); import { action, observable } from 'mobx'; import { observer } from 'mobx-react'; import * as Autosuggest from 'react-autosuggest'; -import { ObjectField } from '../../new_fields/ObjectField'; -import { SchemaHeaderField } from '../../new_fields/SchemaHeaderField'; +import { ObjectField } from '../../fields/ObjectField'; +import { SchemaHeaderField } from '../../fields/SchemaHeaderField'; import "./EditableView.scss"; export interface EditableProps { diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx index 812ff3b93..aadf5f535 100644 --- a/src/client/views/GestureOverlay.tsx +++ b/src/client/views/GestureOverlay.tsx @@ -6,13 +6,13 @@ import { computed, observable, action, runInAction, IReactionDisposer, reaction, import { GestureUtils } from "../../pen-gestures/GestureUtils"; import { InteractionUtils } from "../util/InteractionUtils"; import { InkingControl } from "./InkingControl"; -import { InkTool, InkData } from "../../new_fields/InkField"; -import { Doc } from "../../new_fields/Doc"; +import { InkTool, InkData } from "../../fields/InkField"; +import { Doc } from "../../fields/Doc"; import { LinkManager } from "../util/LinkManager"; import { DocUtils, Docs } from "../documents/Documents"; import { undoBatch } from "../util/UndoManager"; import { Scripting } from "../util/Scripting"; -import { FieldValue, Cast, NumCast, BoolCast } from "../../new_fields/Types"; +import { FieldValue, Cast, NumCast, BoolCast } from "../../fields/Types"; import { CurrentUserUtils } from "../util/CurrentUserUtils"; import HorizontalPalette from "./Palette"; import { Utils, emptyPath, emptyFunction, returnFalse, returnOne, returnEmptyString, returnTrue, numberRange, returnZero } from "../../Utils"; @@ -22,9 +22,9 @@ import { DocumentContentsView } from "./nodes/DocumentContentsView"; import { CognitiveServices } from "../cognitive_services/CognitiveServices"; import { DocServer } from "../DocServer"; import htmlToImage from "html-to-image"; -import { ScriptField } from "../../new_fields/ScriptField"; -import { listSpec } from "../../new_fields/Schema"; -import { List } from "../../new_fields/List"; +import { ScriptField } from "../../fields/ScriptField"; +import { listSpec } from "../../fields/Schema"; +import { List } from "../../fields/List"; import { CollectionViewType } from "./collections/CollectionView"; import TouchScrollableMenu, { TouchScrollableMenuItem } from "./TouchScrollableMenu"; import MobileInterface from "../../mobile/MobileInterface"; diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts index b52a0063b..255142771 100644 --- a/src/client/views/GlobalKeyHandler.ts +++ b/src/client/views/GlobalKeyHandler.ts @@ -4,23 +4,23 @@ import { CollectionDockingView } from "./collections/CollectionDockingView"; import { MainView } from "./MainView"; import { DragManager } from "../util/DragManager"; import { action, runInAction } from "mobx"; -import { Doc, DocListCast } from "../../new_fields/Doc"; +import { Doc, DocListCast } from "../../fields/Doc"; import { DictationManager } from "../util/DictationManager"; import SharingManager from "../util/SharingManager"; -import { Cast, PromiseValue, NumCast } from "../../new_fields/Types"; -import { ScriptField } from "../../new_fields/ScriptField"; +import { Cast, PromiseValue, NumCast } from "../../fields/Types"; +import { ScriptField } from "../../fields/ScriptField"; import { InkingControl } from "./InkingControl"; -import { InkTool } from "../../new_fields/InkField"; +import { InkTool } from "../../fields/InkField"; import { DocumentView } from "./nodes/DocumentView"; import GoogleAuthenticationManager from "../apis/GoogleAuthenticationManager"; import { CollectionFreeFormView } from "./collections/collectionFreeForm/CollectionFreeFormView"; import { MarqueeView } from "./collections/collectionFreeForm/MarqueeView"; -import { Id } from "../../new_fields/FieldSymbols"; +import { Id } from "../../fields/FieldSymbols"; import { DocumentDecorations } from "./DocumentDecorations"; import { DocumentType } from "../documents/DocumentTypes"; import { DocServer } from "../DocServer"; -import { List } from "../../new_fields/List"; -import { DateField } from "../../new_fields/DateField"; +import { List } from "../../fields/List"; +import { DateField } from "../../fields/DateField"; const modifiers = ["control", "meta", "shift", "alt"]; type KeyHandler = (keycode: string, e: KeyboardEvent) => KeyControlInfo | Promise; diff --git a/src/client/views/InkingControl.tsx b/src/client/views/InkingControl.tsx index 5115995b0..156f58ec1 100644 --- a/src/client/views/InkingControl.tsx +++ b/src/client/views/InkingControl.tsx @@ -1,8 +1,8 @@ import { action, computed, observable } from "mobx"; import { ColorState } from 'react-color'; -import { Doc } from "../../new_fields/Doc"; -import { InkTool } from "../../new_fields/InkField"; -import { FieldValue, NumCast, StrCast } from "../../new_fields/Types"; +import { Doc } from "../../fields/Doc"; +import { InkTool } from "../../fields/InkField"; +import { FieldValue, NumCast, StrCast } from "../../fields/Types"; import { CurrentUserUtils } from "../util/CurrentUserUtils"; import { Scripting } from "../util/Scripting"; import { SelectionManager } from "../util/SelectionManager"; diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx index 7a318d5c2..25ea50a27 100644 --- a/src/client/views/InkingStroke.tsx +++ b/src/client/views/InkingStroke.tsx @@ -1,14 +1,14 @@ import { observer } from "mobx-react"; -import { documentSchema } from "../../new_fields/documentSchemas"; -import { InkData, InkField, InkTool } from "../../new_fields/InkField"; -import { makeInterface } from "../../new_fields/Schema"; -import { Cast, StrCast, NumCast } from "../../new_fields/Types"; +import { documentSchema } from "../../fields/documentSchemas"; +import { InkData, InkField, InkTool } from "../../fields/InkField"; +import { makeInterface } from "../../fields/Schema"; +import { Cast, StrCast, NumCast } from "../../fields/Types"; import { ViewBoxBaseComponent } from "./DocComponent"; import { InkingControl } from "./InkingControl"; import "./InkingStroke.scss"; import { FieldView, FieldViewProps } from "./nodes/FieldView"; import React = require("react"); -import { TraceMobx } from "../../new_fields/util"; +import { TraceMobx } from "../../fields/util"; import { InteractionUtils } from "../util/InteractionUtils"; import { ContextMenu } from "./ContextMenu"; import { CognitiveServices } from "../cognitive_services/CognitiveServices"; diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 9bc08de3e..978cf7868 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -13,12 +13,12 @@ import { observer } from 'mobx-react'; import "normalize.css"; import * as React from 'react'; import Measure from 'react-measure'; -import { Doc, DocListCast, Field, Opt } from '../../new_fields/Doc'; -import { Id } from '../../new_fields/FieldSymbols'; -import { List } from '../../new_fields/List'; -import { listSpec } from '../../new_fields/Schema'; -import { BoolCast, Cast, FieldValue, StrCast } from '../../new_fields/Types'; -import { TraceMobx } from '../../new_fields/util'; +import { Doc, DocListCast, Field, Opt } from '../../fields/Doc'; +import { Id } from '../../fields/FieldSymbols'; +import { List } from '../../fields/List'; +import { listSpec } from '../../fields/Schema'; +import { BoolCast, Cast, FieldValue, StrCast } from '../../fields/Types'; +import { TraceMobx } from '../../fields/util'; import { CurrentUserUtils } from '../util/CurrentUserUtils'; import { emptyFunction, emptyPath, returnFalse, returnOne, returnZero, returnTrue, Utils } from '../../Utils'; import GoogleAuthenticationManager from '../apis/GoogleAuthenticationManager'; @@ -48,7 +48,7 @@ import { RadialMenu } from './nodes/RadialMenu'; import { OverlayView } from './OverlayView'; import PDFMenu from './pdf/PDFMenu'; import { PreviewCursor } from './PreviewCursor'; -import { ScriptField } from '../../new_fields/ScriptField'; +import { ScriptField } from '../../fields/ScriptField'; import { TimelineMenu } from './animationtimeline/TimelineMenu'; import { DragManager } from '../util/DragManager'; import { SnappingManager } from '../util/SnappingManager'; diff --git a/src/client/views/MainViewNotifs.tsx b/src/client/views/MainViewNotifs.tsx index 82e07c449..05f890485 100644 --- a/src/client/views/MainViewNotifs.tsx +++ b/src/client/views/MainViewNotifs.tsx @@ -2,7 +2,7 @@ import { action, computed, observable } from 'mobx'; import { observer } from 'mobx-react'; import "normalize.css"; import * as React from 'react'; -import { Doc, DocListCast, Opt } from '../../new_fields/Doc'; +import { Doc, DocListCast, Opt } from '../../fields/Doc'; import { emptyFunction } from '../../Utils'; import { SetupDrag } from '../util/DragManager'; import "./MainViewNotifs.scss"; diff --git a/src/client/views/MetadataEntryMenu.tsx b/src/client/views/MetadataEntryMenu.tsx index 8bc80ed06..e100d3f52 100644 --- a/src/client/views/MetadataEntryMenu.tsx +++ b/src/client/views/MetadataEntryMenu.tsx @@ -3,7 +3,7 @@ import "./MetadataEntryMenu.scss"; import { observer } from 'mobx-react'; import { observable, action, runInAction, trace, computed, IReactionDisposer, reaction } from 'mobx'; import { KeyValueBox } from './nodes/KeyValueBox'; -import { Doc, Field, DocListCastAsync } from '../../new_fields/Doc'; +import { Doc, Field, DocListCastAsync } from '../../fields/Doc'; import * as Autosuggest from 'react-autosuggest'; import { undoBatch } from '../util/UndoManager'; import { emptyFunction, emptyPath } from '../../Utils'; diff --git a/src/client/views/OverlayView.tsx b/src/client/views/OverlayView.tsx index afb6bfb7d..bfa44fe47 100644 --- a/src/client/views/OverlayView.tsx +++ b/src/client/views/OverlayView.tsx @@ -1,9 +1,9 @@ import { action, computed, observable } from "mobx"; import { observer } from "mobx-react"; import * as React from "react"; -import { Doc, DocListCast, Opt } from "../../new_fields/Doc"; -import { Id } from "../../new_fields/FieldSymbols"; -import { NumCast } from "../../new_fields/Types"; +import { Doc, DocListCast, Opt } from "../../fields/Doc"; +import { Id } from "../../fields/FieldSymbols"; +import { NumCast } from "../../fields/Types"; import { emptyFunction, emptyPath, returnEmptyString, returnFalse, returnOne, returnTrue, returnZero, Utils } from "../../Utils"; import { Transform } from "../util/Transform"; import { CollectionFreeFormLinksView } from "./collections/collectionFreeForm/CollectionFreeFormLinksView"; diff --git a/src/client/views/Palette.tsx b/src/client/views/Palette.tsx index 63744cb50..108eb83d6 100644 --- a/src/client/views/Palette.tsx +++ b/src/client/views/Palette.tsx @@ -1,8 +1,8 @@ import { IReactionDisposer, observable, reaction } from "mobx"; import { observer } from "mobx-react"; import * as React from "react"; -import { Doc } from "../../new_fields/Doc"; -import { NumCast } from "../../new_fields/Types"; +import { Doc } from "../../fields/Doc"; +import { NumCast } from "../../fields/Types"; import { emptyFunction, emptyPath, returnEmptyString, returnZero, returnFalse, returnOne, returnTrue } from "../../Utils"; import { Transform } from "../util/Transform"; import { DocumentView } from "./nodes/DocumentView"; diff --git a/src/client/views/PreviewCursor.tsx b/src/client/views/PreviewCursor.tsx index f50ac34c8..dd65681d4 100644 --- a/src/client/views/PreviewCursor.tsx +++ b/src/client/views/PreviewCursor.tsx @@ -4,11 +4,11 @@ import "normalize.css"; import * as React from 'react'; import "./PreviewCursor.scss"; import { Docs } from '../documents/Documents'; -import { Doc } from '../../new_fields/Doc'; +import { Doc } from '../../fields/Doc'; import { Transform } from "../util/Transform"; import { DocServer } from '../DocServer'; import { undoBatch } from '../util/UndoManager'; -import { NumCast } from '../../new_fields/Types'; +import { NumCast } from '../../fields/Types'; @observer export class PreviewCursor extends React.Component<{}> { diff --git a/src/client/views/RecommendationsBox.tsx b/src/client/views/RecommendationsBox.tsx index e66fd3eb4..8ca81c070 100644 --- a/src/client/views/RecommendationsBox.tsx +++ b/src/client/views/RecommendationsBox.tsx @@ -3,17 +3,17 @@ import React = require("react"); import { observable, action, computed, runInAction } from "mobx"; import Measure from "react-measure"; import "./RecommendationsBox.scss"; -import { Doc, DocListCast, WidthSym, HeightSym } from "../../new_fields/Doc"; +import { Doc, DocListCast, WidthSym, HeightSym } from "../../fields/Doc"; import { DocumentIcon } from "./nodes/DocumentIcon"; -import { StrCast, NumCast } from "../../new_fields/Types"; +import { StrCast, NumCast } from "../../fields/Types"; import { returnFalse, emptyFunction, returnEmptyString, returnOne, emptyPath, returnZero } from "../../Utils"; import { Transform } from "../util/Transform"; -import { ObjectField } from "../../new_fields/ObjectField"; +import { ObjectField } from "../../fields/ObjectField"; import { DocumentView } from "./nodes/DocumentView"; import { DocumentType } from '../documents/DocumentTypes'; import { ClientRecommender } from "../ClientRecommender"; import { DocServer } from "../DocServer"; -import { Id } from "../../new_fields/FieldSymbols"; +import { Id } from "../../fields/FieldSymbols"; import { FieldView, FieldViewProps } from "./nodes/FieldView"; import { DocumentManager } from "../util/DocumentManager"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; diff --git a/src/client/views/ScriptBox.tsx b/src/client/views/ScriptBox.tsx index 66d3b937e..888f84dfa 100644 --- a/src/client/views/ScriptBox.tsx +++ b/src/client/views/ScriptBox.tsx @@ -5,11 +5,11 @@ import { observable, action } from "mobx"; import "./ScriptBox.scss"; import { OverlayView } from "./OverlayView"; import { DocumentIconContainer } from "./nodes/DocumentIcon"; -import { Opt, Doc } from "../../new_fields/Doc"; +import { Opt, Doc } from "../../fields/Doc"; import { emptyFunction } from "../../Utils"; -import { ScriptCast } from "../../new_fields/Types"; +import { ScriptCast } from "../../fields/Types"; import { CompileScript } from "../util/Scripting"; -import { ScriptField } from "../../new_fields/ScriptField"; +import { ScriptField } from "../../fields/ScriptField"; import { DragManager } from "../util/DragManager"; import { EditableView } from "./EditableView"; import { getEffectiveTypeRoots } from "typescript"; diff --git a/src/client/views/SearchDocBox.tsx b/src/client/views/SearchDocBox.tsx index 7bd689b19..e038d8213 100644 --- a/src/client/views/SearchDocBox.tsx +++ b/src/client/views/SearchDocBox.tsx @@ -3,9 +3,9 @@ import { faBullseye, faLink } from "@fortawesome/free-solid-svg-icons"; import { action, computed, observable, runInAction } from "mobx"; import { observer } from "mobx-react"; //import "./SearchBoxDoc.scss"; -import { Doc, DocListCast } from "../../new_fields/Doc"; -import { Id } from "../../new_fields/FieldSymbols"; -import { BoolCast, Cast, NumCast, StrCast } from "../../new_fields/Types"; +import { Doc, DocListCast } from "../../fields/Doc"; +import { Id } from "../../fields/FieldSymbols"; +import { BoolCast, Cast, NumCast, StrCast } from "../../fields/Types"; import { returnFalse, returnZero } from "../../Utils"; import { Docs } from "../documents/Documents"; import { SearchUtil } from "../util/SearchUtil"; diff --git a/src/client/views/TemplateMenu.tsx b/src/client/views/TemplateMenu.tsx index 43debfe99..f5e95e4fd 100644 --- a/src/client/views/TemplateMenu.tsx +++ b/src/client/views/TemplateMenu.tsx @@ -6,15 +6,15 @@ import './TemplateMenu.scss'; import { DocumentView } from "./nodes/DocumentView"; import { Template } from "./Templates"; import React = require("react"); -import { Doc, DocListCast } from "../../new_fields/Doc"; +import { Doc, DocListCast } from "../../fields/Doc"; import { Docs, } from "../documents/Documents"; -import { StrCast, Cast } from "../../new_fields/Types"; +import { StrCast, Cast } from "../../fields/Types"; import { CollectionTreeView } from "./collections/CollectionTreeView"; import { returnTrue, emptyFunction, returnFalse, returnOne, emptyPath, returnZero } from "../../Utils"; import { Transform } from "../util/Transform"; -import { ScriptField, ComputedField } from "../../new_fields/ScriptField"; +import { ScriptField, ComputedField } from "../../fields/ScriptField"; import { Scripting } from "../util/Scripting"; -import { List } from "../../new_fields/List"; +import { List } from "../../fields/List"; @observer class TemplateToggle extends React.Component<{ template: Template, checked: boolean, toggle: (event: React.ChangeEvent, template: Template) => void }> { diff --git a/src/client/views/animationtimeline/Keyframe.tsx b/src/client/views/animationtimeline/Keyframe.tsx index bbd7b2676..92b0f05b3 100644 --- a/src/client/views/animationtimeline/Keyframe.tsx +++ b/src/client/views/animationtimeline/Keyframe.tsx @@ -4,10 +4,10 @@ import "./Timeline.scss"; import "../globalCssVariables.scss"; import { observer } from "mobx-react"; import { observable, reaction, action, IReactionDisposer, observe, computed, runInAction, trace } from "mobx"; -import { Doc, DocListCast, DocListCastAsync, Opt } from "../../../new_fields/Doc"; -import { Cast, NumCast } from "../../../new_fields/Types"; -import { List } from "../../../new_fields/List"; -import { createSchema, defaultSpec, makeInterface, listSpec } from "../../../new_fields/Schema"; +import { Doc, DocListCast, DocListCastAsync, Opt } from "../../../fields/Doc"; +import { Cast, NumCast } from "../../../fields/Types"; +import { List } from "../../../fields/List"; +import { createSchema, defaultSpec, makeInterface, listSpec } from "../../../fields/Schema"; import { Transform } from "../../util/Transform"; import { TimelineMenu } from "./TimelineMenu"; import { Docs } from "../../documents/Documents"; diff --git a/src/client/views/animationtimeline/Timeline.tsx b/src/client/views/animationtimeline/Timeline.tsx index 466cbb867..30692944d 100644 --- a/src/client/views/animationtimeline/Timeline.tsx +++ b/src/client/views/animationtimeline/Timeline.tsx @@ -1,12 +1,12 @@ import * as React from "react"; import "./Timeline.scss"; -import { listSpec } from "../../../new_fields/Schema"; +import { listSpec } from "../../../fields/Schema"; import { observer } from "mobx-react"; import { Track } from "./Track"; import { observable, action, computed, runInAction, IReactionDisposer, reaction, trace } from "mobx"; -import { Cast, NumCast, StrCast, BoolCast } from "../../../new_fields/Types"; -import { List } from "../../../new_fields/List"; -import { Doc, DocListCast } from "../../../new_fields/Doc"; +import { Cast, NumCast, StrCast, BoolCast } from "../../../fields/Types"; +import { List } from "../../../fields/List"; +import { Doc, DocListCast } from "../../../fields/Doc"; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faPlayCircle, faBackward, faForward, faGripLines, faPauseCircle, faEyeSlash, faEye, faCheckCircle, faTimesCircle } from "@fortawesome/free-solid-svg-icons"; import { ContextMenu } from "../ContextMenu"; diff --git a/src/client/views/animationtimeline/Track.tsx b/src/client/views/animationtimeline/Track.tsx index 461db4858..fc96c320a 100644 --- a/src/client/views/animationtimeline/Track.tsx +++ b/src/client/views/animationtimeline/Track.tsx @@ -1,12 +1,12 @@ import { action, computed, intercept, observable, reaction, runInAction } from "mobx"; import { observer } from "mobx-react"; import * as React from "react"; -import { Doc, DocListCast, Opt, DocListCastAsync } from "../../../new_fields/Doc"; -import { Copy } from "../../../new_fields/FieldSymbols"; -import { List } from "../../../new_fields/List"; -import { ObjectField } from "../../../new_fields/ObjectField"; -import { listSpec } from "../../../new_fields/Schema"; -import { Cast, NumCast } from "../../../new_fields/Types"; +import { Doc, DocListCast, Opt, DocListCastAsync } from "../../../fields/Doc"; +import { Copy } from "../../../fields/FieldSymbols"; +import { List } from "../../../fields/List"; +import { ObjectField } from "../../../fields/ObjectField"; +import { listSpec } from "../../../fields/Schema"; +import { Cast, NumCast } from "../../../fields/Types"; import { Transform } from "../../util/Transform"; import { Keyframe, KeyframeFunc, RegionData } from "./Keyframe"; import "./Track.scss"; diff --git a/src/client/views/collections/CollectionCarouselView.tsx b/src/client/views/collections/CollectionCarouselView.tsx index a04136e51..39bb9bc23 100644 --- a/src/client/views/collections/CollectionCarouselView.tsx +++ b/src/client/views/collections/CollectionCarouselView.tsx @@ -2,18 +2,18 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { observable, computed } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; -import { documentSchema, collectionSchema } from '../../../new_fields/documentSchemas'; -import { makeInterface } from '../../../new_fields/Schema'; -import { NumCast, StrCast, ScriptCast, Cast } from '../../../new_fields/Types'; +import { documentSchema, collectionSchema } from '../../../fields/documentSchemas'; +import { makeInterface } from '../../../fields/Schema'; +import { NumCast, StrCast, ScriptCast, Cast } from '../../../fields/Types'; import { DragManager } from '../../util/DragManager'; import { ContentFittingDocumentView } from '../nodes/ContentFittingDocumentView'; import "./CollectionCarouselView.scss"; import { CollectionSubView } from './CollectionSubView'; import { faCaretLeft, faCaretRight } from '@fortawesome/free-solid-svg-icons'; -import { Doc } from '../../../new_fields/Doc'; +import { Doc } from '../../../fields/Doc'; import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox'; import { ContextMenu } from '../ContextMenu'; -import { ObjectField } from '../../../new_fields/ObjectField'; +import { ObjectField } from '../../../fields/ObjectField'; import { returnFalse } from '../../../Utils'; type CarouselDocument = makeInterface<[typeof documentSchema, typeof collectionSchema]>; diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 581625222..745476ef7 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -7,13 +7,13 @@ import { observer } from "mobx-react"; import * as ReactDOM from 'react-dom'; import Measure from "react-measure"; import * as GoldenLayout from "../../../client/goldenLayout"; -import { DateField } from '../../../new_fields/DateField'; -import { Doc, DocListCast, Field, Opt, DataSym } from "../../../new_fields/Doc"; -import { Id } from '../../../new_fields/FieldSymbols'; -import { List } from '../../../new_fields/List'; -import { FieldId } from "../../../new_fields/RefField"; -import { Cast, NumCast, StrCast } from "../../../new_fields/Types"; -import { TraceMobx } from '../../../new_fields/util'; +import { DateField } from '../../../fields/DateField'; +import { Doc, DocListCast, Field, Opt, DataSym } from "../../../fields/Doc"; +import { Id } from '../../../fields/FieldSymbols'; +import { List } from '../../../fields/List'; +import { FieldId } from "../../../fields/RefField"; +import { Cast, NumCast, StrCast } from "../../../fields/Types"; +import { TraceMobx } from '../../../fields/util'; import { emptyFunction, returnOne, returnTrue, Utils, returnZero } from "../../../Utils"; import { DocServer } from "../../DocServer"; import { Docs } from '../../documents/Documents'; @@ -196,15 +196,16 @@ export class CollectionDockingView extends React.Component => { - for (let i = 0; i < child.contentItems.length; i++) { - if (child.contentItems[i].isRow || child.contentItems[i].isColumn || child.contentItems[i].isStack) { - const val = replaceTab(doc, child.contentItems[i]); + for (const contentItem of child.contentItems) { + const { config, isStack, isRow, isColumn } = contentItem; + if (isRow || isColumn || isStack) { + const val = replaceTab(doc, contentItem); if (val) return val; - } else if (child.contentItems[i].config.component === "DocumentFrameRenderer" && - child.contentItems[i].config.props.documentId === doc[Id]) { + } else if (config.component === "DocumentFrameRenderer" && + config.props.documentId === doc[Id]) { const alias = Doc.MakeAlias(doc); - child.contentItems[i].config.props.documentId = alias[Id]; - child.contentItems[i].config.title = alias.title; + config.props.documentId = alias[Id]; + config.title = alias.title; instance.stateChanged(); return alias; } diff --git a/src/client/views/collections/CollectionLinearView.tsx b/src/client/views/collections/CollectionLinearView.tsx index 344dca23a..f1002044a 100644 --- a/src/client/views/collections/CollectionLinearView.tsx +++ b/src/client/views/collections/CollectionLinearView.tsx @@ -1,9 +1,9 @@ import { action, IReactionDisposer, observable, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; -import { Doc, HeightSym, WidthSym } from '../../../new_fields/Doc'; -import { makeInterface } from '../../../new_fields/Schema'; -import { BoolCast, NumCast, StrCast, Cast, ScriptCast } from '../../../new_fields/Types'; +import { Doc, HeightSym, WidthSym } from '../../../fields/Doc'; +import { makeInterface } from '../../../fields/Schema'; +import { BoolCast, NumCast, StrCast, Cast, ScriptCast } from '../../../fields/Types'; import { emptyFunction, returnEmptyString, returnOne, returnTrue, Utils, returnFalse, returnZero } from '../../../Utils'; import { DragManager } from '../../util/DragManager'; import { Transform } from '../../util/Transform'; @@ -11,8 +11,8 @@ import "./CollectionLinearView.scss"; import { CollectionViewType } from './CollectionView'; import { CollectionSubView } from './CollectionSubView'; import { DocumentView } from '../nodes/DocumentView'; -import { documentSchema } from '../../../new_fields/documentSchemas'; -import { Id } from '../../../new_fields/FieldSymbols'; +import { documentSchema } from '../../../fields/documentSchemas'; +import { Id } from '../../../fields/FieldSymbols'; type LinearDocument = makeInterface<[typeof documentSchema,]>; diff --git a/src/client/views/collections/CollectionMapView.tsx b/src/client/views/collections/CollectionMapView.tsx index 618285293..da902cecd 100644 --- a/src/client/views/collections/CollectionMapView.tsx +++ b/src/client/views/collections/CollectionMapView.tsx @@ -1,10 +1,10 @@ import { GoogleApiWrapper, Map as GeoMap, MapProps as IMapProps, Marker } from "google-maps-react"; import { observer } from "mobx-react"; -import { Doc, Opt, DocListCast, FieldResult, Field } from "../../../new_fields/Doc"; -import { documentSchema } from "../../../new_fields/documentSchemas"; -import { Id } from "../../../new_fields/FieldSymbols"; -import { makeInterface } from "../../../new_fields/Schema"; -import { Cast, NumCast, ScriptCast, StrCast } from "../../../new_fields/Types"; +import { Doc, Opt, DocListCast, FieldResult, Field } from "../../../fields/Doc"; +import { documentSchema } from "../../../fields/documentSchemas"; +import { Id } from "../../../fields/FieldSymbols"; +import { makeInterface } from "../../../fields/Schema"; +import { Cast, NumCast, ScriptCast, StrCast } from "../../../fields/Types"; import "./CollectionMapView.scss"; import { CollectionSubView } from "./CollectionSubView"; import React = require("react"); diff --git a/src/client/views/collections/CollectionMasonryViewFieldRow.tsx b/src/client/views/collections/CollectionMasonryViewFieldRow.tsx index 95c7643c9..d6cb174cc 100644 --- a/src/client/views/collections/CollectionMasonryViewFieldRow.tsx +++ b/src/client/views/collections/CollectionMasonryViewFieldRow.tsx @@ -4,10 +4,10 @@ import { faPalette } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { action, computed, observable, runInAction } from "mobx"; import { observer } from "mobx-react"; -import { Doc } from "../../../new_fields/Doc"; -import { PastelSchemaPalette, SchemaHeaderField } from "../../../new_fields/SchemaHeaderField"; -import { ScriptField } from "../../../new_fields/ScriptField"; -import { StrCast, NumCast } from "../../../new_fields/Types"; +import { Doc } from "../../../fields/Doc"; +import { PastelSchemaPalette, SchemaHeaderField } from "../../../fields/SchemaHeaderField"; +import { ScriptField } from "../../../fields/ScriptField"; +import { StrCast, NumCast } from "../../../fields/Types"; import { numberRange, setupMoveUpEvents, emptyFunction } from "../../../Utils"; import { Docs } from "../../documents/Documents"; import { DragManager } from "../../util/DragManager"; diff --git a/src/client/views/collections/CollectionPileView.tsx b/src/client/views/collections/CollectionPileView.tsx index d3ae21f3a..e3bcf2a21 100644 --- a/src/client/views/collections/CollectionPileView.tsx +++ b/src/client/views/collections/CollectionPileView.tsx @@ -1,8 +1,8 @@ import { action, computed, observable, runInAction } from "mobx"; import { observer } from "mobx-react"; -import { HeightSym, Opt, WidthSym } from "../../../new_fields/Doc"; -import { ScriptField } from "../../../new_fields/ScriptField"; -import { BoolCast, NumCast, StrCast } from "../../../new_fields/Types"; +import { HeightSym, Opt, WidthSym } from "../../../fields/Doc"; +import { ScriptField } from "../../../fields/ScriptField"; +import { BoolCast, NumCast, StrCast } from "../../../fields/Types"; import { ContextMenu } from "../ContextMenu"; import { ContextMenuProps } from "../ContextMenuItem"; import { CollectionFreeFormView } from "./collectionFreeForm/CollectionFreeFormView"; diff --git a/src/client/views/collections/CollectionSchemaCells.tsx b/src/client/views/collections/CollectionSchemaCells.tsx index 8a5450b0c..62aed67ed 100644 --- a/src/client/views/collections/CollectionSchemaCells.tsx +++ b/src/client/views/collections/CollectionSchemaCells.tsx @@ -4,8 +4,8 @@ import { observer } from "mobx-react"; import { CellInfo } from "react-table"; import "react-table/react-table.css"; import { emptyFunction, returnFalse, returnZero, returnOne } from "../../../Utils"; -import { Doc, DocListCast, Field, Opt } from "../../../new_fields/Doc"; -import { Id } from "../../../new_fields/FieldSymbols"; +import { Doc, DocListCast, Field, Opt } from "../../../fields/Doc"; +import { Id } from "../../../fields/FieldSymbols"; import { KeyCodes } from "../../util/KeyCodes"; import { SetupDrag, DragManager } from "../../util/DragManager"; import { CompileScript } from "../../util/Scripting"; @@ -16,11 +16,11 @@ import { EditableView } from "../EditableView"; import { FieldView, FieldViewProps } from "../nodes/FieldView"; import "./CollectionSchemaView.scss"; import { CollectionView } from "./CollectionView"; -import { NumCast, StrCast, BoolCast, FieldValue, Cast } from "../../../new_fields/Types"; +import { NumCast, StrCast, BoolCast, FieldValue, Cast } from "../../../fields/Types"; import { Docs } from "../../documents/Documents"; import { library } from '@fortawesome/fontawesome-svg-core'; import { faExpand } from '@fortawesome/free-solid-svg-icons'; -import { SchemaHeaderField } from "../../../new_fields/SchemaHeaderField"; +import { SchemaHeaderField } from "../../../fields/SchemaHeaderField"; import { undoBatch } from "../../util/UndoManager"; import { SnappingManager } from "../../util/SnappingManager"; diff --git a/src/client/views/collections/CollectionSchemaHeaders.tsx b/src/client/views/collections/CollectionSchemaHeaders.tsx index 507ee89e4..dae0600b1 100644 --- a/src/client/views/collections/CollectionSchemaHeaders.tsx +++ b/src/client/views/collections/CollectionSchemaHeaders.tsx @@ -7,7 +7,7 @@ import { library, IconProp } from "@fortawesome/fontawesome-svg-core"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { ColumnType } from "./CollectionSchemaView"; import { faFile } from "@fortawesome/free-regular-svg-icons"; -import { SchemaHeaderField, PastelSchemaPalette } from "../../../new_fields/SchemaHeaderField"; +import { SchemaHeaderField, PastelSchemaPalette } from "../../../fields/SchemaHeaderField"; import { undoBatch } from "../../util/UndoManager"; const higflyout = require("@hig/flyout"); export const { anchorPoints } = higflyout; diff --git a/src/client/views/collections/CollectionSchemaMovableTableHOC.tsx b/src/client/views/collections/CollectionSchemaMovableTableHOC.tsx index 5aec46a83..6f1e8ac1f 100644 --- a/src/client/views/collections/CollectionSchemaMovableTableHOC.tsx +++ b/src/client/views/collections/CollectionSchemaMovableTableHOC.tsx @@ -2,16 +2,16 @@ import React = require("react"); import { ReactTableDefaults, TableCellRenderer, RowInfo } from "react-table"; import "./CollectionSchemaView.scss"; import { Transform } from "../../util/Transform"; -import { Doc } from "../../../new_fields/Doc"; +import { Doc } from "../../../fields/Doc"; import { DragManager, SetupDrag, dropActionType } from "../../util/DragManager"; -import { Cast, FieldValue, StrCast } from "../../../new_fields/Types"; +import { Cast, FieldValue, StrCast } from "../../../fields/Types"; import { ContextMenu } from "../ContextMenu"; import { action } from "mobx"; import { library } from '@fortawesome/fontawesome-svg-core'; import { faGripVertical, faTrash } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { DocumentManager } from "../../util/DocumentManager"; -import { SchemaHeaderField } from "../../../new_fields/SchemaHeaderField"; +import { SchemaHeaderField } from "../../../fields/SchemaHeaderField"; import { undoBatch } from "../../util/UndoManager"; import { SnappingManager } from "../../util/SnappingManager"; diff --git a/src/client/views/collections/CollectionSchemaView.tsx b/src/client/views/collections/CollectionSchemaView.tsx index 51ad6c81b..35f892d65 100644 --- a/src/client/views/collections/CollectionSchemaView.tsx +++ b/src/client/views/collections/CollectionSchemaView.tsx @@ -6,13 +6,13 @@ import { action, computed, observable, untracked } from "mobx"; import { observer } from "mobx-react"; import ReactTable, { CellInfo, Column, ComponentPropsGetterR, Resize, SortingRule } from "react-table"; import "react-table/react-table.css"; -import { Doc, DocListCast, Field, Opt } from "../../../new_fields/Doc"; -import { Id } from "../../../new_fields/FieldSymbols"; -import { List } from "../../../new_fields/List"; -import { listSpec } from "../../../new_fields/Schema"; -import { SchemaHeaderField } from "../../../new_fields/SchemaHeaderField"; -import { ComputedField } from "../../../new_fields/ScriptField"; -import { Cast, FieldValue, NumCast, StrCast, BoolCast } from "../../../new_fields/Types"; +import { Doc, DocListCast, Field, Opt } from "../../../fields/Doc"; +import { Id } from "../../../fields/FieldSymbols"; +import { List } from "../../../fields/List"; +import { listSpec } from "../../../fields/Schema"; +import { SchemaHeaderField } from "../../../fields/SchemaHeaderField"; +import { ComputedField } from "../../../fields/ScriptField"; +import { Cast, FieldValue, NumCast, StrCast, BoolCast } from "../../../fields/Types"; import { Docs, DocumentOptions } from "../../documents/Documents"; import { CompileScript, Transformer, ts } from "../../util/Scripting"; import { Transform } from "../../util/Transform"; diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index d97f26daf..cc6077d98 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -4,14 +4,14 @@ import { CursorProperty } from "csstype"; import { action, computed, IReactionDisposer, observable, reaction, runInAction } from "mobx"; import { observer } from "mobx-react"; import Switch from 'rc-switch'; -import { DataSym, Doc, HeightSym, WidthSym } from "../../../new_fields/Doc"; -import { collectionSchema, documentSchema } from "../../../new_fields/documentSchemas"; -import { Id } from "../../../new_fields/FieldSymbols"; -import { List } from "../../../new_fields/List"; -import { listSpec, makeInterface } from "../../../new_fields/Schema"; -import { SchemaHeaderField } from "../../../new_fields/SchemaHeaderField"; -import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from "../../../new_fields/Types"; -import { TraceMobx } from "../../../new_fields/util"; +import { DataSym, Doc, HeightSym, WidthSym } from "../../../fields/Doc"; +import { collectionSchema, documentSchema } from "../../../fields/documentSchemas"; +import { Id } from "../../../fields/FieldSymbols"; +import { List } from "../../../fields/List"; +import { listSpec, makeInterface } from "../../../fields/Schema"; +import { SchemaHeaderField } from "../../../fields/SchemaHeaderField"; +import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from "../../../fields/Types"; +import { TraceMobx } from "../../../fields/util"; import { emptyFunction, returnFalse, returnOne, returnZero, setupMoveUpEvents, Utils, smoothScroll } from "../../../Utils"; import { DragManager, dropActionType } from "../../util/DragManager"; import { Transform } from "../../util/Transform"; diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx index dccef7983..53435ccc9 100644 --- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx +++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx @@ -4,13 +4,13 @@ import { faPalette } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { action, observable, runInAction } from "mobx"; import { observer } from "mobx-react"; -import { Doc, DocListCast } from "../../../new_fields/Doc"; -import { RichTextField } from "../../../new_fields/RichTextField"; -import { PastelSchemaPalette, SchemaHeaderField } from "../../../new_fields/SchemaHeaderField"; -import { ScriptField } from "../../../new_fields/ScriptField"; -import { NumCast, StrCast, Cast } from "../../../new_fields/Types"; -import { ImageField } from "../../../new_fields/URLField"; -import { TraceMobx } from "../../../new_fields/util"; +import { Doc, DocListCast } from "../../../fields/Doc"; +import { RichTextField } from "../../../fields/RichTextField"; +import { PastelSchemaPalette, SchemaHeaderField } from "../../../fields/SchemaHeaderField"; +import { ScriptField } from "../../../fields/ScriptField"; +import { NumCast, StrCast, Cast } from "../../../fields/Types"; +import { ImageField } from "../../../fields/URLField"; +import { TraceMobx } from "../../../fields/util"; import { Docs, DocUtils } from "../../documents/Documents"; import { DragManager } from "../../util/DragManager"; import { Transform } from "../../util/Transform"; @@ -21,7 +21,7 @@ import { EditableView } from "../EditableView"; import { CollectionStackingView } from "./CollectionStackingView"; import { setupMoveUpEvents, emptyFunction } from "../../../Utils"; import "./CollectionStackingView.scss"; -import { listSpec } from "../../../new_fields/Schema"; +import { listSpec } from "../../../fields/Schema"; import { SnappingManager } from "../../util/SnappingManager"; const higflyout = require("@hig/flyout"); export const { anchorPoints } = higflyout; diff --git a/src/client/views/collections/CollectionStaffView.tsx b/src/client/views/collections/CollectionStaffView.tsx index 5b9a69bf7..c5c3f96e8 100644 --- a/src/client/views/collections/CollectionStaffView.tsx +++ b/src/client/views/collections/CollectionStaffView.tsx @@ -1,7 +1,7 @@ import { CollectionSubView } from "./CollectionSubView"; import React = require("react"); import { computed, action, IReactionDisposer, reaction, runInAction, observable } from "mobx"; -import { NumCast } from "../../../new_fields/Types"; +import { NumCast } from "../../../fields/Types"; import "./CollectionStaffView.scss"; import { observer } from "mobx-react"; diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index bff6d121b..a4e843c8e 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -1,12 +1,12 @@ import { action, computed, IReactionDisposer, reaction } from "mobx"; import { basename } from 'path'; -import CursorField from "../../../new_fields/CursorField"; -import { Doc, Opt } from "../../../new_fields/Doc"; -import { Id } from "../../../new_fields/FieldSymbols"; -import { List } from "../../../new_fields/List"; -import { listSpec } from "../../../new_fields/Schema"; -import { ScriptField } from "../../../new_fields/ScriptField"; -import { Cast, ScriptCast } from "../../../new_fields/Types"; +import CursorField from "../../../fields/CursorField"; +import { Doc, 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 { Cast, ScriptCast } from "../../../fields/Types"; import { GestureUtils } from "../../../pen-gestures/GestureUtils"; import { CurrentUserUtils } from "../../util/CurrentUserUtils"; import { Upload } from "../../../server/SharedMediaTypes"; diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx index a2d4774c8..15bc0bfd5 100644 --- a/src/client/views/collections/CollectionTimeView.tsx +++ b/src/client/views/collections/CollectionTimeView.tsx @@ -1,11 +1,11 @@ import { action, computed, observable, runInAction } from "mobx"; import { observer } from "mobx-react"; -import { Doc, Opt, DocCastAsync } from "../../../new_fields/Doc"; -import { List } from "../../../new_fields/List"; -import { ObjectField } from "../../../new_fields/ObjectField"; -import { RichTextField } from "../../../new_fields/RichTextField"; -import { ComputedField, ScriptField } from "../../../new_fields/ScriptField"; -import { NumCast, StrCast, BoolCast, Cast } from "../../../new_fields/Types"; +import { Doc, Opt, DocCastAsync } from "../../../fields/Doc"; +import { List } from "../../../fields/List"; +import { ObjectField } from "../../../fields/ObjectField"; +import { RichTextField } from "../../../fields/RichTextField"; +import { ComputedField, ScriptField } from "../../../fields/ScriptField"; +import { NumCast, StrCast, BoolCast, Cast } from "../../../fields/Types"; import { emptyFunction, returnFalse, setupMoveUpEvents } from "../../../Utils"; import { Scripting } from "../../util/Scripting"; import { ContextMenu } from "../ContextMenu"; diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 2f332e77d..3e99af724 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -1,13 +1,13 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, computed, observable } from "mobx"; import { observer } from "mobx-react"; -import { DataSym, Doc, DocListCast, Field, HeightSym, Opt, WidthSym } from '../../../new_fields/Doc'; -import { Id } from '../../../new_fields/FieldSymbols'; -import { List } from '../../../new_fields/List'; -import { PrefetchProxy } from '../../../new_fields/Proxy'; -import { Document, listSpec } from '../../../new_fields/Schema'; -import { ComputedField, ScriptField } from '../../../new_fields/ScriptField'; -import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from '../../../new_fields/Types'; +import { DataSym, Doc, DocListCast, Field, HeightSym, Opt, WidthSym } from '../../../fields/Doc'; +import { Id } from '../../../fields/FieldSymbols'; +import { List } from '../../../fields/List'; +import { PrefetchProxy } from '../../../fields/Proxy'; +import { Document, listSpec } from '../../../fields/Schema'; +import { ComputedField, ScriptField } from '../../../fields/ScriptField'; +import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from '../../../fields/Types'; import { emptyFunction, emptyPath, returnFalse, returnOne, returnTrue, returnZero, simulateMouseClick, Utils } from '../../../Utils'; import { Docs, DocUtils } from '../../documents/Documents'; import { DocumentType } from "../../documents/DocumentTypes"; @@ -32,7 +32,7 @@ import "./CollectionTreeView.scss"; import { CollectionViewType } from './CollectionView'; import React = require("react"); import { makeTemplate } from '../../util/DropConverter'; -import { TraceMobx } from '../../../new_fields/util'; +import { TraceMobx } from '../../../fields/util'; export interface TreeViewProps { document: Doc; diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 4b3b2e234..3b2e5e4fc 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -7,12 +7,12 @@ import { observer } from "mobx-react"; import * as React from 'react'; import Lightbox from 'react-image-lightbox-with-rotate'; import 'react-image-lightbox-with-rotate/style.css'; // This only needs to be imported once in your app -import { DateField } from '../../../new_fields/DateField'; -import { DataSym, Doc, DocListCast, Field, Opt } from '../../../new_fields/Doc'; -import { List } from '../../../new_fields/List'; -import { BoolCast, Cast, NumCast, StrCast, ScriptCast } from '../../../new_fields/Types'; -import { ImageField } from '../../../new_fields/URLField'; -import { TraceMobx } from '../../../new_fields/util'; +import { DateField } from '../../../fields/DateField'; +import { DataSym, Doc, DocListCast, Field, Opt } from '../../../fields/Doc'; +import { List } from '../../../fields/List'; +import { BoolCast, Cast, NumCast, StrCast, ScriptCast } from '../../../fields/Types'; +import { ImageField } from '../../../fields/URLField'; +import { TraceMobx } from '../../../fields/util'; import { Utils, setupMoveUpEvents, returnFalse, returnZero, emptyPath, emptyFunction, returnOne } from '../../../Utils'; import { DocumentType } from '../../documents/DocumentTypes'; import { ImageUtils } from '../../util/Import & Export/ImageUtils'; @@ -36,12 +36,12 @@ import { CollectionTreeView } from "./CollectionTreeView"; import './CollectionView.scss'; import { CollectionViewBaseChrome } from './CollectionViewChromes'; import { CurrentUserUtils } from '../../util/CurrentUserUtils'; -import { Id } from '../../../new_fields/FieldSymbols'; -import { listSpec } from '../../../new_fields/Schema'; +import { Id } from '../../../fields/FieldSymbols'; +import { listSpec } from '../../../fields/Schema'; import { Docs } from '../../documents/Documents'; -import { ScriptField, ComputedField } from '../../../new_fields/ScriptField'; +import { ScriptField, ComputedField } from '../../../fields/ScriptField'; import { InteractionUtils } from '../../util/InteractionUtils'; -import { ObjectField } from '../../../new_fields/ObjectField'; +import { ObjectField } from '../../../fields/ObjectField'; import CollectionMapView from './CollectionMapView'; import { CollectionPileView } from './CollectionPileView'; const higflyout = require("@hig/flyout"); diff --git a/src/client/views/collections/CollectionViewChromes.tsx b/src/client/views/collections/CollectionViewChromes.tsx index 62b03bbdc..5dc0b09ac 100644 --- a/src/client/views/collections/CollectionViewChromes.tsx +++ b/src/client/views/collections/CollectionViewChromes.tsx @@ -2,11 +2,11 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { action, computed, observable, runInAction } from "mobx"; import { observer } from "mobx-react"; import * as React from "react"; -import { Doc, DocListCast } from "../../../new_fields/Doc"; -import { Id } from "../../../new_fields/FieldSymbols"; -import { List } from "../../../new_fields/List"; -import { listSpec } from "../../../new_fields/Schema"; -import { BoolCast, Cast, NumCast, StrCast } from "../../../new_fields/Types"; +import { Doc, DocListCast } from "../../../fields/Doc"; +import { Id } from "../../../fields/FieldSymbols"; +import { List } from "../../../fields/List"; +import { listSpec } from "../../../fields/Schema"; +import { BoolCast, Cast, NumCast, StrCast } from "../../../fields/Types"; import { Utils, emptyFunction, setupMoveUpEvents } from "../../../Utils"; import { DragManager } from "../../util/DragManager"; import { undoBatch } from "../../util/UndoManager"; diff --git a/src/client/views/collections/ParentDocumentSelector.tsx b/src/client/views/collections/ParentDocumentSelector.tsx index 6e4f801c0..649406e6c 100644 --- a/src/client/views/collections/ParentDocumentSelector.tsx +++ b/src/client/views/collections/ParentDocumentSelector.tsx @@ -1,12 +1,12 @@ import * as React from "react"; import './ParentDocumentSelector.scss'; -import { Doc } from "../../../new_fields/Doc"; +import { Doc } from "../../../fields/Doc"; import { observer } from "mobx-react"; import { observable, action, runInAction, trace, computed, reaction, IReactionDisposer } from "mobx"; -import { Id } from "../../../new_fields/FieldSymbols"; +import { Id } from "../../../fields/FieldSymbols"; import { SearchUtil } from "../../util/SearchUtil"; import { CollectionDockingView } from "./CollectionDockingView"; -import { NumCast, StrCast } from "../../../new_fields/Types"; +import { NumCast, StrCast } from "../../../fields/Types"; import { CollectionViewType } from "./CollectionView"; import { DocumentButtonBar } from "../DocumentButtonBar"; import { DocumentManager } from "../../util/DocumentManager"; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx index 9a864078a..3860ce2d7 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx @@ -1,15 +1,15 @@ -import { Doc, Field, FieldResult, WidthSym, HeightSym } from "../../../../new_fields/Doc"; -import { NumCast, StrCast, Cast } from "../../../../new_fields/Types"; +import { Doc, Field, FieldResult, WidthSym, HeightSym } from "../../../../fields/Doc"; +import { NumCast, StrCast, Cast } from "../../../../fields/Types"; import { ScriptBox } from "../../ScriptBox"; import { CompileScript } from "../../../util/Scripting"; -import { ScriptField } from "../../../../new_fields/ScriptField"; +import { ScriptField } from "../../../../fields/ScriptField"; import { OverlayView, OverlayElementOptions } from "../../OverlayView"; import { emptyFunction, aggregateBounds } from "../../../../Utils"; import React = require("react"); -import { Id, ToString } from "../../../../new_fields/FieldSymbols"; -import { ObjectField } from "../../../../new_fields/ObjectField"; -import { RefField } from "../../../../new_fields/RefField"; -import { listSpec } from "../../../../new_fields/Schema"; +import { Id, ToString } from "../../../../fields/FieldSymbols"; +import { ObjectField } from "../../../../fields/ObjectField"; +import { RefField } from "../../../../fields/RefField"; +import { listSpec } from "../../../../fields/Schema"; export interface ViewDefBounds { type: string; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx index ba71aff32..f3fc04752 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx @@ -1,5 +1,5 @@ import { observer } from "mobx-react"; -import { Doc } from "../../../../new_fields/Doc"; +import { Doc } from "../../../../fields/Doc"; import { Utils } from '../../../../Utils'; import { DocumentView } from "../../nodes/DocumentView"; import "./CollectionFreeFormLinkView.scss"; @@ -7,8 +7,8 @@ import React = require("react"); import v5 = require("uuid/v5"); import { DocumentType } from "../../../documents/DocumentTypes"; import { observable, action, reaction, IReactionDisposer } from "mobx"; -import { StrCast, Cast } from "../../../../new_fields/Types"; -import { Id } from "../../../../new_fields/FieldSymbols"; +import { StrCast, Cast } from "../../../../fields/Types"; +import { Id } from "../../../../fields/FieldSymbols"; import { SnappingManager } from "../../../util/SnappingManager"; export interface CollectionFreeFormLinkViewProps { diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx index 1208fb324..ae81b4b36 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx @@ -1,7 +1,7 @@ import { computed } from "mobx"; import { observer } from "mobx-react"; -import { Doc } from "../../../../new_fields/Doc"; -import { Id } from "../../../../new_fields/FieldSymbols"; +import { Doc } from "../../../../fields/Doc"; +import { Id } from "../../../../fields/FieldSymbols"; import { DocumentManager } from "../../../util/DocumentManager"; import { DocumentView } from "../../nodes/DocumentView"; import "./CollectionFreeFormLinksView.scss"; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx index 9a5b2c27c..548ad78a5 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormRemoteCursors.tsx @@ -1,16 +1,16 @@ import { observer } from "mobx-react"; import * as mobxUtils from 'mobx-utils'; -import CursorField from "../../../../new_fields/CursorField"; -import { listSpec } from "../../../../new_fields/Schema"; -import { Cast } from "../../../../new_fields/Types"; +import CursorField from "../../../../fields/CursorField"; +import { listSpec } from "../../../../fields/Schema"; +import { Cast } from "../../../../fields/Types"; import { CurrentUserUtils } from "../../../util/CurrentUserUtils"; import { CollectionViewProps } from "../CollectionSubView"; import "./CollectionFreeFormView.scss"; import React = require("react"); import v5 = require("uuid/v5"); import { computed } from "mobx"; -import { FieldResult } from "../../../../new_fields/Doc"; -import { List } from "../../../../new_fields/List"; +import { FieldResult } from "../../../../fields/Doc"; +import { List } from "../../../../fields/List"; @observer export class CollectionFreeFormRemoteCursors extends React.Component { diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 6c4660c39..fb8bd25da 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -4,16 +4,16 @@ import { faBraille, faChalkboard, faCompass, faCompressArrowsAlt, faExpandArrows import { action, computed, IReactionDisposer, observable, ObservableMap, reaction, runInAction, _allowStateChangesInsideComputed } from "mobx"; import { observer } from "mobx-react"; import { computedFn } from "mobx-utils"; -import { Doc, HeightSym, Opt, WidthSym, DocListCast } from "../../../../new_fields/Doc"; -import { documentSchema, collectionSchema } from "../../../../new_fields/documentSchemas"; -import { Id } from "../../../../new_fields/FieldSymbols"; -import { InkData, InkField, InkTool, PointData } from "../../../../new_fields/InkField"; -import { List } from "../../../../new_fields/List"; -import { RichTextField } from "../../../../new_fields/RichTextField"; -import { createSchema, listSpec, makeInterface } from "../../../../new_fields/Schema"; -import { ScriptField } from "../../../../new_fields/ScriptField"; -import { BoolCast, Cast, FieldValue, NumCast, ScriptCast, StrCast } from "../../../../new_fields/Types"; -import { TraceMobx } from "../../../../new_fields/util"; +import { Doc, HeightSym, Opt, WidthSym, DocListCast } from "../../../../fields/Doc"; +import { documentSchema, collectionSchema } from "../../../../fields/documentSchemas"; +import { Id } from "../../../../fields/FieldSymbols"; +import { InkData, InkField, InkTool, PointData } from "../../../../fields/InkField"; +import { List } from "../../../../fields/List"; +import { RichTextField } from "../../../../fields/RichTextField"; +import { createSchema, listSpec, makeInterface } from "../../../../fields/Schema"; +import { ScriptField } from "../../../../fields/ScriptField"; +import { BoolCast, Cast, FieldValue, NumCast, ScriptCast, StrCast } from "../../../../fields/Types"; +import { TraceMobx } from "../../../../fields/util"; import { GestureUtils } from "../../../../pen-gestures/GestureUtils"; import { aggregateBounds, intersectRect, returnOne, Utils, returnZero, returnFalse } from "../../../../Utils"; import { CognitiveServices } from "../../../cognitive_services/CognitiveServices"; @@ -1034,8 +1034,7 @@ export class CollectionFreeFormView extends CollectionSubView { - for (let i = 0; i < array.length; i++) { - const entry = array[i]; + for (const entry of array) { const lastPos = this._cachedPool.get(entry[0]); // last computed pos const newPos = entry[1]; if (!lastPos || newPos.x !== lastPos.x || newPos.y !== lastPos.y || newPos.z !== lastPos.z || newPos.zIndex !== lastPos.zIndex) { diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 8e20b39d2..04d37934e 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -1,11 +1,11 @@ import { action, computed, observable } from "mobx"; import { observer } from "mobx-react"; -import { Doc, Opt } from "../../../../new_fields/Doc"; -import { InkData, InkField } from "../../../../new_fields/InkField"; -import { List } from "../../../../new_fields/List"; -import { RichTextField } from "../../../../new_fields/RichTextField"; -import { SchemaHeaderField } from "../../../../new_fields/SchemaHeaderField"; -import { Cast, FieldValue, NumCast, StrCast } from "../../../../new_fields/Types"; +import { Doc, Opt } from "../../../../fields/Doc"; +import { InkData, InkField } from "../../../../fields/InkField"; +import { List } from "../../../../fields/List"; +import { RichTextField } from "../../../../fields/RichTextField"; +import { SchemaHeaderField } from "../../../../fields/SchemaHeaderField"; +import { Cast, FieldValue, NumCast, StrCast } from "../../../../fields/Types"; import { Utils } from "../../../../Utils"; import { CognitiveServices } from "../../../cognitive_services/CognitiveServices"; import { Docs, DocumentOptions, DocUtils } from "../../../documents/Documents"; diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx index a09124304..c0e1a0232 100644 --- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx +++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx @@ -1,10 +1,10 @@ import { action, computed } from 'mobx'; import { observer } from 'mobx-react'; import * as React from "react"; -import { Doc } from '../../../../new_fields/Doc'; -import { documentSchema } from '../../../../new_fields/documentSchemas'; -import { makeInterface } from '../../../../new_fields/Schema'; -import { BoolCast, NumCast, ScriptCast, StrCast, Cast } from '../../../../new_fields/Types'; +import { Doc } from '../../../../fields/Doc'; +import { documentSchema } from '../../../../fields/documentSchemas'; +import { makeInterface } from '../../../../fields/Schema'; +import { BoolCast, NumCast, ScriptCast, StrCast, Cast } from '../../../../fields/Types'; import { DragManager, dropActionType } from '../../../util/DragManager'; import { Transform } from '../../../util/Transform'; import { undoBatch } from '../../../util/UndoManager'; @@ -13,7 +13,7 @@ import { CollectionSubView } from '../CollectionSubView'; import "./collectionMulticolumnView.scss"; import ResizeBar from './MulticolumnResizer'; import WidthLabel from './MulticolumnWidthLabel'; -import { List } from '../../../../new_fields/List'; +import { List } from '../../../../fields/List'; import { returnZero, returnFalse, returnOne } from '../../../../Utils'; type MulticolumnDocument = makeInterface<[typeof documentSchema]>; diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx index 4326723b1..602246d07 100644 --- a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx +++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx @@ -1,10 +1,10 @@ import { observer } from 'mobx-react'; -import { makeInterface } from '../../../../new_fields/Schema'; -import { documentSchema } from '../../../../new_fields/documentSchemas'; +import { makeInterface } from '../../../../fields/Schema'; +import { documentSchema } from '../../../../fields/documentSchemas'; import { CollectionSubView, SubCollectionViewProps } from '../CollectionSubView'; import * as React from "react"; -import { Doc } from '../../../../new_fields/Doc'; -import { NumCast, StrCast, BoolCast, ScriptCast } from '../../../../new_fields/Types'; +import { Doc } from '../../../../fields/Doc'; +import { NumCast, StrCast, BoolCast, ScriptCast } from '../../../../fields/Types'; import { ContentFittingDocumentView } from '../../nodes/ContentFittingDocumentView'; import { Utils, returnZero, returnFalse, returnOne } from '../../../../Utils'; import "./collectionMultirowView.scss"; @@ -14,7 +14,7 @@ import HeightLabel from './MultirowHeightLabel'; import ResizeBar from './MultirowResizer'; import { undoBatch } from '../../../util/UndoManager'; import { DragManager, dropActionType } from '../../../util/DragManager'; -import { List } from '../../../../new_fields/List'; +import { List } from '../../../../fields/List'; type MultirowDocument = makeInterface<[typeof documentSchema]>; const MultirowDocument = makeInterface(documentSchema); diff --git a/src/client/views/collections/collectionMulticolumn/MulticolumnResizer.tsx b/src/client/views/collections/collectionMulticolumn/MulticolumnResizer.tsx index a24eb1631..734915a93 100644 --- a/src/client/views/collections/collectionMulticolumn/MulticolumnResizer.tsx +++ b/src/client/views/collections/collectionMulticolumn/MulticolumnResizer.tsx @@ -1,8 +1,8 @@ import * as React from "react"; import { observer } from "mobx-react"; import { observable, action } from "mobx"; -import { Doc } from "../../../../new_fields/Doc"; -import { NumCast, StrCast } from "../../../../new_fields/Types"; +import { Doc } from "../../../../fields/Doc"; +import { NumCast, StrCast } from "../../../../fields/Types"; import { DimUnit } from "./CollectionMulticolumnView"; import { UndoManager } from "../../../util/UndoManager"; diff --git a/src/client/views/collections/collectionMulticolumn/MulticolumnWidthLabel.tsx b/src/client/views/collections/collectionMulticolumn/MulticolumnWidthLabel.tsx index 5b2054428..9985a9fba 100644 --- a/src/client/views/collections/collectionMulticolumn/MulticolumnWidthLabel.tsx +++ b/src/client/views/collections/collectionMulticolumn/MulticolumnWidthLabel.tsx @@ -1,8 +1,8 @@ import * as React from "react"; import { observer } from "mobx-react"; import { computed } from "mobx"; -import { Doc } from "../../../../new_fields/Doc"; -import { NumCast, StrCast, BoolCast } from "../../../../new_fields/Types"; +import { Doc } from "../../../../fields/Doc"; +import { NumCast, StrCast, BoolCast } from "../../../../fields/Types"; import { EditableView } from "../../EditableView"; import { DimUnit } from "./CollectionMulticolumnView"; diff --git a/src/client/views/collections/collectionMulticolumn/MultirowHeightLabel.tsx b/src/client/views/collections/collectionMulticolumn/MultirowHeightLabel.tsx index 899577fd5..aa5439fa4 100644 --- a/src/client/views/collections/collectionMulticolumn/MultirowHeightLabel.tsx +++ b/src/client/views/collections/collectionMulticolumn/MultirowHeightLabel.tsx @@ -1,8 +1,8 @@ import * as React from "react"; import { observer } from "mobx-react"; import { computed } from "mobx"; -import { Doc } from "../../../../new_fields/Doc"; -import { NumCast, StrCast, BoolCast } from "../../../../new_fields/Types"; +import { Doc } from "../../../../fields/Doc"; +import { NumCast, StrCast, BoolCast } from "../../../../fields/Types"; import { EditableView } from "../../EditableView"; import { DimUnit } from "./CollectionMultirowView"; diff --git a/src/client/views/collections/collectionMulticolumn/MultirowResizer.tsx b/src/client/views/collections/collectionMulticolumn/MultirowResizer.tsx index 5f00b18b9..d0bc4d01c 100644 --- a/src/client/views/collections/collectionMulticolumn/MultirowResizer.tsx +++ b/src/client/views/collections/collectionMulticolumn/MultirowResizer.tsx @@ -1,8 +1,8 @@ import * as React from "react"; import { observer } from "mobx-react"; import { observable, action } from "mobx"; -import { Doc } from "../../../../new_fields/Doc"; -import { NumCast, StrCast } from "../../../../new_fields/Types"; +import { Doc } from "../../../../fields/Doc"; +import { NumCast, StrCast } from "../../../../fields/Types"; import { DimUnit } from "./CollectionMultirowView"; import { UndoManager } from "../../../util/UndoManager"; diff --git a/src/client/views/linking/LinkEditor.tsx b/src/client/views/linking/LinkEditor.tsx index b7f3dd995..5fb4cf3c6 100644 --- a/src/client/views/linking/LinkEditor.tsx +++ b/src/client/views/linking/LinkEditor.tsx @@ -3,8 +3,8 @@ import { faArrowLeft, faCog, faEllipsisV, faExchangeAlt, faPlus, faTable, faTime import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { action, observable } from "mobx"; import { observer } from "mobx-react"; -import { Doc } from "../../../new_fields/Doc"; -import { StrCast } from "../../../new_fields/Types"; +import { Doc } from "../../../fields/Doc"; +import { StrCast } from "../../../fields/Types"; import { Utils } from "../../../Utils"; import { LinkManager } from "../../util/LinkManager"; import './LinkEditor.scss'; diff --git a/src/client/views/linking/LinkMenu.tsx b/src/client/views/linking/LinkMenu.tsx index b768eacc3..786d6be47 100644 --- a/src/client/views/linking/LinkMenu.tsx +++ b/src/client/views/linking/LinkMenu.tsx @@ -4,7 +4,7 @@ import { DocumentView } from "../nodes/DocumentView"; import { LinkEditor } from "./LinkEditor"; import './LinkMenu.scss'; import React = require("react"); -import { Doc } from "../../../new_fields/Doc"; +import { Doc } from "../../../fields/Doc"; import { LinkManager } from "../../util/LinkManager"; import { LinkMenuGroup } from "./LinkMenuGroup"; import { faTrash } from '@fortawesome/free-solid-svg-icons'; diff --git a/src/client/views/linking/LinkMenuGroup.tsx b/src/client/views/linking/LinkMenuGroup.tsx index c97e1062d..89deb3a55 100644 --- a/src/client/views/linking/LinkMenuGroup.tsx +++ b/src/client/views/linking/LinkMenuGroup.tsx @@ -1,9 +1,9 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { action } from "mobx"; import { observer } from "mobx-react"; -import { Doc } from "../../../new_fields/Doc"; -import { Id } from "../../../new_fields/FieldSymbols"; -import { SchemaHeaderField } from "../../../new_fields/SchemaHeaderField"; +import { Doc } from "../../../fields/Doc"; +import { Id } from "../../../fields/FieldSymbols"; +import { SchemaHeaderField } from "../../../fields/SchemaHeaderField"; import { Docs } from "../../documents/Documents"; import { DragManager, SetupDrag } from "../../util/DragManager"; import { LinkManager } from "../../util/LinkManager"; diff --git a/src/client/views/linking/LinkMenuItem.tsx b/src/client/views/linking/LinkMenuItem.tsx index b0c61cb04..17cd33241 100644 --- a/src/client/views/linking/LinkMenuItem.tsx +++ b/src/client/views/linking/LinkMenuItem.tsx @@ -3,8 +3,8 @@ import { faArrowRight, faChevronDown, faChevronUp, faEdit, faEye, faTimes } from import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, observable } from 'mobx'; import { observer } from "mobx-react"; -import { Doc, DocListCast } from '../../../new_fields/Doc'; -import { Cast, StrCast } from '../../../new_fields/Types'; +import { Doc, DocListCast } from '../../../fields/Doc'; +import { Cast, StrCast } from '../../../fields/Types'; import { DragManager } from '../../util/DragManager'; import { LinkManager } from '../../util/LinkManager'; import { ContextMenu } from '../ContextMenu'; diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx index 1c5e13620..1a935d9b0 100644 --- a/src/client/views/nodes/AudioBox.tsx +++ b/src/client/views/nodes/AudioBox.tsx @@ -2,23 +2,23 @@ import React = require("react"); import { FieldViewProps, FieldView } from './FieldView'; import { observer } from "mobx-react"; import "./AudioBox.scss"; -import { Cast, DateCast, NumCast } from "../../../new_fields/Types"; -import { AudioField, nullAudio } from "../../../new_fields/URLField"; +import { Cast, DateCast, NumCast } from "../../../fields/Types"; +import { AudioField, nullAudio } from "../../../fields/URLField"; import { ViewBoxBaseComponent } from "../DocComponent"; -import { makeInterface, createSchema } from "../../../new_fields/Schema"; -import { documentSchema } from "../../../new_fields/documentSchemas"; +import { makeInterface, createSchema } from "../../../fields/Schema"; +import { documentSchema } from "../../../fields/documentSchemas"; import { Utils, returnTrue, emptyFunction, returnOne, returnTransparent, returnFalse, returnZero } from "../../../Utils"; import { runInAction, observable, reaction, IReactionDisposer, computed, action } from "mobx"; -import { DateField } from "../../../new_fields/DateField"; +import { DateField } from "../../../fields/DateField"; import { SelectionManager } from "../../util/SelectionManager"; -import { Doc, DocListCast } from "../../../new_fields/Doc"; +import { Doc, DocListCast } from "../../../fields/Doc"; import { ContextMenuProps } from "../ContextMenuItem"; import { ContextMenu } from "../ContextMenu"; -import { Id } from "../../../new_fields/FieldSymbols"; +import { Id } from "../../../fields/FieldSymbols"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { DocumentView } from "./DocumentView"; import { Docs, DocUtils } from "../../documents/Documents"; -import { ComputedField } from "../../../new_fields/ScriptField"; +import { ComputedField } from "../../../fields/ScriptField"; import { Networking } from "../../Network"; import { LinkAnchorBox } from "./LinkAnchorBox"; diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index cdbe506a5..5d6e587d9 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -1,14 +1,14 @@ import { computed, IReactionDisposer, observable, reaction, trace } from "mobx"; import { observer } from "mobx-react"; -import { Doc, HeightSym, WidthSym } from "../../../new_fields/Doc"; -import { Cast, NumCast, StrCast } from "../../../new_fields/Types"; +import { Doc, HeightSym, WidthSym } from "../../../fields/Doc"; +import { Cast, NumCast, StrCast } from "../../../fields/Types"; import { Transform } from "../../util/Transform"; import { DocComponent } from "../DocComponent"; import "./CollectionFreeFormDocumentView.scss"; import { DocumentView, DocumentViewProps } from "./DocumentView"; import React = require("react"); -import { Document } from "../../../new_fields/documentSchemas"; -import { TraceMobx } from "../../../new_fields/util"; +import { Document } from "../../../fields/documentSchemas"; +import { TraceMobx } from "../../../fields/util"; import { ContentFittingDocumentView } from "./ContentFittingDocumentView"; export interface CollectionFreeFormDocumentViewProps extends DocumentViewProps { diff --git a/src/client/views/nodes/ColorBox.tsx b/src/client/views/nodes/ColorBox.tsx index bc84204b9..bef6609c4 100644 --- a/src/client/views/nodes/ColorBox.tsx +++ b/src/client/views/nodes/ColorBox.tsx @@ -1,9 +1,9 @@ import React = require("react"); import { observer } from "mobx-react"; import { SketchPicker } from 'react-color'; -import { documentSchema } from "../../../new_fields/documentSchemas"; -import { makeInterface } from "../../../new_fields/Schema"; -import { StrCast } from "../../../new_fields/Types"; +import { documentSchema } from "../../../fields/documentSchemas"; +import { makeInterface } from "../../../fields/Schema"; +import { StrCast } from "../../../fields/Types"; import { CurrentUserUtils } from "../../util/CurrentUserUtils"; import { SelectionManager } from "../../util/SelectionManager"; import { ViewBoxBaseComponent } from "../DocComponent"; diff --git a/src/client/views/nodes/ContentFittingDocumentView.tsx b/src/client/views/nodes/ContentFittingDocumentView.tsx index 1c6250b94..a90b4668e 100644 --- a/src/client/views/nodes/ContentFittingDocumentView.tsx +++ b/src/client/views/nodes/ContentFittingDocumentView.tsx @@ -2,9 +2,9 @@ import React = require("react"); import { computed } from "mobx"; import { observer } from "mobx-react"; import "react-table/react-table.css"; -import { Doc, Opt, WidthSym, HeightSym } from "../../../new_fields/Doc"; -import { NumCast, StrCast, Cast } from "../../../new_fields/Types"; -import { TraceMobx } from "../../../new_fields/util"; +import { Doc, Opt, WidthSym, HeightSym } from "../../../fields/Doc"; +import { NumCast, StrCast, Cast } from "../../../fields/Types"; +import { TraceMobx } from "../../../fields/util"; import { emptyFunction, returnOne } from "../../../Utils"; import '../DocumentDecorations.scss'; import { DocumentView, DocumentViewProps } from "../nodes/DocumentView"; diff --git a/src/client/views/nodes/DocHolderBox.tsx b/src/client/views/nodes/DocHolderBox.tsx index af8dc704c..0c5239d66 100644 --- a/src/client/views/nodes/DocHolderBox.tsx +++ b/src/client/views/nodes/DocHolderBox.tsx @@ -1,12 +1,12 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { action, IReactionDisposer, reaction } from "mobx"; import { observer } from "mobx-react"; -import { Doc, Field } from "../../../new_fields/Doc"; -import { collectionSchema, documentSchema } from "../../../new_fields/documentSchemas"; -import { makeInterface, listSpec } from "../../../new_fields/Schema"; -import { ComputedField } from "../../../new_fields/ScriptField"; -import { Cast, NumCast, StrCast } from "../../../new_fields/Types"; -import { TraceMobx } from "../../../new_fields/util"; +import { Doc, Field } from "../../../fields/Doc"; +import { collectionSchema, documentSchema } from "../../../fields/documentSchemas"; +import { makeInterface, listSpec } from "../../../fields/Schema"; +import { ComputedField } from "../../../fields/ScriptField"; +import { Cast, NumCast, StrCast } from "../../../fields/Types"; +import { TraceMobx } from "../../../fields/util"; import { emptyPath, returnFalse, returnOne, returnZero } from "../../../Utils"; import { DocumentType } from "../../documents/DocumentTypes"; import { DragManager } from "../../util/DragManager"; diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx index 2fc82e524..f4785bb0c 100644 --- a/src/client/views/nodes/DocumentContentsView.tsx +++ b/src/client/views/nodes/DocumentContentsView.tsx @@ -1,7 +1,7 @@ import { computed } from "mobx"; import { observer } from "mobx-react"; -import { Doc, Opt, Field } from "../../../new_fields/Doc"; -import { Cast, StrCast, NumCast } from "../../../new_fields/Types"; +import { Doc, Opt, Field } from "../../../fields/Doc"; +import { Cast, StrCast, NumCast } from "../../../fields/Types"; import { OmitKeys, Without, emptyPath } from "../../../Utils"; import DirectoryImportBox from "../../util/Import & Export/DirectoryImportBox"; import { CollectionDockingView } from "../collections/CollectionDockingView"; @@ -35,8 +35,8 @@ import { WebBox } from "./WebBox"; import { InkingStroke } from "../InkingStroke"; import React = require("react"); import { RecommendationsBox } from "../RecommendationsBox"; -import { TraceMobx } from "../../../new_fields/util"; -import { ScriptField } from "../../../new_fields/ScriptField"; +import { TraceMobx } from "../../../fields/util"; +import { ScriptField } from "../../../fields/ScriptField"; import XRegExp = require("xregexp"); const JsxParser = require('react-jsx-parser').default; //TODO Why does this need to be imported like this? diff --git a/src/client/views/nodes/DocumentIcon.tsx b/src/client/views/nodes/DocumentIcon.tsx index f56f5e829..fb54f18e8 100644 --- a/src/client/views/nodes/DocumentIcon.tsx +++ b/src/client/views/nodes/DocumentIcon.tsx @@ -3,7 +3,7 @@ import * as React from "react"; import { DocumentView } from "./DocumentView"; import { DocumentManager } from "../../util/DocumentManager"; import { Transformer, Scripting, ts } from "../../util/Scripting"; -import { Field } from "../../../new_fields/Doc"; +import { Field } from "../../../fields/Doc"; @observer export class DocumentIcon extends React.Component<{ view: DocumentView, index: number }> { diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index d821bb8ac..340fa06a8 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -4,16 +4,16 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, computed, observable, runInAction } from "mobx"; import { observer } from "mobx-react"; import * as rp from "request-promise"; -import { Doc, DocListCast, HeightSym, Opt, WidthSym, DataSym } from "../../../new_fields/Doc"; -import { Document } from '../../../new_fields/documentSchemas'; -import { Id } from '../../../new_fields/FieldSymbols'; -import { InkTool } from '../../../new_fields/InkField'; -import { listSpec } from "../../../new_fields/Schema"; -import { SchemaHeaderField } from '../../../new_fields/SchemaHeaderField'; -import { ScriptField } from '../../../new_fields/ScriptField'; -import { BoolCast, Cast, NumCast, StrCast } from "../../../new_fields/Types"; -import { ImageField } from '../../../new_fields/URLField'; -import { TraceMobx } from '../../../new_fields/util'; +import { Doc, DocListCast, HeightSym, Opt, WidthSym, DataSym } from "../../../fields/Doc"; +import { Document } from '../../../fields/documentSchemas'; +import { Id } from '../../../fields/FieldSymbols'; +import { InkTool } from '../../../fields/InkField'; +import { listSpec } from "../../../fields/Schema"; +import { SchemaHeaderField } from '../../../fields/SchemaHeaderField'; +import { ScriptField } from '../../../fields/ScriptField'; +import { BoolCast, Cast, NumCast, StrCast } from "../../../fields/Types"; +import { ImageField } from '../../../fields/URLField'; +import { TraceMobx } from '../../../fields/util'; import { GestureUtils } from '../../../pen-gestures/GestureUtils'; import { emptyFunction, OmitKeys, returnOne, returnTransparent, Utils, emptyPath } from "../../../Utils"; import { GooglePhotos } from '../../apis/google_docs/GooglePhotosClientUtils'; diff --git a/src/client/views/nodes/FaceRectangles.tsx b/src/client/views/nodes/FaceRectangles.tsx index 3c7f1f206..92ca276cb 100644 --- a/src/client/views/nodes/FaceRectangles.tsx +++ b/src/client/views/nodes/FaceRectangles.tsx @@ -1,8 +1,8 @@ import React = require("react"); -import { Doc, DocListCast } from "../../../new_fields/Doc"; -import { Cast, NumCast } from "../../../new_fields/Types"; +import { Doc, DocListCast } from "../../../fields/Doc"; +import { Cast, NumCast } from "../../../fields/Types"; import { observer } from "mobx-react"; -import { Id } from "../../../new_fields/FieldSymbols"; +import { Id } from "../../../fields/FieldSymbols"; import FaceRectangle from "./FaceRectangle"; interface FaceRectanglesProps { diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx index 2ab0a416d..e9dc43bd8 100644 --- a/src/client/views/nodes/FieldView.tsx +++ b/src/client/views/nodes/FieldView.tsx @@ -1,11 +1,11 @@ import React = require("react"); import { computed } from "mobx"; import { observer } from "mobx-react"; -import { DateField } from "../../../new_fields/DateField"; -import { Doc, FieldResult, Opt, Field } from "../../../new_fields/Doc"; -import { List } from "../../../new_fields/List"; -import { ScriptField } from "../../../new_fields/ScriptField"; -import { AudioField, VideoField } from "../../../new_fields/URLField"; +import { DateField } from "../../../fields/DateField"; +import { Doc, FieldResult, Opt, Field } from "../../../fields/Doc"; +import { List } from "../../../fields/List"; +import { ScriptField } from "../../../fields/ScriptField"; +import { AudioField, VideoField } from "../../../fields/URLField"; import { Transform } from "../../util/Transform"; import { CollectionView } from "../collections/CollectionView"; import { AudioBox } from "./AudioBox"; diff --git a/src/client/views/nodes/FontIconBox.tsx b/src/client/views/nodes/FontIconBox.tsx index 0d597b3a8..cf0b16c7c 100644 --- a/src/client/views/nodes/FontIconBox.tsx +++ b/src/client/views/nodes/FontIconBox.tsx @@ -1,16 +1,16 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { observer } from 'mobx-react'; import * as React from 'react'; -import { createSchema, makeInterface } from '../../../new_fields/Schema'; +import { createSchema, makeInterface } from '../../../fields/Schema'; import { DocComponent } from '../DocComponent'; import './FontIconBox.scss'; import { FieldView, FieldViewProps } from './FieldView'; -import { StrCast, Cast } from '../../../new_fields/Types'; +import { StrCast, Cast } from '../../../fields/Types'; import { Utils } from "../../../Utils"; import { runInAction, observable, reaction, IReactionDisposer } from 'mobx'; -import { Doc } from '../../../new_fields/Doc'; +import { Doc } from '../../../fields/Doc'; import { ContextMenu } from '../ContextMenu'; -import { ScriptField } from '../../../new_fields/ScriptField'; +import { ScriptField } from '../../../fields/ScriptField'; const FontIconSchema = createSchema({ icon: "string" }); diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index aaebceaa2..47e7607d6 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -4,16 +4,16 @@ import { faAsterisk, faBrain, faFileAudio, faImage, faPaintBrush } from '@fortaw import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { action, computed, observable, runInAction } from 'mobx'; import { observer } from "mobx-react"; -import { DataSym, Doc, DocListCast, HeightSym, WidthSym } from '../../../new_fields/Doc'; -import { documentSchema } from '../../../new_fields/documentSchemas'; -import { Id } from '../../../new_fields/FieldSymbols'; -import { List } from '../../../new_fields/List'; -import { ObjectField } from '../../../new_fields/ObjectField'; -import { createSchema, listSpec, makeInterface } from '../../../new_fields/Schema'; -import { ComputedField } from '../../../new_fields/ScriptField'; -import { Cast, NumCast, StrCast } from '../../../new_fields/Types'; -import { AudioField, ImageField } from '../../../new_fields/URLField'; -import { TraceMobx } from '../../../new_fields/util'; +import { DataSym, Doc, DocListCast, HeightSym, WidthSym } from '../../../fields/Doc'; +import { documentSchema } from '../../../fields/documentSchemas'; +import { Id } from '../../../fields/FieldSymbols'; +import { List } from '../../../fields/List'; +import { ObjectField } from '../../../fields/ObjectField'; +import { createSchema, listSpec, makeInterface } from '../../../fields/Schema'; +import { ComputedField } from '../../../fields/ScriptField'; +import { Cast, NumCast, StrCast } from '../../../fields/Types'; +import { AudioField, ImageField } from '../../../fields/URLField'; +import { TraceMobx } from '../../../fields/util'; import { emptyFunction, returnOne, Utils, returnZero } from '../../../Utils'; import { CognitiveServices, Confidence, Service, Tag } from '../../cognitive_services/CognitiveServices'; import { Docs } from '../../documents/Documents'; diff --git a/src/client/views/nodes/KeyValueBox.tsx b/src/client/views/nodes/KeyValueBox.tsx index 39d7109b1..e983852ea 100644 --- a/src/client/views/nodes/KeyValueBox.tsx +++ b/src/client/views/nodes/KeyValueBox.tsx @@ -1,13 +1,13 @@ import { action, computed, observable } from "mobx"; import { observer } from "mobx-react"; -import { Doc, Field, FieldResult } from "../../../new_fields/Doc"; -import { List } from "../../../new_fields/List"; -import { RichTextField } from "../../../new_fields/RichTextField"; -import { listSpec } from "../../../new_fields/Schema"; -import { ComputedField, ScriptField } from "../../../new_fields/ScriptField"; -import { Cast, FieldValue, NumCast } from "../../../new_fields/Types"; -import { ImageField } from "../../../new_fields/URLField"; +import { Doc, Field, FieldResult } from "../../../fields/Doc"; +import { List } from "../../../fields/List"; +import { RichTextField } from "../../../fields/RichTextField"; +import { listSpec } from "../../../fields/Schema"; +import { ComputedField, ScriptField } from "../../../fields/ScriptField"; +import { Cast, FieldValue, NumCast } from "../../../fields/Types"; +import { ImageField } from "../../../fields/URLField"; import { Docs } from "../../documents/Documents"; import { SetupDrag } from "../../util/DragManager"; import { CompiledScript, CompileScript, ScriptOptions } from "../../util/Scripting"; diff --git a/src/client/views/nodes/KeyValuePair.tsx b/src/client/views/nodes/KeyValuePair.tsx index 6dc4ae578..956d6556b 100644 --- a/src/client/views/nodes/KeyValuePair.tsx +++ b/src/client/views/nodes/KeyValuePair.tsx @@ -1,6 +1,6 @@ import { action, observable } from 'mobx'; import { observer } from "mobx-react"; -import { Doc, Field, Opt } from '../../../new_fields/Doc'; +import { Doc, Field, Opt } from '../../../fields/Doc'; import { emptyFunction, returnFalse, returnOne, returnZero } from '../../../Utils'; import { Docs } from '../../documents/Documents'; import { Transform } from '../../util/Transform'; diff --git a/src/client/views/nodes/LabelBox.tsx b/src/client/views/nodes/LabelBox.tsx index ac27640bd..2d27ec441 100644 --- a/src/client/views/nodes/LabelBox.tsx +++ b/src/client/views/nodes/LabelBox.tsx @@ -3,11 +3,11 @@ import { faEdit } from '@fortawesome/free-regular-svg-icons'; import { action } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; -import { Doc, DocListCast } from '../../../new_fields/Doc'; -import { documentSchema } from '../../../new_fields/documentSchemas'; -import { List } from '../../../new_fields/List'; -import { createSchema, listSpec, makeInterface } from '../../../new_fields/Schema'; -import { Cast, NumCast, StrCast } from '../../../new_fields/Types'; +import { Doc, DocListCast } from '../../../fields/Doc'; +import { documentSchema } from '../../../fields/documentSchemas'; +import { List } from '../../../fields/List'; +import { createSchema, listSpec, makeInterface } from '../../../fields/Schema'; +import { Cast, NumCast, StrCast } from '../../../fields/Types'; import { DragManager } from '../../util/DragManager'; import { undoBatch } from '../../util/UndoManager'; import { ContextMenu } from '../ContextMenu'; diff --git a/src/client/views/nodes/LinkAnchorBox.tsx b/src/client/views/nodes/LinkAnchorBox.tsx index bc36e056e..098aa58e9 100644 --- a/src/client/views/nodes/LinkAnchorBox.tsx +++ b/src/client/views/nodes/LinkAnchorBox.tsx @@ -1,9 +1,9 @@ import { action, observable } from "mobx"; import { observer } from "mobx-react"; -import { Doc, DocListCast } from "../../../new_fields/Doc"; -import { documentSchema } from "../../../new_fields/documentSchemas"; -import { makeInterface } from "../../../new_fields/Schema"; -import { Cast, NumCast, StrCast } from "../../../new_fields/Types"; +import { Doc, DocListCast } from "../../../fields/Doc"; +import { documentSchema } from "../../../fields/documentSchemas"; +import { makeInterface } from "../../../fields/Schema"; +import { Cast, NumCast, StrCast } from "../../../fields/Types"; import { Utils, setupMoveUpEvents, emptyFunction } from '../../../Utils'; import { DocumentManager } from "../../util/DocumentManager"; import { DragManager } from "../../util/DragManager"; @@ -16,7 +16,7 @@ import { ContextMenu } from "../ContextMenu"; import { LinkEditor } from "../linking/LinkEditor"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { SelectionManager } from "../../util/SelectionManager"; -import { TraceMobx } from "../../../new_fields/util"; +import { TraceMobx } from "../../../fields/util"; const higflyout = require("@hig/flyout"); export const { anchorPoints } = higflyout; export const Flyout = higflyout.default; diff --git a/src/client/views/nodes/LinkBox.tsx b/src/client/views/nodes/LinkBox.tsx index 740f2ef04..3f942e87b 100644 --- a/src/client/views/nodes/LinkBox.tsx +++ b/src/client/views/nodes/LinkBox.tsx @@ -1,13 +1,13 @@ import React = require("react"); import { observer } from "mobx-react"; -import { documentSchema } from "../../../new_fields/documentSchemas"; -import { makeInterface, listSpec } from "../../../new_fields/Schema"; +import { documentSchema } from "../../../fields/documentSchemas"; +import { makeInterface, listSpec } from "../../../fields/Schema"; import { returnFalse, returnZero } from "../../../Utils"; import { CollectionTreeView } from "../collections/CollectionTreeView"; import { ViewBoxBaseComponent } from "../DocComponent"; import { FieldView, FieldViewProps } from './FieldView'; import "./LinkBox.scss"; -import { Cast } from "../../../new_fields/Types"; +import { Cast } from "../../../fields/Types"; type LinkDocument = makeInterface<[typeof documentSchema]>; const LinkDocument = makeInterface(documentSchema); diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index 3712c648e..493f23dc4 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -3,11 +3,11 @@ import { action, observable, runInAction, reaction, IReactionDisposer, trace, un import { observer } from "mobx-react"; import * as Pdfjs from "pdfjs-dist"; import "pdfjs-dist/web/pdf_viewer.css"; -import { Opt, WidthSym, Doc, HeightSym } from "../../../new_fields/Doc"; -import { makeInterface } from "../../../new_fields/Schema"; -import { ScriptField } from '../../../new_fields/ScriptField'; -import { Cast, NumCast, StrCast } from "../../../new_fields/Types"; -import { PdfField, URLField } from "../../../new_fields/URLField"; +import { Opt, WidthSym, Doc, HeightSym } from "../../../fields/Doc"; +import { makeInterface } from "../../../fields/Schema"; +import { ScriptField } from '../../../fields/ScriptField'; +import { Cast, NumCast, StrCast } from "../../../fields/Types"; +import { PdfField, URLField } from "../../../fields/URLField"; import { Utils } from '../../../Utils'; import { undoBatch } from '../../util/UndoManager'; import { panZoomSchema } from '../collections/collectionFreeForm/CollectionFreeFormView'; @@ -20,7 +20,7 @@ import { pageSchema } from "./ImageBox"; import { KeyCodes } from '../../util/KeyCodes'; import "./PDFBox.scss"; import React = require("react"); -import { documentSchema } from '../../../new_fields/documentSchemas'; +import { documentSchema } from '../../../fields/documentSchemas'; type PdfDocument = makeInterface<[typeof documentSchema, typeof panZoomSchema, typeof pageSchema]>; const PdfDocument = makeInterface(documentSchema, panZoomSchema, pageSchema); diff --git a/src/client/views/nodes/PresBox.tsx b/src/client/views/nodes/PresBox.tsx index 42552ec73..342a8a215 100644 --- a/src/client/views/nodes/PresBox.tsx +++ b/src/client/views/nodes/PresBox.tsx @@ -2,11 +2,11 @@ import React = require("react"); import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { action, computed, IReactionDisposer, observable, reaction, runInAction } from "mobx"; import { observer } from "mobx-react"; -import { Doc, DocListCast, DocCastAsync } from "../../../new_fields/Doc"; -import { InkTool } from "../../../new_fields/InkField"; -import { BoolCast, Cast, NumCast, StrCast } from "../../../new_fields/Types"; +import { Doc, DocListCast, DocCastAsync } from "../../../fields/Doc"; +import { InkTool } from "../../../fields/InkField"; +import { BoolCast, Cast, NumCast, StrCast } from "../../../fields/Types"; import { returnFalse } from "../../../Utils"; -import { documentSchema } from "../../../new_fields/documentSchemas"; +import { documentSchema } from "../../../fields/documentSchemas"; import { DocumentManager } from "../../util/DocumentManager"; import { undoBatch } from "../../util/UndoManager"; import { CollectionDockingView } from "../collections/CollectionDockingView"; @@ -15,11 +15,11 @@ import { InkingControl } from "../InkingControl"; import { FieldView, FieldViewProps } from './FieldView'; import "./PresBox.scss"; import { ViewBoxBaseComponent } from "../DocComponent"; -import { makeInterface } from "../../../new_fields/Schema"; -import { List } from "../../../new_fields/List"; +import { makeInterface } from "../../../fields/Schema"; +import { List } from "../../../fields/List"; import { Docs } from "../../documents/Documents"; -import { PrefetchProxy } from "../../../new_fields/Proxy"; -import { ScriptField } from "../../../new_fields/ScriptField"; +import { PrefetchProxy } from "../../../fields/Proxy"; +import { ScriptField } from "../../../fields/ScriptField"; import { Scripting } from "../../util/Scripting"; type PresBoxSchema = makeInterface<[typeof documentSchema]>; diff --git a/src/client/views/nodes/QueryBox.tsx b/src/client/views/nodes/QueryBox.tsx index 2a21a380d..0fff0b57f 100644 --- a/src/client/views/nodes/QueryBox.tsx +++ b/src/client/views/nodes/QueryBox.tsx @@ -1,15 +1,15 @@ import React = require("react"); import { IReactionDisposer } from "mobx"; import { observer } from "mobx-react"; -import { documentSchema } from "../../../new_fields/documentSchemas"; -import { Id } from '../../../new_fields/FieldSymbols'; -import { makeInterface, listSpec } from "../../../new_fields/Schema"; -import { StrCast, Cast } from "../../../new_fields/Types"; +import { documentSchema } from "../../../fields/documentSchemas"; +import { Id } from '../../../fields/FieldSymbols'; +import { makeInterface, listSpec } from "../../../fields/Schema"; +import { StrCast, Cast } from "../../../fields/Types"; import { ViewBoxAnnotatableComponent } from '../DocComponent'; import { SearchBox } from "../search/SearchBox"; import { FieldView, FieldViewProps } from './FieldView'; import "./QueryBox.scss"; -import { List } from "../../../new_fields/List"; +import { List } from "../../../fields/List"; import { SnappingManager } from "../../util/SnappingManager"; type QueryDocument = makeInterface<[typeof documentSchema]>; diff --git a/src/client/views/nodes/ScreenshotBox.tsx b/src/client/views/nodes/ScreenshotBox.tsx index a0ecc9ff5..5d4af2d77 100644 --- a/src/client/views/nodes/ScreenshotBox.tsx +++ b/src/client/views/nodes/ScreenshotBox.tsx @@ -5,10 +5,10 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { action, computed, IReactionDisposer, observable, runInAction } from "mobx"; import { observer } from "mobx-react"; import * as rp from 'request-promise'; -import { documentSchema } from "../../../new_fields/documentSchemas"; -import { makeInterface } from "../../../new_fields/Schema"; -import { Cast, NumCast } from "../../../new_fields/Types"; -import { VideoField } from "../../../new_fields/URLField"; +import { documentSchema } from "../../../fields/documentSchemas"; +import { makeInterface } from "../../../fields/Schema"; +import { Cast, NumCast } from "../../../fields/Types"; +import { VideoField } from "../../../fields/URLField"; import { emptyFunction, returnFalse, returnOne, Utils, returnZero } from "../../../Utils"; import { Docs, DocUtils } from "../../documents/Documents"; import { CollectionFreeFormView } from "../collections/collectionFreeForm/CollectionFreeFormView"; diff --git a/src/client/views/nodes/ScriptingBox.tsx b/src/client/views/nodes/ScriptingBox.tsx index c607d6614..0944edf60 100644 --- a/src/client/views/nodes/ScriptingBox.tsx +++ b/src/client/views/nodes/ScriptingBox.tsx @@ -1,10 +1,10 @@ import { action, observable, computed } from "mobx"; import { observer } from "mobx-react"; import * as React from "react"; -import { documentSchema } from "../../../new_fields/documentSchemas"; -import { createSchema, makeInterface, listSpec } from "../../../new_fields/Schema"; -import { ScriptField } from "../../../new_fields/ScriptField"; -import { StrCast, ScriptCast, Cast } from "../../../new_fields/Types"; +import { documentSchema } from "../../../fields/documentSchemas"; +import { createSchema, makeInterface, listSpec } from "../../../fields/Schema"; +import { ScriptField } from "../../../fields/ScriptField"; +import { StrCast, ScriptCast, Cast } from "../../../fields/Types"; import { InteractionUtils } from "../../util/InteractionUtils"; import { CompileScript, isCompileError, ScriptParam } from "../../util/Scripting"; import { ViewBoxAnnotatableComponent } from "../DocComponent"; @@ -13,7 +13,7 @@ import { FieldView, FieldViewProps } from "../nodes/FieldView"; import "./ScriptingBox.scss"; import { OverlayView } from "../OverlayView"; import { DocumentIconContainer } from "./DocumentIcon"; -import { List } from "../../../new_fields/List"; +import { List } from "../../../fields/List"; const ScriptingSchema = createSchema({}); type ScriptingDocument = makeInterface<[typeof ScriptingSchema, typeof documentSchema]>; diff --git a/src/client/views/nodes/SliderBox.tsx b/src/client/views/nodes/SliderBox.tsx index cb2526769..9a1aefba9 100644 --- a/src/client/views/nodes/SliderBox.tsx +++ b/src/client/views/nodes/SliderBox.tsx @@ -4,10 +4,10 @@ import { runInAction } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { Handles, Rail, Slider, Ticks, Tracks } from 'react-compound-slider'; -import { documentSchema } from '../../../new_fields/documentSchemas'; -import { createSchema, makeInterface } from '../../../new_fields/Schema'; -import { ScriptField } from '../../../new_fields/ScriptField'; -import { Cast, NumCast, StrCast } from '../../../new_fields/Types'; +import { documentSchema } from '../../../fields/documentSchemas'; +import { createSchema, makeInterface } from '../../../fields/Schema'; +import { ScriptField } from '../../../fields/ScriptField'; +import { Cast, NumCast, StrCast } from '../../../fields/Types'; import { ContextMenu } from '../ContextMenu'; import { ContextMenuProps } from '../ContextMenuItem'; import { ViewBoxBaseComponent } from '../DocComponent'; diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx index 9602eac52..ccf1f5588 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -5,12 +5,12 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { action, computed, IReactionDisposer, observable, reaction, runInAction, untracked } from "mobx"; import { observer } from "mobx-react"; import * as rp from 'request-promise'; -import { Doc } from "../../../new_fields/Doc"; -import { InkTool } from "../../../new_fields/InkField"; -import { createSchema, makeInterface } from "../../../new_fields/Schema"; -import { ScriptField } from "../../../new_fields/ScriptField"; -import { Cast, StrCast } from "../../../new_fields/Types"; -import { VideoField } from "../../../new_fields/URLField"; +import { Doc } from "../../../fields/Doc"; +import { InkTool } from "../../../fields/InkField"; +import { createSchema, makeInterface } from "../../../fields/Schema"; +import { ScriptField } from "../../../fields/ScriptField"; +import { Cast, StrCast } from "../../../fields/Types"; +import { VideoField } from "../../../fields/URLField"; import { Utils, emptyFunction, returnOne, returnZero } from "../../../Utils"; import { Docs, DocUtils } from "../../documents/Documents"; import { CollectionFreeFormView } from "../collections/collectionFreeForm/CollectionFreeFormView"; @@ -21,7 +21,7 @@ import { DocumentDecorations } from "../DocumentDecorations"; import { InkingControl } from "../InkingControl"; import { FieldView, FieldViewProps } from './FieldView'; import "./VideoBox.scss"; -import { documentSchema } from "../../../new_fields/documentSchemas"; +import { documentSchema } from "../../../fields/documentSchemas"; const path = require('path'); export const timeSchema = createSchema({ @@ -337,7 +337,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent { const curTime = (this.layoutDoc.currentTimecode || -1); diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index 6d4cc1a07..82f05012a 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -2,13 +2,13 @@ import { library } from "@fortawesome/fontawesome-svg-core"; import { faStickyNote, faPen, faMousePointer } from '@fortawesome/free-solid-svg-icons'; import { action, computed, observable, trace, IReactionDisposer, reaction } from "mobx"; import { observer } from "mobx-react"; -import { Doc, FieldResult } from "../../../new_fields/Doc"; -import { documentSchema } from "../../../new_fields/documentSchemas"; -import { HtmlField } from "../../../new_fields/HtmlField"; -import { InkTool } from "../../../new_fields/InkField"; -import { makeInterface } from "../../../new_fields/Schema"; -import { Cast, NumCast, BoolCast, StrCast } from "../../../new_fields/Types"; -import { WebField } from "../../../new_fields/URLField"; +import { Doc, FieldResult } from "../../../fields/Doc"; +import { documentSchema } from "../../../fields/documentSchemas"; +import { HtmlField } from "../../../fields/HtmlField"; +import { InkTool } from "../../../fields/InkField"; +import { makeInterface } from "../../../fields/Schema"; +import { Cast, NumCast, BoolCast, StrCast } from "../../../fields/Types"; +import { WebField } from "../../../fields/URLField"; import { Utils, returnOne, emptyFunction, returnZero } from "../../../Utils"; import { Docs } from "../../documents/Documents"; import { DragManager } from "../../util/DragManager"; diff --git a/src/client/views/nodes/formattedText/DashDocCommentView.tsx b/src/client/views/nodes/formattedText/DashDocCommentView.tsx index d94fe7fc6..d56b87ae5 100644 --- a/src/client/views/nodes/formattedText/DashDocCommentView.tsx +++ b/src/client/views/nodes/formattedText/DashDocCommentView.tsx @@ -8,14 +8,14 @@ import { EditorState, NodeSelection, Plugin, TextSelection } from "prosemirror-s import { StepMap } from "prosemirror-transform"; import { EditorView } from "prosemirror-view"; import * as ReactDOM from 'react-dom'; -import { Doc, DocListCast, Field, HeightSym, WidthSym } from "../../../../new_fields/Doc"; -import { Id } from "../../../../new_fields/FieldSymbols"; -import { List } from "../../../../new_fields/List"; -import { ObjectField } from "../../../../new_fields/ObjectField"; -import { listSpec } from "../../../../new_fields/Schema"; -import { SchemaHeaderField } from "../../../../new_fields/SchemaHeaderField"; -import { ComputedField } from "../../../../new_fields/ScriptField"; -import { BoolCast, Cast, NumCast, StrCast } from "../../../../new_fields/Types"; +import { Doc, DocListCast, Field, HeightSym, WidthSym } from "../../../../fields/Doc"; +import { Id } from "../../../../fields/FieldSymbols"; +import { List } from "../../../../fields/List"; +import { ObjectField } from "../../../../fields/ObjectField"; +import { listSpec } from "../../../../fields/Schema"; +import { SchemaHeaderField } from "../../../../fields/SchemaHeaderField"; +import { ComputedField } from "../../../../fields/ScriptField"; +import { BoolCast, Cast, NumCast, StrCast } from "../../../../fields/Types"; import { emptyFunction, returnEmptyString, returnFalse, returnOne, Utils, returnZero } from "../../../../Utils"; import { DocServer } from "../../../DocServer"; diff --git a/src/client/views/nodes/formattedText/DashDocView.tsx b/src/client/views/nodes/formattedText/DashDocView.tsx index 7130fee2b..05e6a5959 100644 --- a/src/client/views/nodes/formattedText/DashDocView.tsx +++ b/src/client/views/nodes/formattedText/DashDocView.tsx @@ -1,10 +1,10 @@ import { IReactionDisposer, reaction } from "mobx"; import { NodeSelection } from "prosemirror-state"; -import { Doc, HeightSym, WidthSym } from "../../../../new_fields/Doc"; -import { Id } from "../../../../new_fields/FieldSymbols"; -import { ObjectField } from "../../../../new_fields/ObjectField"; -import { ComputedField } from "../../../../new_fields/ScriptField"; -import { BoolCast, Cast, NumCast, StrCast } from "../../../../new_fields/Types"; +import { Doc, HeightSym, WidthSym } from "../../../../fields/Doc"; +import { Id } from "../../../../fields/FieldSymbols"; +import { ObjectField } from "../../../../fields/ObjectField"; +import { ComputedField } from "../../../../fields/ScriptField"; +import { BoolCast, Cast, NumCast, StrCast } from "../../../../fields/Types"; import { emptyFunction, returnEmptyString, returnFalse, Utils, returnZero } from "../../../../Utils"; import { DocServer } from "../../../DocServer"; import { Docs } from "../../../documents/Documents"; diff --git a/src/client/views/nodes/formattedText/DashFieldView.tsx b/src/client/views/nodes/formattedText/DashFieldView.tsx index 3c6841f08..d05e8f1ea 100644 --- a/src/client/views/nodes/formattedText/DashFieldView.tsx +++ b/src/client/views/nodes/formattedText/DashFieldView.tsx @@ -1,10 +1,10 @@ import { IReactionDisposer, observable, runInAction, computed, action } from "mobx"; -import { Doc, DocListCast, Field } from "../../../../new_fields/Doc"; -import { List } from "../../../../new_fields/List"; -import { listSpec } from "../../../../new_fields/Schema"; -import { SchemaHeaderField } from "../../../../new_fields/SchemaHeaderField"; -import { ComputedField } from "../../../../new_fields/ScriptField"; -import { Cast, StrCast } from "../../../../new_fields/Types"; +import { Doc, DocListCast, Field } from "../../../../fields/Doc"; +import { List } from "../../../../fields/List"; +import { listSpec } from "../../../../fields/Schema"; +import { SchemaHeaderField } from "../../../../fields/SchemaHeaderField"; +import { ComputedField } from "../../../../fields/ScriptField"; +import { Cast, StrCast } from "../../../../fields/Types"; import { DocServer } from "../../../DocServer"; import { CollectionViewType } from "../../collections/CollectionView"; import { FormattedTextBox } from "./FormattedTextBox"; diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index 206c3db8c..5e33e7e70 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -12,17 +12,17 @@ import { Fragment, Mark, Node, Slice } from "prosemirror-model"; import { EditorState, NodeSelection, Plugin, TextSelection, Transaction } from "prosemirror-state"; import { ReplaceStep } from 'prosemirror-transform'; import { EditorView } from "prosemirror-view"; -import { DateField } from '../../../../new_fields/DateField'; -import { DataSym, Doc, DocListCast, DocListCastAsync, Field, HeightSym, Opt, WidthSym } from "../../../../new_fields/Doc"; -import { documentSchema } from '../../../../new_fields/documentSchemas'; -import { Id } from '../../../../new_fields/FieldSymbols'; -import { InkTool } from '../../../../new_fields/InkField'; -import { PrefetchProxy } from '../../../../new_fields/Proxy'; -import { RichTextField } from "../../../../new_fields/RichTextField"; -import { RichTextUtils } from '../../../../new_fields/RichTextUtils'; -import { createSchema, makeInterface } from "../../../../new_fields/Schema"; -import { Cast, DateCast, NumCast, StrCast } from "../../../../new_fields/Types"; -import { TraceMobx } from '../../../../new_fields/util'; +import { DateField } from '../../../../fields/DateField'; +import { DataSym, Doc, DocListCast, DocListCastAsync, Field, HeightSym, Opt, WidthSym } from "../../../../fields/Doc"; +import { documentSchema } from '../../../../fields/documentSchemas'; +import { Id } from '../../../../fields/FieldSymbols'; +import { InkTool } from '../../../../fields/InkField'; +import { PrefetchProxy } from '../../../../fields/Proxy'; +import { RichTextField } from "../../../../fields/RichTextField"; +import { RichTextUtils } from '../../../../fields/RichTextUtils'; +import { createSchema, makeInterface } from "../../../../fields/Schema"; +import { Cast, DateCast, NumCast, StrCast } from "../../../../fields/Types"; +import { TraceMobx } from '../../../../fields/util'; import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, emptyFunction, numberRange, returnOne, returnZero, Utils, setupMoveUpEvents } from '../../../../Utils'; import { GoogleApiClientUtils, Pulls, Pushes } from '../../../apis/google_docs/GoogleApiClientUtils'; import { DocServer } from "../../../DocServer"; @@ -58,7 +58,7 @@ import { FieldView, FieldViewProps } from "../FieldView"; import "./FormattedTextBox.scss"; import { FormattedTextBoxComment, formattedTextBoxCommentPlugin } from './FormattedTextBoxComment'; import React = require("react"); -import { ScriptField } from '../../../../new_fields/ScriptField'; +import { ScriptField } from '../../../../fields/ScriptField'; import GoogleAuthenticationManager from '../../../apis/GoogleAuthenticationManager'; library.add(faEdit); diff --git a/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx b/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx index 07aecf148..d47ae63af 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBoxComment.tsx @@ -2,8 +2,8 @@ import { Mark, ResolvedPos } from "prosemirror-model"; import { EditorState, Plugin } from "prosemirror-state"; import { EditorView } from "prosemirror-view"; import * as ReactDOM from 'react-dom'; -import { Doc, DocCastAsync } from "../../../../new_fields/Doc"; -import { Cast, FieldValue, NumCast } from "../../../../new_fields/Types"; +import { Doc, DocCastAsync } from "../../../../fields/Doc"; +import { Cast, FieldValue, NumCast } from "../../../../fields/Types"; import { emptyFunction, returnEmptyString, returnFalse, Utils, emptyPath, returnZero, returnOne } from "../../../../Utils"; import { DocServer } from "../../../DocServer"; import { DocumentManager } from "../../../util/DocumentManager"; diff --git a/src/client/views/nodes/formattedText/ImageResizeView.tsx b/src/client/views/nodes/formattedText/ImageResizeView.tsx index 8f98da0fd..401ecd7e6 100644 --- a/src/client/views/nodes/formattedText/ImageResizeView.tsx +++ b/src/client/views/nodes/formattedText/ImageResizeView.tsx @@ -1,5 +1,5 @@ import { NodeSelection } from "prosemirror-state"; -import { Doc } from "../../../../new_fields/Doc"; +import { Doc } from "../../../../fields/Doc"; import { DocServer } from "../../../DocServer"; import { DocumentManager } from "../../../util/DocumentManager"; import React = require("react"); diff --git a/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts b/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts index a0b02880e..2f7d23021 100644 --- a/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts +++ b/src/client/views/nodes/formattedText/ProsemirrorExampleTransfer.ts @@ -7,10 +7,10 @@ import { splitListItem, wrapInList, } from "prosemirror-schema-list"; import { EditorState, Transaction, TextSelection } from "prosemirror-state"; import { SelectionManager } from "../../../util/SelectionManager"; import { Docs } from "../../../documents/Documents"; -import { NumCast, BoolCast, Cast, StrCast } from "../../../../new_fields/Types"; -import { Doc } from "../../../../new_fields/Doc"; +import { NumCast, BoolCast, Cast, StrCast } from "../../../../fields/Types"; +import { Doc } from "../../../../fields/Doc"; import { FormattedTextBox } from "./FormattedTextBox"; -import { Id } from "../../../../new_fields/FieldSymbols"; +import { Id } from "../../../../fields/FieldSymbols"; const mac = typeof navigator !== "undefined" ? /Mac/.test(navigator.platform) : false; diff --git a/src/client/views/nodes/formattedText/RichTextMenu.tsx b/src/client/views/nodes/formattedText/RichTextMenu.tsx index 170a39801..fd1b26208 100644 --- a/src/client/views/nodes/formattedText/RichTextMenu.tsx +++ b/src/client/views/nodes/formattedText/RichTextMenu.tsx @@ -11,14 +11,14 @@ import { IconProp, library } from '@fortawesome/fontawesome-svg-core'; import { faBold, faItalic, faChevronLeft, faUnderline, faStrikethrough, faSubscript, faSuperscript, faIndent, faEyeDropper, faCaretDown, faPalette, faHighlighter, faLink, faPaintRoller, faSleigh } from "@fortawesome/free-solid-svg-icons"; import { updateBullets } from "./ProsemirrorExampleTransfer"; import { FieldViewProps } from "../FieldView"; -import { Cast, StrCast } from "../../../../new_fields/Types"; +import { Cast, StrCast } from "../../../../fields/Types"; import { FormattedTextBoxProps } from "./FormattedTextBox"; import { unimplementedFunction, Utils } from "../../../../Utils"; import { wrapInList } from "prosemirror-schema-list"; -import { PastelSchemaPalette, DarkPastelSchemaPalette } from '../../../../new_fields/SchemaHeaderField'; +import { PastelSchemaPalette, DarkPastelSchemaPalette } from '../../../../fields/SchemaHeaderField'; import "./RichTextMenu.scss"; import { DocServer } from "../../../DocServer"; -import { Doc } from "../../../../new_fields/Doc"; +import { Doc } from "../../../../fields/Doc"; import { SelectionManager } from "../../../util/SelectionManager"; import { LinkManager } from "../../../util/LinkManager"; const { toggleMark, setBlockType } = require("prosemirror-commands"); diff --git a/src/client/views/nodes/formattedText/RichTextRules.ts b/src/client/views/nodes/formattedText/RichTextRules.ts index 0ba591fec..fbd6c87bb 100644 --- a/src/client/views/nodes/formattedText/RichTextRules.ts +++ b/src/client/views/nodes/formattedText/RichTextRules.ts @@ -1,9 +1,9 @@ import { ellipsis, emDash, InputRule, smartQuotes, textblockTypeInputRule } from "prosemirror-inputrules"; import { NodeSelection, TextSelection } from "prosemirror-state"; -import { DataSym, Doc } from "../../../../new_fields/Doc"; -import { Id } from "../../../../new_fields/FieldSymbols"; -import { ComputedField } from "../../../../new_fields/ScriptField"; -import { Cast, NumCast } from "../../../../new_fields/Types"; +import { DataSym, Doc } from "../../../../fields/Doc"; +import { Id } from "../../../../fields/FieldSymbols"; +import { ComputedField } from "../../../../fields/ScriptField"; +import { Cast, NumCast } from "../../../../fields/Types"; import { returnFalse, Utils } from "../../../../Utils"; import { DocServer } from "../../../DocServer"; import { Docs, DocUtils } from "../../../documents/Documents"; @@ -11,7 +11,7 @@ import { FormattedTextBox } from "./FormattedTextBox"; import { wrappingInputRule } from "./prosemirrorPatches"; import RichTextMenu from "./RichTextMenu"; import { schema } from "./schema_rts"; -import { List } from "../../../../new_fields/List"; +import { List } from "../../../../fields/List"; export class RichTextRules { public Document: Doc; diff --git a/src/client/views/nodes/formattedText/RichTextSchema.tsx b/src/client/views/nodes/formattedText/RichTextSchema.tsx index 7edd191cf..91280dea4 100644 --- a/src/client/views/nodes/formattedText/RichTextSchema.tsx +++ b/src/client/views/nodes/formattedText/RichTextSchema.tsx @@ -8,14 +8,14 @@ import { EditorState, NodeSelection, Plugin, TextSelection } from "prosemirror-s import { StepMap } from "prosemirror-transform"; import { EditorView } from "prosemirror-view"; import * as ReactDOM from 'react-dom'; -import { Doc, DocListCast, Field, HeightSym, WidthSym } from "../../../../new_fields/Doc"; -import { Id } from "../../../../new_fields/FieldSymbols"; -import { List } from "../../../../new_fields/List"; -import { ObjectField } from "../../../../new_fields/ObjectField"; -import { listSpec } from "../../../../new_fields/Schema"; -import { SchemaHeaderField } from "../../../../new_fields/SchemaHeaderField"; -import { ComputedField } from "../../../../new_fields/ScriptField"; -import { BoolCast, Cast, NumCast, StrCast, FieldValue } from "../../../../new_fields/Types"; +import { Doc, DocListCast, Field, HeightSym, WidthSym } from "../../../../fields/Doc"; +import { Id } from "../../../../fields/FieldSymbols"; +import { List } from "../../../../fields/List"; +import { ObjectField } from "../../../../fields/ObjectField"; +import { listSpec } from "../../../../fields/Schema"; +import { SchemaHeaderField } from "../../../../fields/SchemaHeaderField"; +import { ComputedField } from "../../../../fields/ScriptField"; +import { BoolCast, Cast, NumCast, StrCast, FieldValue } from "../../../../fields/Types"; import { emptyFunction, returnEmptyString, returnFalse, returnOne, Utils, returnZero } from "../../../../Utils"; import { DocServer } from "../../../DocServer"; import { Docs } from "../../../documents/Documents"; diff --git a/src/client/views/nodes/formattedText/marks_rts.ts b/src/client/views/nodes/formattedText/marks_rts.ts index 46bf481fb..ebaa23e99 100644 --- a/src/client/views/nodes/formattedText/marks_rts.ts +++ b/src/client/views/nodes/formattedText/marks_rts.ts @@ -1,6 +1,6 @@ import React = require("react"); import { DOMOutputSpecArray, Fragment, MarkSpec, Node, NodeSpec, Schema, Slice } from "prosemirror-model"; -import { Doc } from "../../../../new_fields/Doc"; +import { Doc } from "../../../../fields/Doc"; const emDOM: DOMOutputSpecArray = ["em", 0]; diff --git a/src/client/views/pdf/Annotation.tsx b/src/client/views/pdf/Annotation.tsx index 672d3adb8..cb6a15f36 100644 --- a/src/client/views/pdf/Annotation.tsx +++ b/src/client/views/pdf/Annotation.tsx @@ -1,10 +1,10 @@ import React = require("react"); import { action, IReactionDisposer, observable, reaction, runInAction } from "mobx"; import { observer } from "mobx-react"; -import { Doc, DocListCast, HeightSym, WidthSym } from "../../../new_fields/Doc"; -import { Id } from "../../../new_fields/FieldSymbols"; -import { List } from "../../../new_fields/List"; -import { Cast, FieldValue, NumCast, StrCast } from "../../../new_fields/Types"; +import { Doc, DocListCast, HeightSym, WidthSym } from "../../../fields/Doc"; +import { Id } from "../../../fields/FieldSymbols"; +import { List } from "../../../fields/List"; +import { Cast, FieldValue, NumCast, StrCast } from "../../../fields/Types"; import { DocumentManager } from "../../util/DocumentManager"; import PDFMenu from "./PDFMenu"; import "./Annotation.scss"; diff --git a/src/client/views/pdf/PDFMenu.tsx b/src/client/views/pdf/PDFMenu.tsx index 2a6eff7ff..ff328068b 100644 --- a/src/client/views/pdf/PDFMenu.tsx +++ b/src/client/views/pdf/PDFMenu.tsx @@ -5,7 +5,7 @@ import { observer } from "mobx-react"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { unimplementedFunction, returnFalse } from "../../../Utils"; import AntimodeMenu from "../AntimodeMenu"; -import { Doc, Opt } from "../../../new_fields/Doc"; +import { Doc, Opt } from "../../../fields/Doc"; @observer export default class PDFMenu extends AntimodeMenu { diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index acaa4363e..c50969493 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -4,16 +4,16 @@ import * as Pdfjs from "pdfjs-dist"; import "pdfjs-dist/web/pdf_viewer.css"; import * as rp from "request-promise"; import { Dictionary } from "typescript-collections"; -import { Doc, DocListCast, FieldResult, HeightSym, Opt, WidthSym } from "../../../new_fields/Doc"; -import { documentSchema } from "../../../new_fields/documentSchemas"; -import { Id } from "../../../new_fields/FieldSymbols"; -import { InkTool } from "../../../new_fields/InkField"; -import { List } from "../../../new_fields/List"; -import { createSchema, makeInterface } from "../../../new_fields/Schema"; -import { ScriptField } from "../../../new_fields/ScriptField"; -import { Cast, NumCast } from "../../../new_fields/Types"; -import { PdfField } from "../../../new_fields/URLField"; -import { TraceMobx } from "../../../new_fields/util"; +import { Doc, DocListCast, FieldResult, HeightSym, Opt, WidthSym } from "../../../fields/Doc"; +import { documentSchema } from "../../../fields/documentSchemas"; +import { Id } from "../../../fields/FieldSymbols"; +import { InkTool } from "../../../fields/InkField"; +import { List } from "../../../fields/List"; +import { createSchema, makeInterface } from "../../../fields/Schema"; +import { ScriptField } from "../../../fields/ScriptField"; +import { Cast, NumCast } from "../../../fields/Types"; +import { PdfField } from "../../../fields/URLField"; +import { TraceMobx } from "../../../fields/util"; import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, emptyFunction, emptyPath, intersectRect, returnZero, smoothScroll, Utils } from "../../../Utils"; import { Docs, DocUtils } from "../../documents/Documents"; import { DocumentType } from "../../documents/DocumentTypes"; diff --git a/src/client/views/presentationview/PresElementBox.tsx b/src/client/views/presentationview/PresElementBox.tsx index e13a5f2f7..280ba9093 100644 --- a/src/client/views/presentationview/PresElementBox.tsx +++ b/src/client/views/presentationview/PresElementBox.tsx @@ -1,11 +1,11 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { action, computed, IReactionDisposer, reaction } from "mobx"; import { observer } from "mobx-react"; -import { Doc, DataSym, DocListCast } from "../../../new_fields/Doc"; -import { documentSchema } from '../../../new_fields/documentSchemas'; -import { Id } from "../../../new_fields/FieldSymbols"; -import { createSchema, makeInterface } from '../../../new_fields/Schema'; -import { Cast, NumCast, BoolCast, ScriptCast } from "../../../new_fields/Types"; +import { Doc, DataSym, DocListCast } from "../../../fields/Doc"; +import { documentSchema } from '../../../fields/documentSchemas'; +import { Id } from "../../../fields/FieldSymbols"; +import { createSchema, makeInterface } from '../../../fields/Schema'; +import { Cast, NumCast, BoolCast, ScriptCast } from "../../../fields/Types"; import { emptyFunction, emptyPath, returnFalse, returnTrue, returnOne, returnZero } from "../../../Utils"; import { Transform } from "../../util/Transform"; import { CollectionViewType } from '../collections/CollectionView'; diff --git a/src/client/views/search/FilterBox.tsx b/src/client/views/search/FilterBox.tsx index 662b37d77..4b53963a5 100644 --- a/src/client/views/search/FilterBox.tsx +++ b/src/client/views/search/FilterBox.tsx @@ -4,10 +4,10 @@ import { observable, action } from 'mobx'; import "./SearchBox.scss"; import { faTimes, faCheckCircle, faObjectGroup } from '@fortawesome/free-solid-svg-icons'; import { library } from '@fortawesome/fontawesome-svg-core'; -import { Doc } from '../../../new_fields/Doc'; -import { Id } from '../../../new_fields/FieldSymbols'; +import { Doc } from '../../../fields/Doc'; +import { Id } from '../../../fields/FieldSymbols'; import { DocumentType } from "../../documents/DocumentTypes"; -import { Cast, StrCast } from '../../../new_fields/Types'; +import { Cast, StrCast } from '../../../fields/Types'; import * as _ from "lodash"; import { IconBar } from './IconBar'; import { FieldFilters } from './FieldFilters'; diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx index e41b725b1..eea7b528b 100644 --- a/src/client/views/search/SearchBox.tsx +++ b/src/client/views/search/SearchBox.tsx @@ -5,9 +5,9 @@ import { action, computed, observable, runInAction, IReactionDisposer, reaction import { observer } from 'mobx-react'; import * as React from 'react'; import * as rp from 'request-promise'; -import { Doc } from '../../../new_fields/Doc'; -import { Id } from '../../../new_fields/FieldSymbols'; -import { Cast, NumCast, StrCast } from '../../../new_fields/Types'; +import { Doc } from '../../../fields/Doc'; +import { Id } from '../../../fields/FieldSymbols'; +import { Cast, NumCast, StrCast } from '../../../fields/Types'; import { Utils } from '../../../Utils'; import { Docs } from '../../documents/Documents'; import { SetupDrag } from '../../util/DragManager'; @@ -19,7 +19,7 @@ import { FieldView } from '../nodes/FieldView'; import { DocumentType } from "../../documents/DocumentTypes"; import { DocumentView } from '../nodes/DocumentView'; import { SelectionManager } from '../../util/SelectionManager'; -import { listSpec } from '../../../new_fields/Schema'; +import { listSpec } from '../../../fields/Schema'; library.add(faTimes); diff --git a/src/client/views/search/SearchItem.tsx b/src/client/views/search/SearchItem.tsx index 96f43e931..24d6e9d6f 100644 --- a/src/client/views/search/SearchItem.tsx +++ b/src/client/views/search/SearchItem.tsx @@ -4,9 +4,9 @@ import { faCaretUp, faChartBar, faFile, faFilePdf, faFilm, faFingerprint, faGlob import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { action, computed, observable, runInAction } from "mobx"; import { observer } from "mobx-react"; -import { Doc } from "../../../new_fields/Doc"; -import { Id } from "../../../new_fields/FieldSymbols"; -import { Cast, NumCast, StrCast } from "../../../new_fields/Types"; +import { Doc } from "../../../fields/Doc"; +import { Id } from "../../../fields/FieldSymbols"; +import { Cast, NumCast, StrCast } from "../../../fields/Types"; import { emptyFunction, emptyPath, returnFalse, Utils, returnTrue, returnOne, returnZero } from "../../../Utils"; import { DocumentType } from "../../documents/DocumentTypes"; import { DocumentManager } from "../../util/DocumentManager"; diff --git a/src/debug/Repl.tsx b/src/debug/Repl.tsx index fd6b47ff0..d541c8009 100644 --- a/src/debug/Repl.tsx +++ b/src/debug/Repl.tsx @@ -3,9 +3,9 @@ import * as ReactDOM from 'react-dom'; import { observer } from 'mobx-react'; import { observable, computed } from 'mobx'; import { CompileScript } from '../client/util/Scripting'; -import { makeInterface } from '../new_fields/Schema'; -import { ObjectField } from '../new_fields/ObjectField'; -import { RefField } from '../new_fields/RefField'; +import { makeInterface } from '../fields/Schema'; +import { ObjectField } from '../fields/ObjectField'; +import { RefField } from '../fields/RefField'; import { DocServer } from '../client/DocServer'; @observer diff --git a/src/debug/Test.tsx b/src/debug/Test.tsx index 3baedce4b..17d3db8fd 100644 --- a/src/debug/Test.tsx +++ b/src/debug/Test.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; import * as ReactDOM from 'react-dom'; import { DocServer } from '../client/DocServer'; -import { Doc } from '../new_fields/Doc'; +import { Doc } from '../fields/Doc'; import * as Pdfjs from "pdfjs-dist"; import "pdfjs-dist/web/pdf_viewer.css"; import { Utils } from '../Utils'; diff --git a/src/debug/Viewer.tsx b/src/debug/Viewer.tsx index a26d2e06a..6ce39d533 100644 --- a/src/debug/Viewer.tsx +++ b/src/debug/Viewer.tsx @@ -3,17 +3,17 @@ import "normalize.css"; import * as React from 'react'; import * as ReactDOM from 'react-dom'; import { observer } from 'mobx-react'; -import { Doc, Field, FieldResult, Opt } from '../new_fields/Doc'; +import { Doc, Field, FieldResult, Opt } from '../fields/Doc'; import { DocServer } from '../client/DocServer'; -import { Id } from '../new_fields/FieldSymbols'; -import { List } from '../new_fields/List'; -import { URLField } from '../new_fields/URLField'; +import { Id } from '../fields/FieldSymbols'; +import { List } from '../fields/List'; +import { URLField } from '../fields/URLField'; import { EditableView } from '../client/views/EditableView'; import { CompileScript } from '../client/util/Scripting'; -import { RichTextField } from '../new_fields/RichTextField'; -import { DateField } from '../new_fields/DateField'; -import { ScriptField } from '../new_fields/ScriptField'; -import CursorField from '../new_fields/CursorField'; +import { RichTextField } from '../fields/RichTextField'; +import { DateField } from '../fields/DateField'; +import { ScriptField } from '../fields/ScriptField'; +import CursorField from '../fields/CursorField'; DateField; URLField; diff --git a/src/fields/CursorField.ts b/src/fields/CursorField.ts new file mode 100644 index 000000000..28467377b --- /dev/null +++ b/src/fields/CursorField.ts @@ -0,0 +1,66 @@ +import { ObjectField } from "./ObjectField"; +import { observable } from "mobx"; +import { Deserializable } from "../client/util/SerializationHelper"; +import { serializable, createSimpleSchema, object, date } from "serializr"; +import { OnUpdate, ToScriptString, ToString, Copy } from "./FieldSymbols"; + +export type CursorPosition = { + x: number, + y: number +}; + +export type CursorMetadata = { + id: string, + identifier: string, + timestamp: number +}; + +export type CursorData = { + metadata: CursorMetadata, + position: CursorPosition +}; + +const PositionSchema = createSimpleSchema({ + x: true, + y: true +}); + +const MetadataSchema = createSimpleSchema({ + id: true, + identifier: true, + timestamp: true +}); + +const CursorSchema = createSimpleSchema({ + metadata: object(MetadataSchema), + position: object(PositionSchema) +}); + +@Deserializable("cursor") +export default class CursorField extends ObjectField { + + @serializable(object(CursorSchema)) + readonly data: CursorData; + + constructor(data: CursorData) { + super(); + this.data = data; + } + + setPosition(position: CursorPosition) { + this.data.position = position; + this.data.metadata.timestamp = Date.now(); + this[OnUpdate](); + } + + [Copy]() { + return new CursorField(this.data); + } + + [ToScriptString]() { + return "invalid"; + } + [ToString]() { + return "invalid"; + } +} \ No newline at end of file diff --git a/src/fields/DateField.ts b/src/fields/DateField.ts new file mode 100644 index 000000000..a925148c2 --- /dev/null +++ b/src/fields/DateField.ts @@ -0,0 +1,36 @@ +import { Deserializable } from "../client/util/SerializationHelper"; +import { serializable, date } from "serializr"; +import { ObjectField } from "./ObjectField"; +import { Copy, ToScriptString, ToString } from "./FieldSymbols"; +import { scriptingGlobal, Scripting } from "../client/util/Scripting"; + +@scriptingGlobal +@Deserializable("date") +export class DateField extends ObjectField { + @serializable(date()) + readonly date: Date; + + constructor(date: Date = new Date()) { + super(); + this.date = date; + } + + [Copy]() { + return new DateField(this.date); + } + + toString() { + return `${this.date.toISOString()}`; + } + + [ToScriptString]() { + return `new DateField(new Date(${this.date.toISOString()}))`; + } + [ToString]() { + return this.date.toISOString(); + } +} + +Scripting.addGlobal(function d(...dateArgs: any[]) { + return new DateField(new (Date as any)(...dateArgs)); +}); diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts new file mode 100644 index 000000000..a1e1e11b1 --- /dev/null +++ b/src/fields/Doc.ts @@ -0,0 +1,1109 @@ +import { action, computed, observable, ObservableMap, runInAction } from "mobx"; +import { computedFn } from "mobx-utils"; +import { alias, map, serializable } from "serializr"; +import { DocServer } from "../client/DocServer"; +import { DocumentType } from "../client/documents/DocumentTypes"; +import { Scripting, scriptingGlobal } from "../client/util/Scripting"; +import { afterDocDeserialize, autoObject, Deserializable, SerializationHelper } from "../client/util/SerializationHelper"; +import { UndoManager } from "../client/util/UndoManager"; +import { intersectRect, Utils } from "../Utils"; +import { HandleUpdate, Id, OnUpdate, Parent, Self, SelfProxy, ToScriptString, ToString, Update, Copy } from "./FieldSymbols"; +import { List } from "./List"; +import { ObjectField } from "./ObjectField"; +import { PrefetchProxy, ProxyField } from "./Proxy"; +import { FieldId, RefField } from "./RefField"; +import { RichTextField } from "./RichTextField"; +import { listSpec } from "./Schema"; +import { ComputedField, ScriptField } from "./ScriptField"; +import { Cast, FieldValue, NumCast, StrCast, ToConstructor, ScriptCast } from "./Types"; +import { deleteProperty, getField, getter, makeEditable, makeReadOnly, setter, updateFunction } from "./util"; +import { Docs, DocumentOptions } from "../client/documents/Documents"; +import { PdfField, VideoField, AudioField, ImageField } from "./URLField"; +import { LinkManager } from "../client/util/LinkManager"; + +export namespace Field { + export function toKeyValueString(doc: Doc, key: string): string { + const onDelegate = Object.keys(doc).includes(key); + + const field = ComputedField.WithoutComputed(() => FieldValue(doc[key])); + if (Field.IsField(field)) { + return (onDelegate ? "=" : "") + (field instanceof ComputedField ? `:=${field.script.originalScript}` : Field.toScriptString(field)); + } + return ""; + } + export function toScriptString(field: Field): string { + if (typeof field === "string") { + return `"${field}"`; + } else if (typeof field === "number" || typeof field === "boolean") { + return String(field); + } else { + return field[ToScriptString](); + } + } + export function toString(field: Field): string { + if (typeof field === "string") { + return field; + } else if (typeof field === "number" || typeof field === "boolean") { + return String(field); + } else if (field instanceof ObjectField) { + return field[ToString](); + } else if (field instanceof RefField) { + return field[ToString](); + } + return ""; + } + export function IsField(field: any): field is Field; + export function IsField(field: any, includeUndefined: true): field is Field | undefined; + export function IsField(field: any, includeUndefined: boolean = false): field is Field | undefined { + return (typeof field === "string") + || (typeof field === "number") + || (typeof field === "boolean") + || (field instanceof ObjectField) + || (field instanceof RefField) + || (includeUndefined && field === undefined); + } +} +export type Field = number | string | boolean | ObjectField | RefField; +export type Opt = T | undefined; +export type FieldWaiting = T extends undefined ? never : Promise; +export type FieldResult = Opt | FieldWaiting>; + +/** + * Cast any field to either a List of Docs or undefined if the given field isn't a List of Docs. + * If a default value is given, that will be returned instead of undefined. + * If a default value is given, the returned value should not be modified as it might be a temporary value. + * If no default value is given, and the returned value is not undefined, it can be safely modified. + */ +export function DocListCastAsync(field: FieldResult): Promise; +export function DocListCastAsync(field: FieldResult, defaultValue: Doc[]): Promise; +export function DocListCastAsync(field: FieldResult, defaultValue?: Doc[]) { + const list = Cast(field, listSpec(Doc)); + return list ? Promise.all(list).then(() => list) : Promise.resolve(defaultValue); +} + +export async function DocCastAsync(field: FieldResult): Promise> { + return Cast(field, Doc); +} + +export function DocListCast(field: FieldResult): Doc[] { + return Cast(field, listSpec(Doc), []).filter(d => d instanceof Doc) as Doc[]; +} + +export const WidthSym = Symbol("Width"); +export const HeightSym = Symbol("Height"); +export const DataSym = Symbol("Data"); +export const LayoutSym = Symbol("Layout"); +export const UpdatingFromServer = Symbol("UpdatingFromServer"); +const CachedUpdates = Symbol("Cached updates"); + + +function fetchProto(doc: Doc) { + const proto = doc.proto; + if (proto instanceof Promise) { + return proto; + } +} + +@scriptingGlobal +@Deserializable("Doc", fetchProto).withFields(["id"]) +export class Doc extends RefField { + constructor(id?: FieldId, forceSave?: boolean) { + super(id); + const doc = new Proxy(this, { + set: setter, + get: getter, + // getPrototypeOf: (target) => Cast(target[SelfProxy].proto, Doc) || null, // TODO this might be able to replace the proto logic in getter + has: (target, key) => key in target.__fields, + ownKeys: target => { + const obj = {} as any; + Object.assign(obj, target.___fields); + runInAction(() => obj.__LAYOUT__ = target.__LAYOUT__); + return Object.keys(obj); + }, + getOwnPropertyDescriptor: (target, prop) => { + if (prop.toString() === "__LAYOUT__") { + return Reflect.getOwnPropertyDescriptor(target, prop); + } + if (prop in target.__fields) { + return { + configurable: true,//TODO Should configurable be true? + enumerable: true, + value: target.__fields[prop] + }; + } + return Reflect.getOwnPropertyDescriptor(target, prop); + }, + deleteProperty: deleteProperty, + defineProperty: () => { throw new Error("Currently properties can't be defined on documents using Object.defineProperty"); }, + }); + this[SelfProxy] = doc; + if (!id || forceSave) { + DocServer.CreateField(doc); + } + return doc; + } + + proto: Opt; + [key: string]: FieldResult; + + @serializable(alias("fields", map(autoObject(), { afterDeserialize: afterDocDeserialize }))) + private get __fields() { return this.___fields; } + private set __fields(value) { + this.___fields = value; + for (const key in value) { + const field = value[key]; + if (!(field instanceof ObjectField)) continue; + field[Parent] = this[Self]; + field[OnUpdate] = updateFunction(this[Self], key, field, this[SelfProxy]); + } + } + + @observable + //{ [key: string]: Field | FieldWaiting | undefined } + private ___fields: any = {}; + + private [UpdatingFromServer]: boolean = false; + + private [Update] = (diff: any) => { + !this[UpdatingFromServer] && DocServer.UpdateField(this[Id], diff); + } + + private [Self] = this; + private [SelfProxy]: any; + public [WidthSym] = () => NumCast(this[SelfProxy]._width); + public [HeightSym] = () => NumCast(this[SelfProxy]._height); + public get [LayoutSym]() { return this[SelfProxy].__LAYOUT__; } + public get [DataSym]() { + const self = this[SelfProxy]; + return self.resolvedDataDoc && !self.isTemplateForField ? self : + Doc.GetProto(Cast(Doc.Layout(self).resolvedDataDoc, Doc, null) || self); + } + @computed get __LAYOUT__() { + const templateLayoutDoc = Cast(Doc.LayoutField(this[SelfProxy]), Doc, null); + if (templateLayoutDoc) { + let renderFieldKey: any; + const layoutField = templateLayoutDoc[StrCast(templateLayoutDoc.layoutKey, "layout")]; + if (typeof layoutField === "string") { + renderFieldKey = layoutField.split("fieldKey={'")[1].split("'")[0];//layoutField.split("'")[1]; + } else { + return Cast(layoutField, Doc, null); + } + return Cast(this[SelfProxy][renderFieldKey + "-layout[" + templateLayoutDoc[Id] + "]"], Doc, null) || templateLayoutDoc; + } + return undefined; + } + + [ToScriptString]() { return `DOC-"${this[Self][Id]}"-`; } + [ToString]() { return `Doc(${this.title})`; } + + private [CachedUpdates]: { [key: string]: () => void | Promise } = {}; + public static CurrentUserEmail: string = ""; + public async [HandleUpdate](diff: any) { + const set = diff.$set; + const sameAuthor = this.author === Doc.CurrentUserEmail; + if (set) { + for (const key in set) { + if (!key.startsWith("fields.")) { + continue; + } + const fKey = key.substring(7); + const fn = async () => { + const value = await SerializationHelper.Deserialize(set[key]); + this[UpdatingFromServer] = true; + this[fKey] = value; + this[UpdatingFromServer] = false; + }; + if (sameAuthor || DocServer.getFieldWriteMode(fKey) !== DocServer.WriteMode.Playground) { + delete this[CachedUpdates][fKey]; + await fn(); + } else { + this[CachedUpdates][fKey] = fn; + } + } + } + const unset = diff.$unset; + if (unset) { + for (const key in unset) { + if (!key.startsWith("fields.")) { + continue; + } + const fKey = key.substring(7); + const fn = () => { + this[UpdatingFromServer] = true; + delete this[fKey]; + this[UpdatingFromServer] = false; + }; + if (sameAuthor || DocServer.getFieldWriteMode(fKey) !== DocServer.WriteMode.Playground) { + delete this[CachedUpdates][fKey]; + await fn(); + } else { + this[CachedUpdates][fKey] = fn; + } + } + } + } +} + +export namespace Doc { + // export function GetAsync(doc: Doc, key: string, ignoreProto: boolean = false): Promise { + // const self = doc[Self]; + // return new Promise(res => getField(self, key, ignoreProto, res)); + // } + // export function GetTAsync(doc: Doc, key: string, ctor: ToConstructor, ignoreProto: boolean = false): Promise { + // return new Promise(async res => { + // const field = await GetAsync(doc, key, ignoreProto); + // return Cast(field, ctor); + // }); + // } + + export function RunCachedUpdate(doc: Doc, field: string) { + const update = doc[CachedUpdates][field]; + if (update) { + update(); + delete doc[CachedUpdates][field]; + } + } + export function AddCachedUpdate(doc: Doc, field: string, oldValue: any) { + const val = oldValue; + doc[CachedUpdates][field] = () => { + doc[UpdatingFromServer] = true; + doc[field] = val; + doc[UpdatingFromServer] = false; + }; + } + export function MakeReadOnly(): { end(): void } { + makeReadOnly(); + return { + end() { + makeEditable(); + } + }; + } + + export function Get(doc: Doc, key: string, ignoreProto: boolean = false): FieldResult { + try { + return getField(doc[Self], key, ignoreProto); + } catch { + return doc; + } + } + export function GetT(doc: Doc, key: string, ctor: ToConstructor, ignoreProto: boolean = false): FieldResult { + return Cast(Get(doc, key, ignoreProto), ctor) as FieldResult; + } + export function IsPrototype(doc: Doc) { + return GetT(doc, "isPrototype", "boolean", true); + } + export function IsBaseProto(doc: Doc) { + return GetT(doc, "baseProto", "boolean", true); + } + export async function SetInPlace(doc: Doc, key: string, value: Field | undefined, defaultProto: boolean) { + const hasProto = doc.proto instanceof Doc; + const onDeleg = Object.getOwnPropertyNames(doc).indexOf(key) !== -1; + const onProto = hasProto && Object.getOwnPropertyNames(doc.proto).indexOf(key) !== -1; + if (onDeleg || !hasProto || (!onProto && !defaultProto)) { + doc[key] = value; + } else doc.proto![key] = value; + } + export async function SetOnPrototype(doc: Doc, key: string, value: Field) { + const proto = Object.getOwnPropertyNames(doc).indexOf("isPrototype") === -1 ? doc.proto : doc; + + if (proto) { + proto[key] = value; + } + } + export function GetAllPrototypes(doc: Doc): Doc[] { + const protos: Doc[] = []; + let d: Opt = doc; + while (d) { + protos.push(d); + d = FieldValue(d.proto); + } + return protos; + } + + /** + * This function is intended to model Object.assign({}, {}) [https://mzl.la/1Mo3l21], which copies + * the values of the properties of a source object into the target. + * + * This is just a specific, Dash-authored version that serves the same role for our + * Doc class. + * + * @param doc the target document into which you'd like to insert the new fields + * @param fields the fields to project onto the target. Its type signature defines a mapping from some string key + * to a potentially undefined field, where each entry in this mapping is optional. + */ + export function assign(doc: Doc, fields: Partial>>, skipUndefineds: boolean = false) { + for (const key in fields) { + if (fields.hasOwnProperty(key)) { + const value = fields[key]; + if (!skipUndefineds || value !== undefined) { // Do we want to filter out undefineds? + doc[key] = value; + } + } + } + return doc; + } + + // compare whether documents or their protos match + export function AreProtosEqual(doc?: Doc, other?: Doc) { + if (!doc || !other) return false; + const r = (doc === other); + const r2 = (Doc.GetProto(doc) === other); + const r3 = (Doc.GetProto(other) === doc); + const r4 = (Doc.GetProto(doc) === Doc.GetProto(other) && Doc.GetProto(other) !== undefined); + return r || r2 || r3 || r4; + } + + // Gets the data document for the document. Note: this is mis-named -- it does not specifically + // return the doc's proto, but rather recursively searches through the proto inheritance chain + // and returns the document who's proto is undefined or whose proto is marked as a base prototype ('isPrototype'). + export function GetProto(doc: Doc): Doc { + if (doc instanceof Promise) { + console.log("GetProto: error: got Promise insead of Doc"); + } + const proto = doc && (Doc.GetT(doc, "isPrototype", "boolean", true) ? doc : (doc.proto || doc)); + return proto === doc ? proto : Doc.GetProto(proto); + } + export function GetDataDoc(doc: Doc): Doc { + const proto = Doc.GetProto(doc); + return proto === doc ? proto : Doc.GetDataDoc(proto); + } + + export function allKeys(doc: Doc): string[] { + const results: Set = new Set; + + let proto: Doc | undefined = doc; + while (proto) { + Object.keys(proto).forEach(key => results.add(key)); + proto = proto.proto; + } + + return Array.from(results); + } + + export function IndexOf(toFind: Doc, list: Doc[], allowProtos: boolean = true) { + let index = list.reduce((p, v, i) => (v instanceof Doc && v === toFind) ? i : p, -1); + index = allowProtos && index !== -1 ? index : list.reduce((p, v, i) => (v instanceof Doc && Doc.AreProtosEqual(v, toFind)) ? i : p, -1); + return index; // list.findIndex(doc => doc === toFind || Doc.AreProtosEqual(doc, toFind)); + } + export function RemoveDocFromList(listDoc: Doc, fieldKey: string | undefined, doc: Doc) { + const key = fieldKey ? fieldKey : Doc.LayoutFieldKey(listDoc); + if (listDoc[key] === undefined) { + Doc.GetProto(listDoc)[key] = new List(); + } + const list = Cast(listDoc[key], listSpec(Doc)); + if (list) { + const ind = list.indexOf(doc); + if (ind !== -1) { + list.splice(ind, 1); + return true; + } + } + return false; + } + export function AddDocToList(listDoc: Doc, fieldKey: string | undefined, doc: Doc, relativeTo?: Doc, before?: boolean, first?: boolean, allowDuplicates?: boolean, reversed?: boolean) { + const key = fieldKey ? fieldKey : Doc.LayoutFieldKey(listDoc); + if (listDoc[key] === undefined) { + Doc.GetProto(listDoc)[key] = new List(); + } + const list = Cast(listDoc[key], listSpec(Doc)); + if (list) { + if (allowDuplicates !== true) { + const pind = list.reduce((l, d, i) => d instanceof Doc && d[Id] === doc[Id] ? i : l, -1); + if (pind !== -1) { + list.splice(pind, 1); + } + } + if (first) { + list.splice(0, 0, doc); + } + else { + const ind = relativeTo ? list.indexOf(relativeTo) : -1; + if (ind === -1) { + if (reversed) list.splice(0, 0, doc); + else list.push(doc); + } + else { + if (reversed) list.splice(before ? (list.length - ind) + 1 : list.length - ind, 0, doc); + else list.splice(before ? ind : ind + 1, 0, doc); + } + } + return true; + } + return false; + } + + // + // Computes the bounds of the contents of a set of documents. + // + export function ComputeContentBounds(docList: Doc[]) { + const bounds = docList.reduce((bounds, doc) => { + const [sptX, sptY] = [NumCast(doc.x), NumCast(doc.y)]; + const [bptX, bptY] = [sptX + doc[WidthSym](), sptY + doc[HeightSym]()]; + return { + x: Math.min(sptX, bounds.x), y: Math.min(sptY, bounds.y), + r: Math.max(bptX, bounds.r), b: Math.max(bptY, bounds.b) + }; + }, { x: Number.MAX_VALUE, y: Number.MAX_VALUE, r: -Number.MAX_VALUE, b: -Number.MAX_VALUE }); + return bounds; + } + + export function MakeAlias(doc: Doc, id?: string) { + const alias = !GetT(doc, "isPrototype", "boolean", true) ? Doc.MakeCopy(doc, undefined, id) : Doc.MakeDelegate(doc, id); + const layout = Doc.LayoutField(alias); + if (layout instanceof Doc && layout !== alias && layout === Doc.Layout(alias)) { + Doc.SetLayout(alias, Doc.MakeAlias(layout)); + } + alias.aliasOf = doc; + alias.title = ComputedField.MakeFunction(`renameAlias(this, ${Doc.GetProto(doc).aliasNumber = NumCast(Doc.GetProto(doc).aliasNumber) + 1})`); + return alias; + } + + // + // Determines whether the layout needs to be expanded (as a template). + // template expansion is rquired when the layout is a template doc/field and there's a datadoc which isn't equal to the layout template + // + export function WillExpandTemplateLayout(layoutDoc: Doc, dataDoc?: Doc) { + return (layoutDoc.isTemplateForField || layoutDoc.isTemplateDoc) && dataDoc && layoutDoc !== dataDoc; + } + + const _pendingMap: Map = new Map(); + // + // Returns an expanded template layout for a target data document if there is a template relationship + // between the two. If so, the layoutDoc is expanded into a new document that inherits the properties + // of the original layout while allowing for individual layout properties to be overridden in the expanded layout. + // templateArgs should be equivalent to the layout key that generates the template since that's where the template parameters are stored in ()'s at the end of the key. + // NOTE: the template will have references to "@params" -- the template arguments will be assigned to the '@params' field + // so that when the @params key is accessed, it will be rewritten as the key that is stored in the 'params' field and + // the derefence will then occur on the rootDocument (the original document). + // in the future, field references could be written as @ and then arguments would be passed in the layout key as: + // layout_mytemplate(somparam=somearg). + // then any references to @someparam would be rewritten as accesses to 'somearg' on the rootDocument + export function expandTemplateLayout(templateLayoutDoc: Doc, targetDoc?: Doc, templateArgs?: string) { + const args = templateArgs?.match(/\(([a-zA-Z0-9._\-]*)\)/)?.[1].replace("()", "") || StrCast(templateLayoutDoc.PARAMS); + if (!args && !WillExpandTemplateLayout(templateLayoutDoc, targetDoc) || !targetDoc) return templateLayoutDoc; + + const templateField = StrCast(templateLayoutDoc.isTemplateForField); // the field that the template renders + // First it checks if an expanded layout already exists -- if so it will be stored on the dataDoc + // using the template layout doc's id as the field key. + // If it doesn't find the expanded layout, then it makes a delegate of the template layout and + // saves it on the data doc indexed by the template layout's id. + // + const params = args.split("=").length > 1 ? args.split("=")[0] : "PARAMS"; + const layoutFielddKey = Doc.LayoutFieldKey(templateLayoutDoc); + const expandedLayoutFieldKey = (templateField || layoutFielddKey) + "-layout[" + templateLayoutDoc[Id] + (args ? `(${args})` : "") + "]"; + let expandedTemplateLayout = targetDoc?.[expandedLayoutFieldKey]; + + if (templateLayoutDoc.resolvedDataDoc instanceof Promise) { + expandedTemplateLayout = undefined; + _pendingMap.set(targetDoc[Id] + expandedLayoutFieldKey, true); + } + else if (expandedTemplateLayout === undefined && !_pendingMap.get(targetDoc[Id] + expandedLayoutFieldKey + args)) { + if (templateLayoutDoc.resolvedDataDoc === (targetDoc.rootDocument || Doc.GetProto(targetDoc)) && templateLayoutDoc.PARAMS === StrCast(targetDoc.PARAMS)) { + expandedTemplateLayout = templateLayoutDoc; // reuse an existing template layout if its for the same document with the same params + } else { + _pendingMap.set(targetDoc[Id] + expandedLayoutFieldKey + args, true); + templateLayoutDoc.resolvedDataDoc && (templateLayoutDoc = Cast(templateLayoutDoc.proto, Doc, null) || templateLayoutDoc); // if the template has already been applied (ie, a nested template), then use the template's prototype + setTimeout(action(() => { + if (!targetDoc[expandedLayoutFieldKey]) { + const newLayoutDoc = Doc.MakeDelegate(templateLayoutDoc, undefined, "[" + templateLayoutDoc.title + "]"); + // the template's arguments are stored in params which is derefenced to find + // the actual field key where the parameterized template data is stored. + newLayoutDoc[params] = args !== "..." ? args : ""; // ... signifies the layout has sub template(s) -- so we have to expand the layout for them so that they can get the correct 'rootDocument' field, but we don't need to reassign their params. it would be better if the 'rootDocument' field could be passed dynamically to avoid have to create instances + newLayoutDoc.rootDocument = targetDoc; + targetDoc[expandedLayoutFieldKey] = newLayoutDoc; + const dataDoc = Doc.GetProto(targetDoc); + newLayoutDoc.resolvedDataDoc = dataDoc; + if (dataDoc[templateField] === undefined && templateLayoutDoc[templateField] instanceof List) { + dataDoc[templateField] = ComputedField.MakeFunction(`ObjectField.MakeCopy(templateLayoutDoc["${templateField}"] as List)`, { templateLayoutDoc: Doc.name }, { templateLayoutDoc }); + } + _pendingMap.delete(targetDoc[Id] + expandedLayoutFieldKey + args); + } + }), 0); + } + } + return expandedTemplateLayout instanceof Doc ? expandedTemplateLayout : undefined; // layout is undefined if the expandedTemplateLayout is pending. + } + + // if the childDoc is a template for a field, then this will return the expanded layout with its data doc. + // otherwise, it just returns the childDoc + export function GetLayoutDataDocPair(containerDoc: Doc, containerDataDoc: Opt, childDoc: Doc) { + if (!childDoc || childDoc instanceof Promise || !Doc.GetProto(childDoc)) { + console.log("No, no, no!"); + return { layout: childDoc, data: childDoc }; + } + const resolvedDataDoc = (Doc.AreProtosEqual(containerDataDoc, containerDoc) || (!childDoc.isTemplateDoc && !childDoc.isTemplateForField && !childDoc.PARAMS) ? undefined : containerDataDoc); + return { layout: Doc.expandTemplateLayout(childDoc, resolvedDataDoc, "(" + StrCast(containerDoc.PARAMS) + ")"), data: resolvedDataDoc }; + } + + export function Overwrite(doc: Doc, overwrite: Doc, copyProto: boolean = false): Doc { + Object.keys(doc).forEach(key => { + const field = ProxyField.WithoutProxy(() => doc[key]); + if (key === "proto" && copyProto) { + if (doc.proto instanceof Doc && overwrite.proto instanceof Doc) { + overwrite[key] = Doc.Overwrite(doc[key]!, overwrite.proto); + } + } else { + if (field instanceof RefField) { + overwrite[key] = field; + } else if (field instanceof ObjectField) { + overwrite[key] = ObjectField.MakeCopy(field); + } else if (field instanceof Promise) { + debugger; //This shouldn't happend... + } else { + overwrite[key] = field; + } + } + }); + + return overwrite; + } + + export function MakeCopy(doc: Doc, copyProto: boolean = false, copyProtoId?: string): Doc { + const copy = new Doc(copyProtoId, true); + const exclude = Cast(doc.excludeFields, listSpec("string"), []); + Object.keys(doc).forEach(key => { + if (exclude.includes(key)) return; + const cfield = ComputedField.WithoutComputed(() => FieldValue(doc[key])); + const field = ProxyField.WithoutProxy(() => doc[key]); + if (key === "proto" && copyProto) { + if (doc[key] instanceof Doc) { + copy[key] = Doc.MakeCopy(doc[key]!, false); + } + } else { + if (field instanceof RefField) { + copy[key] = field; + } else if (cfield instanceof ComputedField) { + copy[key] = ComputedField.MakeFunction(cfield.script.originalScript); + } else if (field instanceof ObjectField) { + copy[key] = doc[key] instanceof Doc ? + key.includes("layout[") ? Doc.MakeCopy(doc[key] as Doc, false) : doc[key] : // reference documents except copy documents that are expanded teplate fields + ObjectField.MakeCopy(field); + } else if (field instanceof Promise) { + debugger; //This shouldn't happend... + } else { + copy[key] = field; + } + } + }); + + return copy; + } + + export function MakeClone(doc: Doc): Doc { + const cloneMap = new Map(); + const rtfMap: { copy: Doc, key: string, field: RichTextField }[] = []; + const copy = Doc.makeClone(doc, cloneMap, rtfMap); + rtfMap.map(({ copy, key, field }) => { + const replacer = (match: any, attr: string, id: string, offset: any, string: any) => { + const mapped = cloneMap.get(id); + return attr + "\"" + (mapped ? mapped[Id] : id) + "\""; + }; + const replacer2 = (match: any, href: string, id: string, offset: any, string: any) => { + const mapped = cloneMap.get(id); + return href + (mapped ? mapped[Id] : id); + }; + const regex = `(${Utils.prepend("/doc/")})([^"]*)`; + const re = new RegExp(regex, "g"); + copy[key] = new RichTextField(field.Data.replace(/("docid":|"targetId":|"linkId":)"([^"]+)"/g, replacer).replace(re, replacer2), field.Text); + }); + return copy; + } + + export function makeClone(doc: Doc, cloneMap: Map, rtfs: { copy: Doc, key: string, field: RichTextField }[]): Doc { + if (Doc.IsBaseProto(doc)) return doc; + if (cloneMap.get(doc[Id])) return cloneMap.get(doc[Id])!; + const copy = new Doc(undefined, true); + cloneMap.set(doc[Id], copy); + if (LinkManager.Instance.getAllLinks().includes(doc) && LinkManager.Instance.getAllLinks().indexOf(copy) === -1) LinkManager.Instance.addLink(copy); + const exclude = Cast(doc.excludeFields, listSpec("string"), []); + Object.keys(doc).forEach(key => { + if (exclude.includes(key)) return; + const cfield = ComputedField.WithoutComputed(() => FieldValue(doc[key])); + const field = ProxyField.WithoutProxy(() => doc[key]); + const copyObjectField = (field: ObjectField) => { + const list = Cast(doc[key], listSpec(Doc)); + if (list !== undefined && !(list instanceof Promise)) { + copy[key] = new List(list.filter(d => d instanceof Doc).map(d => Doc.makeClone(d as Doc, cloneMap, rtfs))); + } else if (doc[key] instanceof Doc) { + copy[key] = key.includes("layout[") ? undefined : Doc.makeClone(doc[key] as Doc, cloneMap, rtfs); // reference documents except copy documents that are expanded teplate fields + } else { + copy[key] = ObjectField.MakeCopy(field); + if (field instanceof RichTextField) { + if (field.Data.includes('"docid":') || field.Data.includes('"targetId":') || field.Data.includes('"linkId":')) { + rtfs.push({ copy, key, field }); + } + } + } + }; + if (key === "proto") { + if (doc[key] instanceof Doc) { + copy[key] = Doc.makeClone(doc[key]!, cloneMap, rtfs); + } + } else { + if (field instanceof RefField) { + copy[key] = field; + } else if (cfield instanceof ComputedField) { + copy[key] = ComputedField.MakeFunction(cfield.script.originalScript); + (key === "links" && field instanceof ObjectField) && copyObjectField(field); + } else if (field instanceof ObjectField) { + copyObjectField(field); + } else if (field instanceof Promise) { + debugger; //This shouldn't happend... + } else { + copy[key] = field; + } + } + }); + Doc.SetInPlace(copy, "title", "CLONE: " + doc.title, true); + copy.cloneOf = doc; + cloneMap.set(doc[Id], copy); + return copy; + } + + export function MakeDelegate(doc: Doc, id?: string, title?: string): Doc; + export function MakeDelegate(doc: Opt, id?: string, title?: string): Opt; + export function MakeDelegate(doc: Opt, id?: string, title?: string): Opt { + if (doc) { + const delegate = new Doc(id, true); + delegate.proto = doc; + title && (delegate.title = title); + return delegate; + } + return undefined; + } + + let _applyCount: number = 0; + export function ApplyTemplate(templateDoc: Doc) { + if (templateDoc) { + const target = Doc.MakeDelegate(new Doc()); + const targetKey = StrCast(templateDoc.layoutKey, "layout"); + const applied = ApplyTemplateTo(templateDoc, target, targetKey, templateDoc.title + "(..." + _applyCount++ + ")"); + target.layoutKey = targetKey; + applied && (Doc.GetProto(applied).type = templateDoc.type); + return applied; + } + return undefined; + } + export function ApplyTemplateTo(templateDoc: Doc, target: Doc, targetKey: string, titleTarget: string | undefined) { + if (!Doc.AreProtosEqual(target[targetKey] as Doc, templateDoc)) { + if (target.resolvedDataDoc) { + target[targetKey] = new PrefetchProxy(templateDoc); + } else { + titleTarget && (Doc.GetProto(target).title = titleTarget); + Doc.GetProto(target)[targetKey] = new PrefetchProxy(templateDoc); + } + } + return target; + } + + // + // This function converts a generic field layout display into a field layout that displays a specific + // metadata field indicated by the title of the template field (not the default field that it was rendering) + // + export function MakeMetadataFieldTemplate(templateField: Doc, templateDoc: Opt): boolean { + + // find the metadata field key that this template field doc will display (indicated by its title) + const metadataFieldKey = StrCast(templateField.isTemplateForField) || StrCast(templateField.title).replace(/^-/, ""); + + // update the original template to mark it as a template + templateField.isTemplateForField = metadataFieldKey; + templateField.title = metadataFieldKey; + + const templateFieldValue = templateField[metadataFieldKey] || templateField[Doc.LayoutFieldKey(templateField)]; + const templateCaptionValue = templateField.caption; + // move any data that the template field had been rendering over to the template doc so that things will still be rendered + // when the template field is adjusted to point to the new metadatafield key. + // note 1: if the template field contained a list of documents, each of those documents will be converted to templates as well. + // note 2: this will not overwrite any field that already exists on the template doc at the field key + if (!templateDoc?.[metadataFieldKey] && templateFieldValue instanceof ObjectField) { + Cast(templateFieldValue, listSpec(Doc), [])?.map(d => d instanceof Doc && MakeMetadataFieldTemplate(d, templateDoc)); + (Doc.GetProto(templateField)[metadataFieldKey] = ObjectField.MakeCopy(templateFieldValue)); + } + // copy the textTemplates from 'this' (not 'self') because the layout contains the template info, not the original doc + if (templateCaptionValue instanceof RichTextField && !templateCaptionValue.Empty()) { + templateField["caption-textTemplate"] = ComputedField.MakeFunction(`copyField(this.caption)`); + } + if (templateFieldValue instanceof RichTextField && !templateFieldValue.Empty()) { + templateField[metadataFieldKey + "-textTemplate"] = ComputedField.MakeFunction(`copyField(this.${metadataFieldKey})`); + } + + // get the layout string that the template uses to specify its layout + const templateFieldLayoutString = StrCast(Doc.LayoutField(Doc.Layout(templateField))); + + // change it to render the target metadata field instead of what it was rendering before and assign it to the template field layout document. + Doc.Layout(templateField).layout = templateFieldLayoutString.replace(/fieldKey={'[^']*'}/, `fieldKey={'${metadataFieldKey}'}`); + + // assign the template field doc a delegate of any extension document that was previously used to render the template field (since extension doc's carry rendering informatino) + Doc.Layout(templateField)[metadataFieldKey + "_ext"] = Doc.MakeDelegate(templateField[templateFieldLayoutString?.split("'")[1] + "_ext"] as Doc); + + return true; + } + + export function overlapping(doc1: Doc, doc2: Doc, clusterDistance: number) { + const doc2Layout = Doc.Layout(doc2); + const doc1Layout = Doc.Layout(doc1); + const x2 = NumCast(doc2.x) - clusterDistance; + const y2 = NumCast(doc2.y) - clusterDistance; + const w2 = NumCast(doc2Layout._width) + clusterDistance; + const h2 = NumCast(doc2Layout._height) + clusterDistance; + const x = NumCast(doc1.x) - clusterDistance; + const y = NumCast(doc1.y) - clusterDistance; + const w = NumCast(doc1Layout._width) + clusterDistance; + const h = NumCast(doc1Layout._height) + clusterDistance; + return doc1.z === doc2.z && intersectRect({ left: x, top: y, width: w, height: h }, { left: x2, top: y2, width: w2, height: h2 }); + } + + export function isBrushedHighlightedDegree(doc: Doc) { + if (Doc.IsHighlighted(doc)) { + return 6; + } + else { + return Doc.IsBrushedDegree(doc); + } + } + + export class DocBrush { + BrushedDoc: ObservableMap = new ObservableMap(); + } + const brushManager = new DocBrush(); + + export class DocData { + @observable _user_doc: Doc = undefined!; + @observable _searchQuery: string = ""; + } + + // the document containing the view layout information - will be the Document itself unless the Document has + // a layout field or 'layout' is given. + export function Layout(doc: Doc, layout?: Doc): Doc { + const overrideLayout = layout && Cast(doc[`${StrCast(layout.isTemplateForField, "data")}-layout[` + layout[Id] + "]"], Doc, null); + return overrideLayout || doc[LayoutSym] || doc; + } + export function SetLayout(doc: Doc, layout: Doc | string) { doc[StrCast(doc.layoutKey, "layout")] = layout; } + export function LayoutField(doc: Doc) { return doc[StrCast(doc.layoutKey, "layout")]; } + export function LayoutFieldKey(doc: Doc): string { return StrCast(Doc.Layout(doc).layout).split("'")[1]; } + const manager = new DocData(); + export function SearchQuery(): string { return manager._searchQuery; } + export function SetSearchQuery(query: string) { runInAction(() => manager._searchQuery = query); } + export function UserDoc(): Doc { return manager._user_doc; } + export function SetUserDoc(doc: Doc) { manager._user_doc = doc; } + export function IsBrushed(doc: Doc) { + return computedFn(function IsBrushed(doc: Doc) { + return brushManager.BrushedDoc.has(doc) || brushManager.BrushedDoc.has(Doc.GetProto(doc)); + })(doc); + } + // don't bother memoizing (caching) the result if called from a non-reactive context. (plus this avoids a warning message) + export function IsBrushedDegreeUnmemoized(doc: Doc) { + return brushManager.BrushedDoc.has(doc) ? 2 : brushManager.BrushedDoc.has(Doc.GetProto(doc)) ? 1 : 0; + } + export function IsBrushedDegree(doc: Doc) { + return computedFn(function IsBrushDegree(doc: Doc) { + return Doc.IsBrushedDegreeUnmemoized(doc); + })(doc); + } + export function BrushDoc(doc: Doc) { + brushManager.BrushedDoc.set(doc, true); + brushManager.BrushedDoc.set(Doc.GetProto(doc), true); + return doc; + } + export function UnBrushDoc(doc: Doc) { + brushManager.BrushedDoc.delete(doc); + brushManager.BrushedDoc.delete(Doc.GetProto(doc)); + return doc; + } + + + export function LinkOtherAnchor(linkDoc: Doc, anchorDoc: Doc) { return Doc.AreProtosEqual(anchorDoc, Cast(linkDoc.anchor1, Doc) as Doc) ? Cast(linkDoc.anchor2, Doc) as Doc : Cast(linkDoc.anchor1, Doc) as Doc; } + export function LinkEndpoint(linkDoc: Doc, anchorDoc: Doc) { return Doc.AreProtosEqual(anchorDoc, Cast(linkDoc.anchor1, Doc) as Doc) ? "1" : "2"; } + + export function linkFollowUnhighlight() { + Doc.UnhighlightAll(); + document.removeEventListener("pointerdown", linkFollowUnhighlight); + } + + let _lastDate = 0; + export function linkFollowHighlight(destDoc: Doc, dataAndDisplayDocs = true) { + linkFollowUnhighlight(); + Doc.HighlightDoc(destDoc, dataAndDisplayDocs); + document.removeEventListener("pointerdown", linkFollowUnhighlight); + document.addEventListener("pointerdown", linkFollowUnhighlight); + const lastDate = _lastDate = Date.now(); + window.setTimeout(() => _lastDate === lastDate && linkFollowUnhighlight(), 5000); + } + + export class HighlightBrush { + @observable HighlightedDoc: Map = new Map(); + } + const highlightManager = new HighlightBrush(); + export function IsHighlighted(doc: Doc) { + return highlightManager.HighlightedDoc.get(doc) || highlightManager.HighlightedDoc.get(Doc.GetProto(doc)); + } + export function HighlightDoc(doc: Doc, dataAndDisplayDocs = true) { + runInAction(() => { + highlightManager.HighlightedDoc.set(doc, true); + dataAndDisplayDocs && highlightManager.HighlightedDoc.set(Doc.GetProto(doc), true); + }); + } + export function UnHighlightDoc(doc: Doc) { + runInAction(() => { + highlightManager.HighlightedDoc.set(doc, false); + highlightManager.HighlightedDoc.set(Doc.GetProto(doc), false); + }); + } + export function UnhighlightAll() { + const mapEntries = highlightManager.HighlightedDoc.keys(); + let docEntry: IteratorResult; + while (!(docEntry = mapEntries.next()).done) { + const targetDoc = docEntry.value; + targetDoc && Doc.UnHighlightDoc(targetDoc); + } + + } + export function UnBrushAllDocs() { + brushManager.BrushedDoc.clear(); + } + + export function getDocTemplate(doc?: Doc) { + return doc?.isTemplateDoc ? doc : + Cast(doc?.dragFactory, Doc, null)?.isTemplateDoc ? doc?.dragFactory : + Cast(doc?.layout, Doc, null)?.isTemplateDoc ? doc?.layout : undefined; + } + + export function matchFieldValue(doc: Doc, key: string, value: any): boolean { + const fieldVal = doc[key]; + if (Cast(fieldVal, listSpec("string"), []).length) { + const vals = Cast(fieldVal, listSpec("string"), []); + return vals.some(v => v === value); + } + const fieldStr = Field.toString(fieldVal as Field); + return fieldStr === value; + } + + export function deiconifyView(doc: any) { + StrCast(doc.layoutKey).split("_")[1] === "icon" && setNativeView(doc); + } + + export function setNativeView(doc: any) { + const prevLayout = StrCast(doc.layoutKey).split("_")[1]; + const deiconify = prevLayout === "icon" && StrCast(doc.deiconifyLayout) ? "layout_" + StrCast(doc.deiconifyLayout) : ""; + prevLayout === "icon" && (doc.deiconifyLayout = undefined); + doc.layoutKey = deiconify || "layout"; + } + export function setDocFilterRange(target: Doc, key: string, range?: number[]) { + const docRangeFilters = Cast(target._docRangeFilters, listSpec("string"), []); + for (let i = 0; i < docRangeFilters.length; i += 3) { + if (docRangeFilters[i] === key) { + docRangeFilters.splice(i, 3); + break; + } + } + if (range !== undefined) { + docRangeFilters.push(key); + docRangeFilters.push(range[0].toString()); + docRangeFilters.push(range[1].toString()); + target._docRangeFilters = new List(docRangeFilters); + } + } + + export function aliasDocs(field: any) { + return new List(field.map((d: any) => Doc.MakeAlias(d))); + } + + // filters document in a container collection: + // all documents with the specified value for the specified key are included/excluded + // based on the modifiers :"check", "x", undefined + export function setDocFilter(container: Doc, key: string, value: any, modifiers?: "check" | "x" | undefined) { + const docFilters = Cast(container._docFilters, listSpec("string"), []); + for (let i = 0; i < docFilters.length; i += 3) { + if (docFilters[i] === key && docFilters[i + 1] === value) { + docFilters.splice(i, 3); + break; + } + } + if (typeof modifiers === "string") { + docFilters.push(key); + docFilters.push(value); + docFilters.push(modifiers); + container._docFilters = new List(docFilters); + } + } + export function readDocRangeFilter(doc: Doc, key: string) { + const docRangeFilters = Cast(doc._docRangeFilters, listSpec("string"), []); + for (let i = 0; i < docRangeFilters.length; i += 3) { + if (docRangeFilters[i] === key) { + return [Number(docRangeFilters[i + 1]), Number(docRangeFilters[i + 2])]; + } + } + } + export function assignDocToField(doc: Doc, field: string, id: string) { + DocServer.GetRefField(id).then(layout => layout instanceof Doc && (doc[field] = layout)); + return id; + } + + export function toggleNativeDimensions(layoutDoc: Doc, contentScale: number, panelWidth: number, panelHeight: number) { + runInAction(() => { + if (layoutDoc._nativeWidth || layoutDoc._nativeHeight) { + layoutDoc.scale = NumCast(layoutDoc.scale, 1) * contentScale; + layoutDoc._nativeWidth = undefined; + layoutDoc._nativeHeight = undefined; + } + else { + layoutDoc._autoHeight = false; + if (!layoutDoc._nativeWidth) { + layoutDoc._nativeWidth = NumCast(layoutDoc._width, panelWidth); + layoutDoc._nativeHeight = NumCast(layoutDoc._height, panelHeight); + } + } + }); + } + + export function isDocPinned(doc: Doc) { + //add this new doc to props.Document + const curPres = Cast(Doc.UserDoc().activePresentation, Doc) as Doc; + if (curPres) { + return DocListCast(curPres.data).findIndex((val) => Doc.AreProtosEqual(val, doc)) !== -1; + } + return false; + } + + // 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, options: DocumentOptions, id?: string) => Doc>, templateSignature: string = "custom", docLayoutTemplate?: Doc) { + const batch = UndoManager.StartBatch("makeCustomViewClicked"); + runInAction(() => { + doc.layoutKey = "layout_" + templateSignature; + if (doc[doc.layoutKey] === undefined) { + createCustomView(doc, creator, templateSignature, docLayoutTemplate); + } + }); + batch.end(); + } + export function findTemplate(templateName: string, type: string, signature: string) { + let docLayoutTemplate: Opt; + const iconViews = DocListCast(Cast(Doc.UserDoc()["template-icons"], Doc, null)?.data); + const templBtns = DocListCast(Cast(Doc.UserDoc()["template-buttons"], Doc, null)?.data); + const noteTypes = DocListCast(Cast(Doc.UserDoc()["template-notes"], Doc, null)?.data); + const clickFuncs = DocListCast(Cast(Doc.UserDoc().clickFuncs, Doc, null)?.data); + const allTemplates = iconViews.concat(templBtns).concat(noteTypes).concat(clickFuncs).map(btnDoc => (btnDoc.dragFactory as Doc) || btnDoc).filter(doc => doc.isTemplateDoc); + // bcz: this is hacky -- want to have different templates be applied depending on the "type" of a document. but type is not reliable and there could be other types of template searches so this should be generalized + // first try to find a template that matches the specific document type (_). otherwise, fallback to a general match on + !docLayoutTemplate && allTemplates.forEach(tempDoc => StrCast(tempDoc.title) === templateName + "_" + type && (docLayoutTemplate = tempDoc)); + !docLayoutTemplate && allTemplates.forEach(tempDoc => StrCast(tempDoc.title) === templateName && (docLayoutTemplate = tempDoc)); + return docLayoutTemplate; + } + export function createCustomView(doc: Doc, creator: Opt<(documents: Array, options: DocumentOptions, id?: string) => Doc>, templateSignature: string = "custom", docLayoutTemplate?: Doc) { + const templateName = templateSignature.replace(/\(.*\)/, ""); + docLayoutTemplate = docLayoutTemplate || findTemplate(templateName, StrCast(doc.type), templateSignature); + + const customName = "layout_" + templateSignature; + const _width = NumCast(doc._width); + const _height = NumCast(doc._height); + const options = { title: "data", backgroundColor: StrCast(doc.backgroundColor), _autoHeight: true, _width, x: -_width / 2, y: - _height / 2, _showSidebar: false }; + + let fieldTemplate: Opt; + if (doc.data instanceof RichTextField || typeof (doc.data) === "string") { + fieldTemplate = Docs.Create.TextDocument("", options); + } else if (doc.data instanceof PdfField) { + fieldTemplate = Docs.Create.PdfDocument("http://www.msn.com", options); + } else if (doc.data instanceof VideoField) { + fieldTemplate = Docs.Create.VideoDocument("http://www.cs.brown.edu", options); + } else if (doc.data instanceof AudioField) { + fieldTemplate = Docs.Create.AudioDocument("http://www.cs.brown.edu", options); + } else if (doc.data instanceof ImageField) { + fieldTemplate = Docs.Create.ImageDocument("http://www.cs.brown.edu", options); + } + const docTemplate = docLayoutTemplate || creator?.(fieldTemplate ? [fieldTemplate] : [], { title: customName + "(" + doc.title + ")", isTemplateDoc: true, _width: _width + 20, _height: Math.max(100, _height + 45) }); + + fieldTemplate && Doc.MakeMetadataFieldTemplate(fieldTemplate, docTemplate ? Doc.GetProto(docTemplate) : docTemplate); + docTemplate && Doc.ApplyTemplateTo(docTemplate, doc, customName, undefined); + } + export function makeCustomView(doc: Doc, custom: boolean, layout: string) { + Doc.setNativeView(doc); + if (custom) { + makeCustomViewClicked(doc, Docs.Create.StackingDocument, layout, undefined); + } + } + export function iconify(doc: Doc) { + const layoutKey = Cast(doc.layoutKey, "string", null); + Doc.makeCustomViewClicked(doc, Docs.Create.StackingDocument, "icon", undefined); + if (layoutKey && layoutKey !== "layout" && layoutKey !== "layout_icon") doc.deiconifyLayout = layoutKey.replace("layout_", ""); + } + + export function pileup(selected: Doc[], x: number, y: number) { + const newCollection = Docs.Create.PileDocument(selected, { title: "pileup", x: x - 55, y: y - 55, _width: 110, _height: 100, _LODdisable: true }); + let w = 0, h = 0; + selected.forEach((d, i) => { + Doc.iconify(d); + w = Math.max(d[WidthSym](), w); + h = Math.max(d[HeightSym](), h); + }); + h = Math.max(h, w * 4 / 3); // converting to an icon does not update the height right away. so this is a fallback hack to try to do something reasonable + selected.forEach((d, i) => { + d.x = Math.cos(Math.PI * 2 * i / selected.length) * 10 - w / 2; + d.y = Math.sin(Math.PI * 2 * i / selected.length) * 10 - h / 2; + d.displayTimecode = undefined; // bcz: this should be automatic somehow.. along with any other properties that were logically associated with the original collection + }); + newCollection.x = NumCast(newCollection.x) + NumCast(newCollection._width) / 2 - 55; + newCollection.y = NumCast(newCollection.y) + NumCast(newCollection._height) / 2 - 55; + newCollection._width = newCollection._height = 110; + //newCollection.borderRounding = "40px"; + newCollection._jitterRotation = 10; + newCollection._backgroundColor = "gray"; + newCollection._overflow = "visible"; + return newCollection; + } + + + export async function addFieldEnumerations(doc: Opt, enumeratedFieldKey: string, enumerations: { title: string, _backgroundColor?: string, color?: string }[]) { + let optionsCollection = await DocServer.GetRefField(enumeratedFieldKey); + if (!(optionsCollection instanceof Doc)) { + optionsCollection = Docs.Create.StackingDocument([], { title: `${enumeratedFieldKey} field set` }, enumeratedFieldKey); + Doc.AddDocToList((Doc.UserDoc().fieldTypes as Doc), "data", optionsCollection as Doc); + } + const options = optionsCollection as Doc; + const targetDoc = doc && Doc.GetProto(Cast(doc.rootDocument, Doc, null) || doc); + const docFind = `options.data.find(doc => doc.title === (this.rootDocument||this)["${enumeratedFieldKey}"])?`; + targetDoc && (targetDoc.backgroundColor = ComputedField.MakeFunction(docFind + `._backgroundColor || "white"`, undefined, { options })); + targetDoc && (targetDoc.color = ComputedField.MakeFunction(docFind + `.color || "black"`, undefined, { options })); + targetDoc && (targetDoc.borderRounding = ComputedField.MakeFunction(docFind + `.borderRounding`, undefined, { options })); + enumerations.map(enumeration => { + const found = DocListCast(options.data).find(d => d.title === enumeration.title); + if (found) { + found._backgroundColor = enumeration._backgroundColor || found._backgroundColor; + found._color = enumeration.color || found._color; + } else { + Doc.AddDocToList(options, "data", Docs.Create.TextDocument(enumeration.title, enumeration)); + } + }); + return optionsCollection; + } +} + +Scripting.addGlobal(function renameAlias(doc: any, n: any) { return StrCast(Doc.GetProto(doc).title).replace(/\([0-9]*\)/, "") + `(${n})`; }); +Scripting.addGlobal(function getProto(doc: any) { return Doc.GetProto(doc); }); +Scripting.addGlobal(function getDocTemplate(doc?: any) { return Doc.getDocTemplate(doc); }); +Scripting.addGlobal(function getAlias(doc: any) { return Doc.MakeAlias(doc); }); +Scripting.addGlobal(function getCopy(doc: any, copyProto: any) { return doc.isTemplateDoc ? Doc.ApplyTemplate(doc) : Doc.MakeCopy(doc, copyProto); }); +Scripting.addGlobal(function copyField(field: any) { return ObjectField.MakeCopy(field); }); +Scripting.addGlobal(function aliasDocs(field: any) { return Doc.aliasDocs(field); }); +Scripting.addGlobal(function docList(field: any) { return DocListCast(field); }); +Scripting.addGlobal(function setInPlace(doc: any, field: any, value: any) { return Doc.SetInPlace(doc, field, value, false); }); +Scripting.addGlobal(function sameDocs(doc1: any, doc2: any) { return Doc.AreProtosEqual(doc1, doc2); }); +Scripting.addGlobal(function deiconifyView(doc: any) { Doc.deiconifyView(doc); }); +Scripting.addGlobal(function undo() { return UndoManager.Undo(); }); +Scripting.addGlobal(function redo() { return UndoManager.Redo(); }); +Scripting.addGlobal(function DOC(id: string) { console.log("Can't parse a document id in a script"); return "invalid"; }); +Scripting.addGlobal(function assignDoc(doc: Doc, field: string, id: string) { return Doc.assignDocToField(doc, field, id); }); +Scripting.addGlobal(function docCast(doc: FieldResult): any { return DocCastAsync(doc); }); +Scripting.addGlobal(function activePresentationItem() { + const curPres = Doc.UserDoc().activePresentation as Doc; + return curPres && DocListCast(curPres[Doc.LayoutFieldKey(curPres)])[NumCast(curPres._itemIndex)]; +}); +Scripting.addGlobal(function selectDoc(doc: any) { Doc.UserDoc().activeSelection = new List([doc]); }); +Scripting.addGlobal(function selectedDocs(container: Doc, excludeCollections: boolean, prevValue: any) { + const docs = DocListCast(Doc.UserDoc().activeSelection). + filter(d => !Doc.AreProtosEqual(d, container) && !d.annotationOn && d.type !== DocumentType.DOCHOLDER && d.type !== DocumentType.KVP && + (!excludeCollections || d.type !== DocumentType.COL || !Cast(d.data, listSpec(Doc), null))); + return docs.length ? new List(docs) : prevValue; +}); +Scripting.addGlobal(function setDocFilter(container: Doc, key: string, value: any, modifiers?: "check" | "x" | undefined) { Doc.setDocFilter(container, key, value, modifiers); }); +Scripting.addGlobal(function setDocFilterRange(container: Doc, key: string, range: number[]) { Doc.setDocFilterRange(container, key, range); }); \ No newline at end of file diff --git a/src/fields/FieldSymbols.ts b/src/fields/FieldSymbols.ts new file mode 100644 index 000000000..8d040f493 --- /dev/null +++ b/src/fields/FieldSymbols.ts @@ -0,0 +1,12 @@ + +export const Update = Symbol("Update"); +export const Self = Symbol("Self"); +export const SelfProxy = Symbol("SelfProxy"); +export const HandleUpdate = Symbol("HandleUpdate"); +export const Id = Symbol("Id"); +export const OnUpdate = Symbol("OnUpdate"); +export const Parent = Symbol("Parent"); +export const Copy = Symbol("Copy"); +export const ToScriptString = Symbol("ToScriptString"); +export const ToPlainText = Symbol("ToPlainText"); +export const ToString = Symbol("ToString"); diff --git a/src/fields/HtmlField.ts b/src/fields/HtmlField.ts new file mode 100644 index 000000000..6e8bba977 --- /dev/null +++ b/src/fields/HtmlField.ts @@ -0,0 +1,26 @@ +import { Deserializable } from "../client/util/SerializationHelper"; +import { serializable, primitive } from "serializr"; +import { ObjectField } from "./ObjectField"; +import { Copy, ToScriptString, ToString} from "./FieldSymbols"; + +@Deserializable("html") +export class HtmlField extends ObjectField { + @serializable(primitive()) + readonly html: string; + + constructor(html: string) { + super(); + this.html = html; + } + + [Copy]() { + return new HtmlField(this.html); + } + + [ToScriptString]() { + return "invalid"; + } + [ToString]() { + return this.html; + } +} diff --git a/src/fields/IconField.ts b/src/fields/IconField.ts new file mode 100644 index 000000000..76c4ddf1b --- /dev/null +++ b/src/fields/IconField.ts @@ -0,0 +1,26 @@ +import { Deserializable } from "../client/util/SerializationHelper"; +import { serializable, primitive } from "serializr"; +import { ObjectField } from "./ObjectField"; +import { Copy, ToScriptString, ToString } from "./FieldSymbols"; + +@Deserializable("icon") +export class IconField extends ObjectField { + @serializable(primitive()) + readonly icon: string; + + constructor(icon: string) { + super(); + this.icon = icon; + } + + [Copy]() { + return new IconField(this.icon); + } + + [ToScriptString]() { + return "invalid"; + } + [ToString]() { + return "ICONfield"; + } +} diff --git a/src/fields/InkField.ts b/src/fields/InkField.ts new file mode 100644 index 000000000..bb93de5ac --- /dev/null +++ b/src/fields/InkField.ts @@ -0,0 +1,50 @@ +import { Deserializable } from "../client/util/SerializationHelper"; +import { serializable, custom, createSimpleSchema, list, object, map } from "serializr"; +import { ObjectField } from "./ObjectField"; +import { Copy, ToScriptString, ToString } from "./FieldSymbols"; + +export enum InkTool { + None, + Pen, + Highlighter, + Eraser, + Stamp +} + +export interface PointData { + X: number; + Y: number; +} + +export type InkData = Array; + +const pointSchema = createSimpleSchema({ + X: true, Y: true +}); + +const strokeDataSchema = createSimpleSchema({ + pathData: list(object(pointSchema)), + "*": true +}); + +@Deserializable("ink") +export class InkField extends ObjectField { + @serializable(list(object(strokeDataSchema))) + readonly inkData: InkData; + + constructor(data: InkData) { + super(); + this.inkData = data; + } + + [Copy]() { + return new InkField(this.inkData); + } + + [ToScriptString]() { + return "invalid"; + } + [ToString]() { + return "InkField"; + } +} diff --git a/src/fields/List.ts b/src/fields/List.ts new file mode 100644 index 000000000..fdabea365 --- /dev/null +++ b/src/fields/List.ts @@ -0,0 +1,330 @@ +import { Deserializable, autoObject, afterDocDeserialize } from "../client/util/SerializationHelper"; +import { Field } from "./Doc"; +import { setter, getter, deleteProperty, updateFunction } from "./util"; +import { serializable, alias, list } from "serializr"; +import { observable, action, runInAction } from "mobx"; +import { ObjectField } from "./ObjectField"; +import { RefField } from "./RefField"; +import { ProxyField } from "./Proxy"; +import { Self, Update, Parent, OnUpdate, SelfProxy, ToScriptString, ToString, Copy, Id } from "./FieldSymbols"; +import { Scripting } from "../client/util/Scripting"; +import { DocServer } from "../client/DocServer"; + +const listHandlers: any = { + /// Mutator methods + copyWithin() { + throw new Error("copyWithin not supported yet"); + }, + fill(value: any, start?: number, end?: number) { + if (value instanceof RefField) { + throw new Error("fill with RefFields not supported yet"); + } + const res = this[Self].__fields.fill(value, start, end); + this[Update](); + return res; + }, + pop(): any { + const field = toRealField(this[Self].__fields.pop()); + this[Update](); + return field; + }, + push: action(function (this: any, ...items: any[]) { + items = items.map(toObjectField); + const list = this[Self]; + const length = list.__fields.length; + for (let i = 0; i < items.length; i++) { + const item = items[i]; + //TODO Error checking to make sure parent doesn't already exist + if (item instanceof ObjectField) { + item[Parent] = list; + item[OnUpdate] = updateFunction(list, i + length, item, this); + } + } + const res = list.__fields.push(...items); + this[Update](); + return res; + }), + reverse() { + const res = this[Self].__fields.reverse(); + this[Update](); + return res; + }, + shift() { + const res = toRealField(this[Self].__fields.shift()); + this[Update](); + return res; + }, + sort(cmpFunc: any) { + this[Self].__realFields(); // coerce retrieving entire array + const res = this[Self].__fields.sort(cmpFunc ? (first: any, second: any) => cmpFunc(toRealField(first), toRealField(second)) : undefined); + this[Update](); + return res; + }, + splice: action(function (this: any, start: number, deleteCount: number, ...items: any[]) { + this[Self].__realFields(); // coerce retrieving entire array + items = items.map(toObjectField); + const list = this[Self]; + for (let i = 0; i < items.length; i++) { + const item = items[i]; + //TODO Error checking to make sure parent doesn't already exist + //TODO Need to change indices of other fields in array + if (item instanceof ObjectField) { + item[Parent] = list; + item[OnUpdate] = updateFunction(list, i + start, item, this); + } + } + const res = list.__fields.splice(start, deleteCount, ...items); + this[Update](); + return res.map(toRealField); + }), + unshift(...items: any[]) { + items = items.map(toObjectField); + const list = this[Self]; + const length = list.__fields.length; + for (let i = 0; i < items.length; i++) { + const item = items[i]; + //TODO Error checking to make sure parent doesn't already exist + //TODO Need to change indices of other fields in array + if (item instanceof ObjectField) { + item[Parent] = list; + item[OnUpdate] = updateFunction(list, i, item, this); + } + } + const res = this[Self].__fields.unshift(...items); + this[Update](); + return res; + + }, + /// Accessor methods + concat: action(function (this: any, ...items: any[]) { + this[Self].__realFields(); + return this[Self].__fields.map(toRealField).concat(...items); + }), + includes(valueToFind: any, fromIndex: number) { + if (valueToFind instanceof RefField) { + return this[Self].__realFields().includes(valueToFind, fromIndex); + } else { + return this[Self].__fields.includes(valueToFind, fromIndex); + } + }, + indexOf(valueToFind: any, fromIndex: number) { + if (valueToFind instanceof RefField) { + return this[Self].__realFields().indexOf(valueToFind, fromIndex); + } else { + return this[Self].__fields.indexOf(valueToFind, fromIndex); + } + }, + join(separator: any) { + this[Self].__realFields(); + return this[Self].__fields.map(toRealField).join(separator); + }, + lastIndexOf(valueToFind: any, fromIndex: number) { + if (valueToFind instanceof RefField) { + return this[Self].__realFields().lastIndexOf(valueToFind, fromIndex); + } else { + return this[Self].__fields.lastIndexOf(valueToFind, fromIndex); + } + }, + slice(begin: number, end: number) { + this[Self].__realFields(); + return this[Self].__fields.slice(begin, end).map(toRealField); + }, + + /// Iteration methods + entries() { + return this[Self].__realFields().entries(); + }, + every(callback: any, thisArg: any) { + return this[Self].__realFields().every(callback, thisArg); + // TODO This is probably more efficient, but technically the callback can take the array, which would mean we would have to map the actual array anyway. + // If we don't want to support the array parameter, we should use this version instead + // return this[Self].__fields.every((element:any, index:number, array:any) => callback(toRealField(element), index, array), thisArg); + }, + filter(callback: any, thisArg: any) { + return this[Self].__realFields().filter(callback, thisArg); + // TODO This is probably more efficient, but technically the callback can take the array, which would mean we would have to map the actual array anyway. + // If we don't want to support the array parameter, we should use this version instead + // return this[Self].__fields.filter((element:any, index:number, array:any) => callback(toRealField(element), index, array), thisArg); + }, + find(callback: any, thisArg: any) { + return this[Self].__realFields().find(callback, thisArg); + // TODO This is probably more efficient, but technically the callback can take the array, which would mean we would have to map the actual array anyway. + // If we don't want to support the array parameter, we should use this version instead + // return this[Self].__fields.find((element:any, index:number, array:any) => callback(toRealField(element), index, array), thisArg); + }, + findIndex(callback: any, thisArg: any) { + return this[Self].__realFields().findIndex(callback, thisArg); + // TODO This is probably more efficient, but technically the callback can take the array, which would mean we would have to map the actual array anyway. + // If we don't want to support the array parameter, we should use this version instead + // return this[Self].__fields.findIndex((element:any, index:number, array:any) => callback(toRealField(element), index, array), thisArg); + }, + forEach(callback: any, thisArg: any) { + return this[Self].__realFields().forEach(callback, thisArg); + // TODO This is probably more efficient, but technically the callback can take the array, which would mean we would have to map the actual array anyway. + // If we don't want to support the array parameter, we should use this version instead + // return this[Self].__fields.forEach((element:any, index:number, array:any) => callback(toRealField(element), index, array), thisArg); + }, + map(callback: any, thisArg: any) { + return this[Self].__realFields().map(callback, thisArg); + // TODO This is probably more efficient, but technically the callback can take the array, which would mean we would have to map the actual array anyway. + // If we don't want to support the array parameter, we should use this version instead + // return this[Self].__fields.map((element:any, index:number, array:any) => callback(toRealField(element), index, array), thisArg); + }, + reduce(callback: any, initialValue: any) { + return this[Self].__realFields().reduce(callback, initialValue); + // TODO This is probably more efficient, but technically the callback can take the array, which would mean we would have to map the actual array anyway. + // If we don't want to support the array parameter, we should use this version instead + // return this[Self].__fields.reduce((acc:any, element:any, index:number, array:any) => callback(acc, toRealField(element), index, array), initialValue); + }, + reduceRight(callback: any, initialValue: any) { + return this[Self].__realFields().reduceRight(callback, initialValue); + // TODO This is probably more efficient, but technically the callback can take the array, which would mean we would have to map the actual array anyway. + // If we don't want to support the array parameter, we should use this version instead + // return this[Self].__fields.reduceRight((acc:any, element:any, index:number, array:any) => callback(acc, toRealField(element), index, array), initialValue); + }, + some(callback: any, thisArg: any) { + return this[Self].__realFields().some(callback, thisArg); + // TODO This is probably more efficient, but technically the callback can take the array, which would mean we would have to map the actual array anyway. + // If we don't want to support the array parameter, we should use this version instead + // return this[Self].__fields.some((element:any, index:number, array:any) => callback(toRealField(element), index, array), thisArg); + }, + values() { + return this[Self].__realFields().values(); + }, + [Symbol.iterator]() { + return this[Self].__realFields().values(); + } +}; + +function toObjectField(field: Field) { + return field instanceof RefField ? new ProxyField(field) : field; +} + +function toRealField(field: Field) { + return field instanceof ProxyField ? field.value() : field; +} + +function listGetter(target: any, prop: string | number | symbol, receiver: any): any { + if (listHandlers.hasOwnProperty(prop)) { + return listHandlers[prop]; + } + return getter(target, prop, receiver); +} + +interface ListSpliceUpdate { + type: "splice"; + index: number; + added: T[]; + removedCount: number; +} + +interface ListIndexUpdate { + type: "update"; + index: number; + newValue: T; +} + +type ListUpdate = ListSpliceUpdate | ListIndexUpdate; + +type StoredType = T extends RefField ? ProxyField : T; + +@Deserializable("list") +class ListImpl extends ObjectField { + constructor(fields?: T[]) { + super(); + const list = new Proxy(this, { + set: setter, + get: listGetter, + ownKeys: target => Object.keys(target.__fields), + getOwnPropertyDescriptor: (target, prop) => { + if (prop in target.__fields) { + return { + configurable: true,//TODO Should configurable be true? + enumerable: true, + }; + } + return Reflect.getOwnPropertyDescriptor(target, prop); + }, + deleteProperty: deleteProperty, + defineProperty: () => { throw new Error("Currently properties can't be defined on documents using Object.defineProperty"); }, + }); + this[SelfProxy] = list; + if (fields) { + (list as any).push(...fields); + } + return list; + } + + [key: number]: T | (T extends RefField ? Promise : never); + + // this requests all ProxyFields at the same time to avoid the overhead + // of separate network requests and separate updates to the React dom. + private __realFields() { + const waiting = this.__fields.filter(f => f instanceof ProxyField && f.promisedValue()); + const promised = waiting.map(f => f instanceof ProxyField ? f.promisedValue() : ""); + // if we find any ProxyFields that don't have a current value, then + // start the server request for all of them + if (promised.length) { + const promise = DocServer.GetRefFields(promised); + // as soon as we get the fields from the server, set all the list values in one + // action to generate one React dom update. + promise.then(fields => runInAction(() => { + waiting.map((w, i) => w instanceof ProxyField && w.setValue(fields[promised[i]])); + })); + // we also have to mark all lists items with this promise so that any calls to them + // will await the batch request. + // This counts on the handler for 'promise' in the call above being invoked before the + // handler for 'promise' in the lines below. + waiting.map((w, i) => { + w instanceof ProxyField && w.setPromise(promise.then(fields => fields[promised[i]])); + }); + } + return this.__fields.map(toRealField); + } + + @serializable(alias("fields", list(autoObject(), { afterDeserialize: afterDocDeserialize }))) + private get __fields() { + return this.___fields; + } + + private set __fields(value) { + this.___fields = value; + for (const key in value) { + const field = value[key]; + if (!(field instanceof ObjectField)) continue; + (field as ObjectField)[Parent] = this[Self]; + (field as ObjectField)[OnUpdate] = updateFunction(this[Self], key, field, this[SelfProxy]); + } + } + + [Copy]() { + const copiedData = this[Self].__fields.map(f => f instanceof ObjectField ? f[Copy]() : f); + const deepCopy = new ListImpl(copiedData as any); + return deepCopy; + } + + // @serializable(alias("fields", list(autoObject()))) + @observable + private ___fields: StoredType[] = []; + + private [Update] = (diff: any) => { + // console.log(diff); + const update = this[OnUpdate]; + // update && update(diff); + update?.(); + } + + private [Self] = this; + private [SelfProxy]: any; + + [ToScriptString]() { + return `new List([${(this as any).map((field: any) => Field.toScriptString(field))}])`; + } + [ToString]() { + return "List"; + } +} +export type List = ListImpl & (T | (T extends RefField ? Promise : never))[]; +export const List: { new (fields?: T[]): List } = ListImpl as any; + +Scripting.addGlobal("List", List); \ No newline at end of file diff --git a/src/fields/ListSpec.ts b/src/fields/ListSpec.ts new file mode 100644 index 000000000..e69de29bb diff --git a/src/fields/ObjectField.ts b/src/fields/ObjectField.ts new file mode 100644 index 000000000..9aa1c9b04 --- /dev/null +++ b/src/fields/ObjectField.ts @@ -0,0 +1,20 @@ +import { RefField } from "./RefField"; +import { OnUpdate, Parent, Copy, ToScriptString, ToString } from "./FieldSymbols"; +import { Scripting } from "../client/util/Scripting"; + +export abstract class ObjectField { + protected [OnUpdate](diff?: any) { } + private [Parent]?: RefField | ObjectField; + abstract [Copy](): ObjectField; + + abstract [ToScriptString](): string; + abstract [ToString](): string; +} + +export namespace ObjectField { + export function MakeCopy(field: T) { + return field?.[Copy](); + } +} + +Scripting.addGlobal(ObjectField); \ No newline at end of file diff --git a/src/fields/PresField.ts b/src/fields/PresField.ts new file mode 100644 index 000000000..f236a04fd --- /dev/null +++ b/src/fields/PresField.ts @@ -0,0 +1,6 @@ +//insert code here +import { ObjectField } from "./ObjectField"; + +export abstract class PresField extends ObjectField { + +} \ No newline at end of file diff --git a/src/fields/Proxy.ts b/src/fields/Proxy.ts new file mode 100644 index 000000000..555faaad0 --- /dev/null +++ b/src/fields/Proxy.ts @@ -0,0 +1,126 @@ +import { Deserializable } from "../client/util/SerializationHelper"; +import { FieldWaiting } from "./Doc"; +import { primitive, serializable } from "serializr"; +import { observable, action, runInAction } from "mobx"; +import { DocServer } from "../client/DocServer"; +import { RefField } from "./RefField"; +import { ObjectField } from "./ObjectField"; +import { Id, Copy, ToScriptString, ToString } from "./FieldSymbols"; +import { scriptingGlobal } from "../client/util/Scripting"; +import { Plugins } from "./util"; + +@Deserializable("proxy") +export class ProxyField extends ObjectField { + constructor(); + constructor(value: T); + constructor(fieldId: string); + constructor(value?: T | string) { + super(); + if (typeof value === "string") { + this.fieldId = value; + } else if (value) { + this.cache = value; + this.fieldId = value[Id]; + } + } + + [Copy]() { + if (this.cache) return new ProxyField(this.cache); + return new ProxyField(this.fieldId); + } + + [ToScriptString]() { + return "invalid"; + } + [ToString]() { + return "ProxyField"; + } + + @serializable(primitive()) + readonly fieldId: string = ""; + + // This getter/setter and nested object thing is + // because mobx doesn't play well with observable proxies + @observable.ref + private _cache: { readonly field: T | undefined } = { field: undefined }; + private get cache(): T | undefined { + return this._cache.field; + } + private set cache(field: T | undefined) { + this._cache = { field }; + } + + private failed = false; + private promise?: Promise; + + value(): T | undefined | FieldWaiting { + if (this.cache) { + return this.cache; + } + if (this.failed) { + return undefined; + } + if (!this.promise) { + const cached = DocServer.GetCachedRefField(this.fieldId); + if (cached !== undefined) { + runInAction(() => this.cache = cached as any); + return cached as any; + } + this.promise = DocServer.GetRefField(this.fieldId).then(action((field: any) => { + this.promise = undefined; + this.cache = field; + if (field === undefined) this.failed = true; + return field; + })); + } + return this.promise as any; + } + promisedValue(): string { return !this.cache && !this.failed && !this.promise ? this.fieldId : ""; } + setPromise(promise: any) { + this.promise = promise; + } + @action + setValue(field: any) { + this.promise = undefined; + this.cache = field; + if (field === undefined) this.failed = true; + return field; + } +} + +export namespace ProxyField { + let useProxy = true; + export function DisableProxyFields() { + useProxy = false; + } + + export function EnableProxyFields() { + useProxy = true; + } + + export function WithoutProxy(fn: () => T) { + DisableProxyFields(); + try { + return fn(); + } finally { + EnableProxyFields(); + } + } + + export function initPlugin() { + Plugins.addGetterPlugin((doc, _, value) => { + if (useProxy && value instanceof ProxyField) { + return { value: value.value() }; + } + }); + } +} + +function prefetchValue(proxy: PrefetchProxy) { + return proxy.value() as any; +} + +@scriptingGlobal +@Deserializable("prefetch_proxy", prefetchValue) +export class PrefetchProxy extends ProxyField { +} diff --git a/src/fields/RefField.ts b/src/fields/RefField.ts new file mode 100644 index 000000000..b6ef69750 --- /dev/null +++ b/src/fields/RefField.ts @@ -0,0 +1,21 @@ +import { serializable, primitive, alias } from "serializr"; +import { Utils } from "../Utils"; +import { Id, HandleUpdate, ToScriptString, ToString } from "./FieldSymbols"; +import { afterDocDeserialize } from "../client/util/SerializationHelper"; + +export type FieldId = string; +export abstract class RefField { + @serializable(alias("id", primitive({ afterDeserialize: afterDocDeserialize }))) + private __id: FieldId; + readonly [Id]: FieldId; + + constructor(id?: FieldId) { + this.__id = id || Utils.GenerateGuid(); + this[Id] = this.__id; + } + + protected [HandleUpdate]?(diff: any): void | Promise; + + abstract [ToScriptString](): string; + abstract [ToString](): string; +} diff --git a/src/fields/RichTextField.ts b/src/fields/RichTextField.ts new file mode 100644 index 000000000..5cf0e0cc3 --- /dev/null +++ b/src/fields/RichTextField.ts @@ -0,0 +1,41 @@ +import { ObjectField } from "./ObjectField"; +import { serializable } from "serializr"; +import { Deserializable } from "../client/util/SerializationHelper"; +import { Copy, ToScriptString, ToPlainText, ToString } from "./FieldSymbols"; +import { scriptingGlobal } from "../client/util/Scripting"; + +@scriptingGlobal +@Deserializable("RichTextField") +export class RichTextField extends ObjectField { + @serializable(true) + readonly Data: string; + + @serializable(true) + readonly Text: string; + + constructor(data: string, text: string = "") { + super(); + this.Data = data; + this.Text = text; + } + + Empty() { + return !(this.Text || this.Data.toString().includes("dashField")); + } + + [Copy]() { + return new RichTextField(this.Data, this.Text); + } + + [ToScriptString]() { + return `new RichTextField("${this.Data}", "${this.Text}")`; + } + [ToString]() { + return this.Text; + } + + public static DashField(fieldKey: string) { + return new RichTextField(`{"doc":{"type":"doc","content":[{"type":"paragraph","attrs":{"align":null,"color":null,"id":null,"indent":null,"inset":null,"lineSpacing":null,"paddingBottom":null,"paddingTop":null},"content":[{"type":"dashField","attrs":{"fieldKey":"${fieldKey}","docid":""}}]}]},"selection":{"type":"text","anchor":2,"head":2},"storedMarks":[]}`, ""); + } + +} \ No newline at end of file diff --git a/src/fields/RichTextUtils.ts b/src/fields/RichTextUtils.ts new file mode 100644 index 000000000..c475d0d73 --- /dev/null +++ b/src/fields/RichTextUtils.ts @@ -0,0 +1,519 @@ +import { AssertionError } from "assert"; +import { docs_v1 } from "googleapis"; +import { Fragment, Mark, Node } from "prosemirror-model"; +import { sinkListItem } from "prosemirror-schema-list"; +import { Utils } from "../Utils"; +import { Docs } from "../client/documents/Documents"; +import { schema } from "../client/views/nodes/formattedText/schema_rts"; +import { GooglePhotos } from "../client/apis/google_docs/GooglePhotosClientUtils"; +import { DocServer } from "../client/DocServer"; +import { Networking } from "../client/Network"; +import { FormattedTextBox } from "../client/views/nodes/formattedText/FormattedTextBox"; +import { Doc, Opt } from "./Doc"; +import { Id } from "./FieldSymbols"; +import { RichTextField } from "./RichTextField"; +import { Cast, StrCast } from "./Types"; +import Color = require('color'); +import { EditorState, TextSelection, Transaction } from "prosemirror-state"; +import { GoogleApiClientUtils } from "../client/apis/google_docs/GoogleApiClientUtils"; + +export namespace RichTextUtils { + + const delimiter = "\n"; + const joiner = ""; + + + export const Initialize = (initial?: string) => { + const content: any[] = []; + const state = { + doc: { + type: "doc", + content, + }, + selection: { + type: "text", + anchor: 0, + head: 0 + } + }; + if (initial && initial.length) { + content.push({ + type: "paragraph", + content: { + type: "text", + text: initial + } + }); + state.selection.anchor = state.selection.head = initial.length + 1; + } + return JSON.stringify(state); + }; + + export const Synthesize = (plainText: string, oldState?: RichTextField) => { + return new RichTextField(ToProsemirrorState(plainText, oldState), plainText); + }; + + export const ToPlainText = (state: EditorState) => { + // Because we're working with plain text, just concatenate all paragraphs + const content = state.doc.content; + const paragraphs: Node[] = []; + content.forEach(node => node.type.name === "paragraph" && paragraphs.push(node)); + + // Functions to flatten ProseMirror paragraph objects (and their components) to plain text + // Concatentate paragraphs and string the result together + const textParagraphs: string[] = paragraphs.map(paragraph => { + const text: string[] = []; + paragraph.content.forEach(node => node.text && text.push(node.text)); + return text.join(joiner) + delimiter; + }); + const plainText = textParagraphs.join(joiner); + return plainText.substring(0, plainText.length - 1); + }; + + export const ToProsemirrorState = (plainText: string, oldState?: RichTextField) => { + // Remap the text, creating blocks split on newlines + const elements = plainText.split(delimiter); + + // Google Docs adds in an extra carriage return automatically, so this counteracts it + !elements[elements.length - 1].length && elements.pop(); + + // Preserve the current state, but re-write the content to be the blocks + const parsed = JSON.parse(oldState ? oldState.Data : Initialize()); + parsed.doc.content = elements.map(text => { + const paragraph: any = { type: "paragraph" }; + text.length && (paragraph.content = [{ type: "text", marks: [], text }]); // An empty paragraph gets treated as a line break + return paragraph; + }); + + // If the new content is shorter than the previous content and selection is unchanged, may throw an out of bounds exception, so we reset it + parsed.selection = { type: "text", anchor: 1, head: 1 }; + + // Export the ProseMirror-compatible state object we've just built + return JSON.stringify(parsed); + }; + + export namespace GoogleDocs { + + export const Export = async (state: EditorState): Promise => { + const nodes: (Node | null)[] = []; + const text = ToPlainText(state); + state.doc.content.forEach(node => { + if (!node.childCount) { + nodes.push(null); + } else { + node.content.forEach(child => nodes.push(child)); + } + }); + const requests = await marksToStyle(nodes); + return { text, requests }; + }; + + interface ImageTemplate { + width: number; + title: string; + url: string; + agnostic: string; + } + + const parseInlineObjects = async (document: docs_v1.Schema$Document): Promise> => { + const inlineObjectMap = new Map(); + const inlineObjects = document.inlineObjects; + + if (inlineObjects) { + const objects = Object.keys(inlineObjects).map(objectId => inlineObjects[objectId]); + const mediaItems: MediaItem[] = objects.map(object => { + const embeddedObject = object.inlineObjectProperties!.embeddedObject!; + return { baseUrl: embeddedObject.imageProperties!.contentUri! }; + }); + + const uploads = await Networking.PostToServer("/googlePhotosMediaGet", { mediaItems }); + + if (uploads.length !== mediaItems.length) { + throw new AssertionError({ expected: mediaItems.length, actual: uploads.length, message: "Error with internally uploading inlineObjects!" }); + } + + for (let i = 0; i < objects.length; i++) { + const object = objects[i]; + const { accessPaths } = uploads[i]; + const { agnostic, _m } = accessPaths; + const embeddedObject = object.inlineObjectProperties!.embeddedObject!; + const size = embeddedObject.size!; + const width = size.width!.magnitude!; + + inlineObjectMap.set(object.objectId!, { + title: embeddedObject.title || `Imported Image from ${document.title}`, + width, + url: Utils.prepend(_m.client), + agnostic: Utils.prepend(agnostic.client) + }); + } + } + return inlineObjectMap; + }; + + type BulletPosition = { value: number, sinks: number }; + + interface MediaItem { + baseUrl: string; + } + + export const Import = async (documentId: GoogleApiClientUtils.Docs.DocumentId, textNote: Doc): Promise> => { + const document = await GoogleApiClientUtils.Docs.retrieve({ documentId }); + if (!document) { + return undefined; + } + const inlineObjectMap = await parseInlineObjects(document); + const title = document.title!; + const { text, paragraphs } = GoogleApiClientUtils.Docs.Utils.extractText(document); + let state = FormattedTextBox.blankState(); + const structured = parseLists(paragraphs); + + let position = 3; + const lists: ListGroup[] = []; + const indentMap = new Map(); + let globalOffset = 0; + const nodes: Node[] = []; + for (const element of structured) { + if (Array.isArray(element)) { + lists.push(element); + const positions: BulletPosition[] = []; + const items = element.map(paragraph => { + const item = listItem(state.schema, paragraph.contents); + const sinks = paragraph.bullet!; + positions.push({ + value: position + globalOffset, + sinks + }); + position += item.nodeSize; + globalOffset += 2 * sinks; + return item; + }); + indentMap.set(element, positions); + nodes.push(list(state.schema, items)); + } else { + if (element.contents.some(child => "inlineObjectId" in child)) { + const group = element.contents; + group.forEach((child, i) => { + let node: Opt>; + if ("inlineObjectId" in child) { + node = imageNode(state.schema, inlineObjectMap.get(child.inlineObjectId!)!, textNote); + } else if ("content" in child && (i !== group.length - 1 || child.content!.removeTrailingNewlines().length)) { + node = paragraphNode(state.schema, [child]); + } + if (node) { + position += node.nodeSize; + nodes.push(node); + } + }); + } else { + const paragraph = paragraphNode(state.schema, element.contents); + nodes.push(paragraph); + position += paragraph.nodeSize; + } + } + } + state = state.apply(state.tr.replaceWith(0, 2, nodes)); + + const sink = sinkListItem(state.schema.nodes.list_item); + const dispatcher = (tr: Transaction) => state = state.apply(tr); + for (const list of lists) { + for (const pos of indentMap.get(list)!) { + const resolved = state.doc.resolve(pos.value); + state = state.apply(state.tr.setSelection(new TextSelection(resolved))); + for (let i = 0; i < pos.sinks; i++) { + sink(state, dispatcher); + } + } + } + + return { title, text, state }; + }; + + type Paragraph = GoogleApiClientUtils.Docs.Utils.DeconstructedParagraph; + type ListGroup = Paragraph[]; + type PreparedParagraphs = (ListGroup | Paragraph)[]; + + const parseLists = (paragraphs: ListGroup) => { + const groups: PreparedParagraphs = []; + let group: ListGroup = []; + for (const paragraph of paragraphs) { + if (paragraph.bullet !== undefined) { + group.push(paragraph); + } else { + if (group.length) { + groups.push(group); + group = []; + } + groups.push(paragraph); + } + } + group.length && groups.push(group); + return groups; + }; + + const listItem = (schema: any, runs: docs_v1.Schema$TextRun[]): Node => { + return schema.node("list_item", null, paragraphNode(schema, runs)); + }; + + const list = (schema: any, items: Node[]): Node => { + return schema.node("bullet_list", null, items); + }; + + const paragraphNode = (schema: any, runs: docs_v1.Schema$TextRun[]): Node => { + const children = runs.map(run => textNode(schema, run)).filter(child => child !== undefined); + const fragment = children.length ? Fragment.from(children) : undefined; + return schema.node("paragraph", null, fragment); + }; + + const imageNode = (schema: any, image: ImageTemplate, textNote: Doc) => { + const { url: src, width, agnostic } = image; + let docid: string; + const guid = Utils.GenerateDeterministicGuid(agnostic); + const backingDocId = StrCast(textNote[guid]); + if (!backingDocId) { + const backingDoc = Docs.Create.ImageDocument(agnostic, { _width: 300, _height: 300 }); + Doc.makeCustomViewClicked(backingDoc, Docs.Create.FreeformDocument); + docid = backingDoc[Id]; + textNote[guid] = docid; + } else { + docid = backingDocId; + } + return schema.node("image", { src, agnostic, width, docid, float: null, location: "onRight" }); + }; + + const textNode = (schema: any, run: docs_v1.Schema$TextRun) => { + const text = run.content!.removeTrailingNewlines(); + return text.length ? schema.text(text, styleToMarks(schema, run.textStyle)) : undefined; + }; + + const StyleToMark = new Map([ + ["bold", "strong"], + ["italic", "em"], + ["foregroundColor", "pFontColor"], + ["fontSize", "pFontSize"] + ]); + + const styleToMarks = (schema: any, textStyle?: docs_v1.Schema$TextStyle) => { + if (!textStyle) { + return undefined; + } + const marks: Mark[] = []; + Object.keys(textStyle).forEach(key => { + let value: any; + const targeted = key as keyof docs_v1.Schema$TextStyle; + if (value = textStyle[targeted]) { + const attributes: any = {}; + let converted = StyleToMark.get(targeted) || targeted; + + value.url && (attributes.href = value.url); + if (value.color) { + const object = value.color.rgbColor; + attributes.color = Color.rgb(["red", "green", "blue"].map(color => object[color] * 255 || 0)).hex(); + } + if (value.magnitude) { + attributes.fontSize = value.magnitude; + } + + if (converted === "weightedFontFamily") { + converted = ImportFontFamilyMapping.get(value.fontFamily) || "timesNewRoman"; + } + + const mapped = schema.marks[converted]; + if (!mapped) { + alert(`No mapping found for ${converted}!`); + return; + } + + const mark = schema.mark(mapped, attributes); + mark && marks.push(mark); + } + }); + return marks; + }; + + const MarkToStyle = new Map([ + ["strong", "bold"], + ["em", "italic"], + ["pFontColor", "foregroundColor"], + ["pFontSize", "fontSize"], + ["timesNewRoman", "weightedFontFamily"], + ["georgia", "weightedFontFamily"], + ["comicSans", "weightedFontFamily"], + ["tahoma", "weightedFontFamily"], + ["impact", "weightedFontFamily"] + ]); + + const ExportFontFamilyMapping = new Map([ + ["timesNewRoman", "Times New Roman"], + ["arial", "Arial"], + ["georgia", "Georgia"], + ["comicSans", "Comic Sans MS"], + ["tahoma", "Tahoma"], + ["impact", "Impact"] + ]); + + const ImportFontFamilyMapping = new Map([ + ["Times New Roman", "timesNewRoman"], + ["Arial", "arial"], + ["Georgia", "georgia"], + ["Comic Sans MS", "comicSans"], + ["Tahoma", "tahoma"], + ["Impact", "impact"] + ]); + + const ignored = ["user_mark"]; + + const marksToStyle = async (nodes: (Node | null)[]): Promise => { + const requests: docs_v1.Schema$Request[] = []; + let position = 1; + for (const node of nodes) { + if (node === null) { + position += 2; + continue; + } + const { marks, attrs, nodeSize } = node; + const textStyle: docs_v1.Schema$TextStyle = {}; + const information: LinkInformation = { + startIndex: position, + endIndex: position + nodeSize, + textStyle + }; + let mark: Mark; + const markMap = BuildMarkMap(marks); + for (const markName of Object.keys(schema.marks)) { + if (ignored.includes(markName) || !(mark = markMap[markName])) { + continue; + } + let converted = MarkToStyle.get(markName) || markName as keyof docs_v1.Schema$TextStyle; + let value: any = true; + if (!converted) { + continue; + } + const { attrs } = mark; + switch (converted) { + case "link": + let url = attrs.href; + const delimiter = "/doc/"; + const alreadyShared = "?sharing=true"; + if (new RegExp(window.location.origin + delimiter).test(url) && !url.endsWith(alreadyShared)) { + const linkDoc = await DocServer.GetRefField(url.split(delimiter)[1]); + if (linkDoc instanceof Doc) { + let exported = (await Cast(linkDoc.anchor2, Doc))!; + if (!exported.customLayout) { + exported = Doc.MakeAlias(exported); + Doc.makeCustomViewClicked(exported, Docs.Create.FreeformDocument); + linkDoc.anchor2 = exported; + } + url = Utils.shareUrl(exported[Id]); + } + } + value = { url }; + textStyle.foregroundColor = fromRgb.blue; + textStyle.bold = true; + break; + case "fontSize": + value = { magnitude: attrs.fontSize, unit: "PT" }; + break; + case "foregroundColor": + value = fromHex(attrs.color); + break; + case "weightedFontFamily": + value = { fontFamily: ExportFontFamilyMapping.get(markName) }; + } + let matches: RegExpExecArray | null; + if ((matches = /p(\d+)/g.exec(markName)) !== null) { + converted = "fontSize"; + value = { magnitude: parseInt(matches[1].replace("px", "")), unit: "PT" }; + } + textStyle[converted] = value; + } + if (Object.keys(textStyle).length) { + requests.push(EncodeStyleUpdate(information)); + } + if (node.type.name === "image") { + const width = attrs.width; + requests.push(await EncodeImage({ + startIndex: position + nodeSize - 1, + uri: attrs.agnostic, + width: Number(typeof width === "string" ? width.replace("px", "") : width) + })); + } + position += nodeSize; + } + return requests; + }; + + const BuildMarkMap = (marks: Mark[]) => { + const markMap: { [type: string]: Mark } = {}; + marks.forEach(mark => markMap[mark.type.name] = mark); + return markMap; + }; + + interface LinkInformation { + startIndex: number; + endIndex: number; + textStyle: docs_v1.Schema$TextStyle; + } + + interface ImageInformation { + startIndex: number; + width: number; + uri: string; + } + + namespace fromRgb { + + export const convert = (red: number, green: number, blue: number): docs_v1.Schema$OptionalColor => { + return { + color: { + rgbColor: { + red: red / 255, + green: green / 255, + blue: blue / 255 + } + } + }; + }; + + export const red = convert(255, 0, 0); + export const green = convert(0, 255, 0); + export const blue = convert(0, 0, 255); + + } + + const fromHex = (color: string): docs_v1.Schema$OptionalColor => { + const c = Color(color); + return fromRgb.convert(c.red(), c.green(), c.blue()); + }; + + const EncodeStyleUpdate = (information: LinkInformation): docs_v1.Schema$Request => { + const { startIndex, endIndex, textStyle } = information; + return { + updateTextStyle: { + fields: "*", + range: { startIndex, endIndex }, + textStyle + } as docs_v1.Schema$UpdateTextStyleRequest + }; + }; + + const EncodeImage = async ({ uri, width, startIndex }: ImageInformation) => { + if (!uri) { + return {}; + } + const source = [Docs.Create.ImageDocument(uri)]; + const baseUrls = await GooglePhotos.Transactions.UploadThenFetch(source); + if (baseUrls) { + return { + insertInlineImage: { + uri: baseUrls[0], + objectSize: { width: { magnitude: width, unit: "PT" } }, + location: { index: startIndex } + } + }; + } + return {}; + }; + } + +} \ No newline at end of file diff --git a/src/fields/Schema.ts b/src/fields/Schema.ts new file mode 100644 index 000000000..72bce283d --- /dev/null +++ b/src/fields/Schema.ts @@ -0,0 +1,120 @@ +import { Interface, ToInterface, Cast, ToConstructor, HasTail, Head, Tail, ListSpec, ToType, DefaultFieldConstructor } from "./Types"; +import { Doc, Field } from "./Doc"; +import { ObjectField } from "./ObjectField"; +import { RefField } from "./RefField"; +import { SelfProxy } from "./FieldSymbols"; + +type AllToInterface = { + 1: ToInterface> & AllToInterface>, + 0: ToInterface> +}[HasTail extends true ? 1 : 0]; + +export const emptySchema = createSchema({}); +export const Document = makeInterface(emptySchema); +export type Document = makeInterface<[typeof emptySchema]>; + +export interface InterfaceFunc { + (docs: Doc[]): makeInterface[]; + (): makeInterface; + (doc: Doc): makeInterface; +} + +export type makeInterface = AllToInterface & Doc & { proto: Doc | undefined }; +// export function makeInterface(schemas: T): (doc: U) => All; +// export function makeInterface(schema: T): (doc: U) => makeInterface; +export function makeInterface(...schemas: T): InterfaceFunc { + const schema: Interface = {}; + for (const s of schemas) { + for (const key in s) { + schema[key] = s[key]; + } + } + const proto = new Proxy({}, { + get(target: any, prop, receiver) { + const field = receiver.doc[prop]; + if (prop in schema) { + const desc = prop === "proto" ? Doc : (schema as any)[prop]; // bcz: proto doesn't appear in schemas ... maybe it should? + if (typeof desc === "object" && "defaultVal" in desc && "type" in desc) {//defaultSpec + return Cast(field, desc.type, desc.defaultVal); + } else if (typeof desc === "function" && !ObjectField.isPrototypeOf(desc) && !RefField.isPrototypeOf(desc)) { + const doc = Cast(field, Doc); + if (doc === undefined) { + return undefined; + } else if (doc instanceof Doc) { + return desc(doc); + } else { + return doc.then(doc => doc && desc(doc)); + } + } else { + return Cast(field, desc); + } + } + return field; + }, + set(target: any, prop, value, receiver) { + receiver.doc[prop] = value; + return true; + } + }); + const fn = (doc: Doc) => { + doc = doc[SelfProxy]; + // if (!(doc instanceof Doc)) { + // throw new Error("Currently wrapping a schema in another schema isn't supported"); + // } + const obj = Object.create(proto, { doc: { value: doc, writable: false } }); + return obj; + }; + return function (doc?: Doc | Doc[]) { + doc = doc || new Doc; + if (doc instanceof Doc) { + return fn(doc); + } else { + return doc.map(fn); + } + }; +} + +export type makeStrictInterface = Partial>; +export function makeStrictInterface(schema: T): (doc: Doc) => makeStrictInterface { + const proto = {}; + for (const key in schema) { + const type = schema[key]; + Object.defineProperty(proto, key, { + get() { + return Cast(this.__doc[key], type as any); + }, + set(value) { + value = Cast(value, type as any); + if (value !== undefined) { + this.__doc[key] = value; + return; + } + throw new TypeError("Expected type " + type); + } + }); + } + return function (doc: any) { + if (!(doc instanceof Doc)) { + throw new Error("Currently wrapping a schema in another schema isn't supported"); + } + const obj = Object.create(proto); + obj.__doc = doc; + return obj; + }; +} + +export function createSchema(schema: T): T & { proto: ToConstructor } { + (schema as any).proto = Doc; + return schema as any; +} + +export function listSpec>(type: U): ListSpec> { + return { List: type as any };//TODO Types +} + +export function defaultSpec>(type: T, defaultVal: ToType): DefaultFieldConstructor> { + return { + type: type as any, + defaultVal + }; +} \ No newline at end of file diff --git a/src/fields/SchemaHeaderField.ts b/src/fields/SchemaHeaderField.ts new file mode 100644 index 000000000..07c90f5a2 --- /dev/null +++ b/src/fields/SchemaHeaderField.ts @@ -0,0 +1,122 @@ +import { Deserializable } from "../client/util/SerializationHelper"; +import { serializable, primitive } from "serializr"; +import { ObjectField } from "./ObjectField"; +import { Copy, ToScriptString, ToString, OnUpdate } from "./FieldSymbols"; +import { scriptingGlobal } from "../client/util/Scripting"; +import { ColumnType } from "../client/views/collections/CollectionSchemaView"; + +export const PastelSchemaPalette = new Map([ + // ["pink1", "#FFB4E8"], + ["pink2", "#ff9cee"], + ["pink3", "#ffccf9"], + ["pink4", "#fcc2ff"], + ["pink5", "#f6a6ff"], + ["purple1", "#b28dff"], + ["purple2", "#c5a3ff"], + ["purple3", "#d5aaff"], + ["purple4", "#ecd4ff"], + // ["purple5", "#fb34ff"], + ["purple6", "#dcd3ff"], + ["purple7", "#a79aff"], + ["purple8", "#b5b9ff"], + ["purple9", "#97a2ff"], + ["bluegreen1", "#afcbff"], + ["bluegreen2", "#aff8db"], + ["bluegreen3", "#c4faf8"], + ["bluegreen4", "#85e3ff"], + ["bluegreen5", "#ace7ff"], + // ["bluegreen6", "#6eb5ff"], + ["bluegreen7", "#bffcc6"], + ["bluegreen8", "#dbffd6"], + ["yellow1", "#f3ffe3"], + ["yellow2", "#e7ffac"], + ["yellow3", "#ffffd1"], + ["yellow4", "#fff5ba"], + // ["red1", "#ffc9de"], + ["red2", "#ffabab"], + ["red3", "#ffbebc"], + ["red4", "#ffcbc1"], + ["orange1", "#ffd5b3"], +]); + +export const RandomPastel = () => Array.from(PastelSchemaPalette.values())[Math.floor(Math.random() * PastelSchemaPalette.size)]; + +export const DarkPastelSchemaPalette = new Map([ + ["pink2", "#c932b0"], + ["purple4", "#913ad6"], + ["bluegreen1", "#3978ed"], + ["bluegreen7", "#2adb3e"], + ["bluegreen5", "#21b0eb"], + ["yellow4", "#edcc0c"], + ["red2", "#eb3636"], + ["orange1", "#f2740f"], +]); + +@scriptingGlobal +@Deserializable("schemaheader") +export class SchemaHeaderField extends ObjectField { + @serializable(primitive()) + heading: string; + @serializable(primitive()) + color: string; + @serializable(primitive()) + type: number; + @serializable(primitive()) + width: number; + @serializable(primitive()) + collapsed: boolean | undefined; + @serializable(primitive()) + desc: boolean | undefined; // boolean determines sort order, undefined when no sort + + constructor(heading: string = "", color: string = RandomPastel(), type?: ColumnType, width?: number, desc?: boolean, collapsed?: boolean) { + super(); + + this.heading = heading; + this.color = color; + this.type = type ? type : 0; + this.width = width ? width : -1; + this.desc = desc; + this.collapsed = collapsed; + } + + setHeading(heading: string) { + this.heading = heading; + this[OnUpdate](); + } + + setColor(color: string) { + this.color = color; + this[OnUpdate](); + } + + setType(type: ColumnType) { + this.type = type; + this[OnUpdate](); + } + + setWidth(width: number) { + this.width = width; + this[OnUpdate](); + } + + setDesc(desc: boolean | undefined) { + this.desc = desc; + this[OnUpdate](); + } + + setCollapsed(collapsed: boolean | undefined) { + this.collapsed = collapsed; + this[OnUpdate](); + } + + [Copy]() { + return new SchemaHeaderField(this.heading, this.color, this.type); + } + + [ToScriptString]() { + return `invalid`; + } + [ToString]() { + return `SchemaHeaderField`; + } +} \ No newline at end of file diff --git a/src/fields/ScriptField.ts b/src/fields/ScriptField.ts new file mode 100644 index 000000000..f05f431ac --- /dev/null +++ b/src/fields/ScriptField.ts @@ -0,0 +1,193 @@ +import { ObjectField } from "./ObjectField"; +import { CompiledScript, CompileScript, scriptingGlobal, ScriptOptions, CompileError, CompileResult } from "../client/util/Scripting"; +import { Copy, ToScriptString, ToString, Parent, SelfProxy } from "./FieldSymbols"; +import { serializable, createSimpleSchema, map, primitive, object, deserialize, PropSchema, custom, SKIP } from "serializr"; +import { Deserializable, autoObject } from "../client/util/SerializationHelper"; +import { Doc, Field } from "./Doc"; +import { Plugins, setter } from "./util"; +import { computedFn } from "mobx-utils"; +import { ProxyField } from "./Proxy"; +import { Cast } from "./Types"; + +function optional(propSchema: PropSchema) { + return custom(value => { + if (value !== undefined) { + return propSchema.serializer(value); + } + return SKIP; + }, (jsonValue: any, context: any, oldValue: any, callback: (err: any, result: any) => void) => { + if (jsonValue !== undefined) { + return propSchema.deserializer(jsonValue, callback, context, oldValue); + } + return SKIP; + }); +} + +const optionsSchema = createSimpleSchema({ + requiredType: true, + addReturn: true, + typecheck: true, + editable: true, + readonly: true, + params: optional(map(primitive())) +}); + +const scriptSchema = createSimpleSchema({ + options: object(optionsSchema), + originalScript: true +}); + +async function deserializeScript(script: ScriptField) { + const captures: ProxyField = (script as any).captures; + if (captures) { + const doc = (await captures.value())!; + const captured: any = {}; + const keys = Object.keys(doc); + const vals = await Promise.all(keys.map(key => doc[key]) as any); + keys.forEach((key, i) => captured[key] = vals[i]); + (script.script.options as any).capturedVariables = captured; + } + const comp = CompileScript(script.script.originalScript, script.script.options); + if (!comp.compiled) { + throw new Error("Couldn't compile loaded script"); + } + (script as any).script = comp; +} + +@scriptingGlobal +@Deserializable("script", deserializeScript) +export class ScriptField extends ObjectField { + @serializable(object(scriptSchema)) + readonly script: CompiledScript; + @serializable(object(scriptSchema)) + readonly setterscript: CompiledScript | undefined; + + @serializable(autoObject()) + private captures?: ProxyField; + + constructor(script: CompiledScript, setterscript?: CompileResult) { + super(); + + if (script?.options.capturedVariables) { + const doc = Doc.assign(new Doc, script.options.capturedVariables); + this.captures = new ProxyField(doc); + } + this.setterscript = setterscript?.compiled ? setterscript : undefined; + this.script = script; + } + + // init(callback: (res: Field) => any) { + // const options = this.options!; + // const keys = Object.keys(options.options.capturedIds); + // Server.GetFields(keys).then(fields => { + // let captured: { [name: string]: Field } = {}; + // keys.forEach(key => captured[options.options.capturedIds[key]] = fields[key]); + // const opts: ScriptOptions = { + // addReturn: options.options.addReturn, + // params: options.options.params, + // requiredType: options.options.requiredType, + // capturedVariables: captured + // }; + // const script = CompileScript(options.script, opts); + // if (!script.compiled) { + // throw new Error("Can't compile script"); + // } + // this._script = script; + // callback(this); + // }); + // } + + [Copy](): ObjectField { + return new ScriptField(this.script); + } + toString() { + return `${this.script.originalScript}`; + } + + [ToScriptString]() { + return "script field"; + } + [ToString]() { + return this.script.originalScript; + } + public static CompileScript(script: string, params: object = {}, addReturn = false, capturedVariables?: { [name: string]: Field }) { + const compiled = CompileScript(script, { + params: { this: Doc.name, self: Doc.name, _last_: "any", ...params }, + typecheck: false, + editable: true, + addReturn: addReturn, + capturedVariables + }); + return compiled; + } + public static MakeFunction(script: string, params: object = {}, capturedVariables?: { [name: string]: Field }) { + const compiled = ScriptField.CompileScript(script, params, true, capturedVariables); + return compiled.compiled ? new ScriptField(compiled) : undefined; + } + + public static MakeScript(script: string, params: object = {}, capturedVariables?: { [name: string]: Field }) { + const compiled = ScriptField.CompileScript(script, params, false, capturedVariables); + return compiled.compiled ? new ScriptField(compiled) : undefined; + } +} + +@scriptingGlobal +@Deserializable("computed", deserializeScript) +export class ComputedField extends ScriptField { + _lastComputedResult: any; + //TODO maybe add an observable cache based on what is passed in for doc, considering there shouldn't really be that many possible values for doc + value = computedFn((doc: Doc) => this._valueOutsideReaction(doc)); + _valueOutsideReaction = (doc: Doc) => this._lastComputedResult = this.script.run({ this: doc, self: Cast(doc.rootDocument, Doc, null) || doc, _last_: this._lastComputedResult }, console.log).result; + + + constructor(script: CompiledScript, setterscript?: CompiledScript) { + super(script, + !setterscript && script?.originalScript.includes("self.timecode") ? + ScriptField.CompileScript("self['x' + self.timecode] = value", { value: "any" }, true) : setterscript); + } + + public static MakeScript(script: string, params: object = {}) { + const compiled = ScriptField.CompileScript(script, params, false); + return compiled.compiled ? new ComputedField(compiled) : undefined; + } + public static MakeFunction(script: string, params: object = {}, capturedVariables?: { [name: string]: Field }, setterScript?: string) { + const compiled = ScriptField.CompileScript(script, params, true, capturedVariables); + const setCompiled = setterScript ? ScriptField.CompileScript(setterScript, params, true, capturedVariables) : undefined; + return compiled.compiled ? new ComputedField(compiled, setCompiled?.compiled ? setCompiled : undefined) : undefined; + } + public static MakeInterpolated(fieldKey: string, interpolatorKey: string) { + const getField = ScriptField.CompileScript(`(self['${fieldKey}-indexed'])[self.${interpolatorKey}]`, {}, true, {}); + const setField = ScriptField.CompileScript(`(self['${fieldKey}-indexed'])[self.${interpolatorKey}] = value`, { value: "any" }, true, {}); + return getField.compiled ? new ComputedField(getField, setField?.compiled ? setField : undefined) : undefined; + } +} + +export namespace ComputedField { + let useComputed = true; + export function DisableComputedFields() { + useComputed = false; + } + + export function EnableComputedFields() { + useComputed = true; + } + + export const undefined = "__undefined"; + + export function WithoutComputed(fn: () => T) { + DisableComputedFields(); + try { + return fn(); + } finally { + EnableComputedFields(); + } + } + + export function initPlugin() { + Plugins.addGetterPlugin((doc, _, value) => { + if (useComputed && value instanceof ComputedField) { + return { value: value._valueOutsideReaction(doc), shouldReturn: true }; + } + }); + } +} \ No newline at end of file diff --git a/src/fields/Types.ts b/src/fields/Types.ts new file mode 100644 index 000000000..3d784448d --- /dev/null +++ b/src/fields/Types.ts @@ -0,0 +1,108 @@ +import { Field, Opt, FieldResult, Doc } from "./Doc"; +import { List } from "./List"; +import { RefField } from "./RefField"; +import { DateField } from "./DateField"; +import { ScriptField } from "./ScriptField"; + +export type ToType = + T extends "string" ? string : + T extends "number" ? number : + T extends "boolean" ? boolean : + T extends ListSpec ? List : + // T extends { new(...args: any[]): infer R } ? (R | Promise) : never; + T extends DefaultFieldConstructor ? never : + T extends { new(...args: any[]): List } ? never : + T extends { new(...args: any[]): infer R } ? R : + T extends (doc?: Doc) => infer R ? R : never; + +export type ToConstructor = + T extends string ? "string" : + T extends number ? "number" : + T extends boolean ? "boolean" : + T extends List ? ListSpec : + new (...args: any[]) => T; + +export type ToInterface = { + [P in Exclude]: T[P] extends DefaultFieldConstructor ? Exclude, undefined> : FieldResult>; +}; + +// type ListSpec = { List: ToContructor> | ListSpec> }; +export type ListSpec = { List: ToConstructor }; + +export type DefaultFieldConstructor = { + type: ToConstructor, + defaultVal: T +}; + +// type ListType = { 0: List>>, 1: ToType> }[HasTail extends true ? 0 : 1]; + +export type Head = T extends [any, ...any[]] ? T[0] : never; +export type Tail = + ((...t: T) => any) extends ((_: any, ...tail: infer TT) => any) ? TT : []; +export type HasTail = T extends ([] | [any]) ? false : true; + +export type InterfaceValue = ToConstructor | ListSpec | DefaultFieldConstructor | ((doc?: Doc) => any); +//TODO Allow you to optionally specify default values for schemas, which should then make that field not be partial +export interface Interface { + [key: string]: InterfaceValue; + // [key: string]: ToConstructor | ListSpec; +} +export type WithoutRefField = T extends RefField ? never : T; + +export type CastCtor = ToConstructor | ListSpec; + +export function Cast(field: FieldResult, ctor: T): FieldResult>; +export function Cast(field: FieldResult, ctor: T, defaultVal: WithoutList>> | null): WithoutList>; +export function Cast(field: FieldResult, ctor: T, defaultVal?: ToType | null): FieldResult> | undefined { + if (field instanceof Promise) { + return defaultVal === undefined ? field.then(f => Cast(f, ctor) as any) as any : defaultVal === null ? undefined : defaultVal; + } + if (field !== undefined && !(field instanceof Promise)) { + if (typeof ctor === "string") { + if (typeof field === ctor) { + return field as ToType; + } + } else if (typeof ctor === "object") { + if (field instanceof List) { + return field as any; + } + } else if (field instanceof (ctor as any)) { + return field as ToType; + } + } + return defaultVal === null ? undefined : defaultVal; +} + +export function NumCast(field: FieldResult, defaultVal: number | null = 0) { + return Cast(field, "number", defaultVal); +} + +export function StrCast(field: FieldResult, defaultVal: string | null = "") { + return Cast(field, "string", defaultVal); +} + +export function BoolCast(field: FieldResult, defaultVal: boolean | null = false) { + return Cast(field, "boolean", defaultVal); +} +export function DateCast(field: FieldResult) { + return Cast(field, DateField, null); +} + +export function ScriptCast(field: FieldResult, defaultVal: ScriptField | null = null) { + return Cast(field, ScriptField, defaultVal); +} + +type WithoutList = T extends List ? (R extends RefField ? (R | Promise)[] : R[]) : T; + +export function FieldValue>(field: FieldResult, defaultValue: U): WithoutList; +export function FieldValue(field: FieldResult): Opt; +export function FieldValue(field: FieldResult, defaultValue?: T): Opt { + return (field instanceof Promise || field === undefined) ? defaultValue : field; +} + +export interface PromiseLike { + then(callback: (field: Opt) => void): void; +} +export function PromiseValue(field: FieldResult): PromiseLike> { + return field instanceof Promise ? field : { then(cb: ((field: Opt) => void)) { return cb(field); } }; +} \ No newline at end of file diff --git a/src/fields/URLField.ts b/src/fields/URLField.ts new file mode 100644 index 000000000..fb71160ca --- /dev/null +++ b/src/fields/URLField.ts @@ -0,0 +1,53 @@ +import { Deserializable } from "../client/util/SerializationHelper"; +import { serializable, custom } from "serializr"; +import { ObjectField } from "./ObjectField"; +import { ToScriptString, ToString, Copy } from "./FieldSymbols"; +import { Scripting, scriptingGlobal } from "../client/util/Scripting"; + +function url() { + return custom( + function (value: URL) { + return value.href; + }, + function (jsonValue: string) { + return new URL(jsonValue); + } + ); +} + +export abstract class URLField extends ObjectField { + @serializable(url()) + readonly url: URL; + + constructor(url: string); + constructor(url: URL); + constructor(url: URL | string) { + super(); + if (typeof url === "string") { + url = new URL(url); + } + this.url = url; + } + + [ToScriptString]() { + return `new ${this.constructor.name}("${this.url.href}")`; + } + [ToString]() { + return this.url.href; + } + + [Copy](): this { + return new (this.constructor as any)(this.url); + } +} + +export const nullAudio = "https://actions.google.com/sounds/v1/alarms/beep_short.ogg"; + +@scriptingGlobal @Deserializable("audio") export class AudioField extends URLField { } +@scriptingGlobal @Deserializable("image") export class ImageField extends URLField { } +@scriptingGlobal @Deserializable("video") export class VideoField extends URLField { } +@scriptingGlobal @Deserializable("pdf") export class PdfField extends URLField { } +@scriptingGlobal @Deserializable("web") export class WebField extends URLField { } +@scriptingGlobal @Deserializable("youtube") export class YoutubeField extends URLField { } +@scriptingGlobal @Deserializable("webcam") export class WebCamField extends URLField { } + diff --git a/src/fields/documentSchemas.ts b/src/fields/documentSchemas.ts new file mode 100644 index 000000000..cacba43b6 --- /dev/null +++ b/src/fields/documentSchemas.ts @@ -0,0 +1,100 @@ +import { makeInterface, createSchema, listSpec } from "./Schema"; +import { ScriptField } from "./ScriptField"; +import { Doc } from "./Doc"; +import { DateField } from "./DateField"; + +export const documentSchema = createSchema({ + // content properties + type: "string", // enumerated type of document -- should be template-specific (ie, start with an '_') + title: "string", // document title (can be on either data document or layout) + isTemplateForField: "string",// if specified, it indicates the document is a template that renders the specified field + creationDate: DateField, // when the document was created + links: listSpec(Doc), // computed (readonly) list of links associated with this document + + // "Location" properties in a very general sense + currentTimecode: "number", // current play back time of a temporal document (video / audio) + displayTimecode: "number", // the time that a document should be displayed (e.g., time an annotation should be displayed on a video) + inOverlay: "boolean", // whether the document is rendered in an OverlayView which handles selection/dragging differently + x: "number", // x coordinate when in a freeform view + y: "number", // y coordinate when in a freeform view + z: "number", // z "coordinate" - non-zero specifies the overlay layer of a freeformview + zIndex: "number", // zIndex of a document in a freeform view + scrollY: "number", // "command" to scroll a document to a position on load (the value will be reset to 0 after that ) + scrollTop: "number", // scroll position of a scrollable document (pdf, text, web) + + // appearance properties on the layout + _autoHeight: "boolean", // whether the height of the document should be computed automatically based on its contents + _nativeWidth: "number", // native width of document which determines how much document contents are scaled when the document's width is set + _nativeHeight: "number", // " + _width: "number", // width of document in its container's coordinate system + _height: "number", // " + _xPadding: "number", // pixels of padding on left/right of collectionfreeformview contents when fitToBox is set + _yPadding: "number", // pixels of padding on top/bottom of collectionfreeformview contents when fitToBox is set + _xMargin: "number", // margin added on left/right of most documents to add separation from their container + _yMargin: "number", // margin added on top/bottom of most documents to add separation from their container + _overflow: "string", // sets overflow behvavior for CollectionFreeForm views + _showCaption: "string", // whether editable caption text is overlayed at the bottom of the document + _showTitle: "string", // the fieldkey whose contents should be displayed at the top of the document + _showTitleHover: "string", // the showTitle should be shown only on hover + _showAudio: "boolean", // whether to show the audio record icon on documents + _freeformLayoutEngine: "string",// the string ID for the layout engine to use to layout freeform view documents + _LODdisable: "boolean", // whether to disbale LOD switching for CollectionFreeFormViews + _pivotField: "string", // specifies which field key should be used as the timeline/pivot axis + _replacedChrome: "string", // what the default chrome is replaced with. Currently only supports the value of 'replaced' for PresBox's. + _chromeStatus: "string", // determines the state of the collection chrome. values allowed are 'replaced', 'enabled', 'disabled', 'collapsed' + _fontSize: "number", + _fontFamily: "string", + _sidebarWidthPercent: "string", // percent of text window width taken up by sidebar + + // appearance properties on the data document + backgroundColor: "string", // background color of document + borderRounding: "string", // border radius rounding of document + boxShadow: "string", // the amount of shadow around the perimeter of a document + color: "string", // foreground color of document + fitToBox: "boolean", // whether freeform view contents should be zoomed/panned to fill the area of the document view + fontSize: "string", + layout: "string", // this is the native layout string for the document. templates can be added using other fields and setting layoutKey below + layoutKey: "string", // holds the field key for the field that actually holds the current lyoat + letterSpacing: "string", + opacity: "number", // opacity of document + strokeWidth: "number", + textTransform: "string", + treeViewOpen: "boolean", // flag denoting whether the documents sub-tree (contents) is visible or hidden + treeViewExpandedView: "string", // name of field whose contents are being displayed as the document's subtree + treeViewPreventOpen: "boolean", // ignores the treeViewOpen flag (for allowing a view to not be slaved to other views of the document) + + // interaction and linking properties + ignoreClick: "boolean", // whether documents ignores input clicks (but does not ignore manipulation and other events) + onClick: ScriptField, // script to run when document is clicked (can be overriden by an onClick prop) + onPointerDown: ScriptField, // script to run when document is clicked (can be overriden by an onClick prop) + onPointerUp: ScriptField, // script to run when document is clicked (can be overriden by an onClick prop) + onDragStart: ScriptField, // script to run when document is dragged (without being selected). the script should return the Doc to be dropped. + followLinkLocation: "string",// flag for where to place content when following a click interaction (e.g., onRight, inPlace, inTab, ) + isInPlaceContainer: "boolean",// whether the marked object will display addDocTab() calls that target "inPlace" destinations + isLinkButton: "boolean", // whether document functions as a link follow button to follow the first link on the document when clicked + isBackground: "boolean", // whether document is a background element and ignores input events (can only select with marquee) + lockedPosition: "boolean", // whether the document can be moved (dragged) + lockedTransform: "boolean", // whether the document can be panned/zoomed + + // drag drop properties + dragFactory: Doc, // the document that serves as the "template" for the onDragStart script. ie, to drag out copies of the dragFactory document. + dropAction: "string", // override specifying what should happen when this document is dropped (can be "alias", "copy", "move") + targetDropAction: "string", // allows the target of a drop event to specify the dropAction ("alias", "copy", "move") NOTE: if the document is dropped within the same collection, the dropAction is coerced to 'move' + childDropAction: "string", // specify the override for what should happen when the child of a collection is dragged from it and dropped (can be "alias" or "copy") + removeDropProperties: listSpec("string"), // properties that should be removed from the alias/copy/etc of this document when it is dropped +}); + + +export const collectionSchema = createSchema({ + childLayoutTemplateName: "string", // the name of a template to use to override the layoutKey when rendering a document -- ONLY used in DocHolderBox + childLayoutTemplate: Doc, // layout template to use to render children of a collecion + childLayoutString: "string", //layout string to use to render children of a collection + childClickedOpenTemplateView: Doc, // layout template to apply to a child when its clicked on in a collection and opened (requires onChildClick or other script to read this value and apply template) + dontRegisterChildViews: "boolean", // whether views made of this document are registered so that they can be found when drawing links scrollToLinkID: "string", // id of link being traversed. allows this doc to scroll/highlight/etc its link anchor. scrollToLinkID should be set to undefined by this doc after it sets up its scroll,etc. + onChildClick: ScriptField, // script to run for each child when its clicked + onChildDoubleClick: ScriptField, // script to run for each child when its clicked + onCheckedClick: ScriptField, // script to run when a checkbox is clicked next to a child in a tree view +}); + +export type Document = makeInterface<[typeof documentSchema]>; +export const Document = makeInterface(documentSchema); diff --git a/src/fields/util.ts b/src/fields/util.ts new file mode 100644 index 000000000..a287b0210 --- /dev/null +++ b/src/fields/util.ts @@ -0,0 +1,199 @@ +import { UndoManager } from "../client/util/UndoManager"; +import { Doc, Field, FieldResult, UpdatingFromServer, LayoutSym } from "./Doc"; +import { SerializationHelper } from "../client/util/SerializationHelper"; +import { ProxyField, PrefetchProxy } from "./Proxy"; +import { RefField } from "./RefField"; +import { ObjectField } from "./ObjectField"; +import { action, trace } from "mobx"; +import { Parent, OnUpdate, Update, Id, SelfProxy, Self } from "./FieldSymbols"; +import { DocServer } from "../client/DocServer"; +import { ComputedField } from "./ScriptField"; +import { ScriptCast } from "./Types"; + +function _readOnlySetter(): never { + throw new Error("Documents can't be modified in read-only mode"); +} + +const tracing = false; +export function TraceMobx() { + tracing && trace(); +} + +export interface GetterResult { + value: FieldResult; + shouldReturn?: boolean; +} +export type GetterPlugin = (receiver: any, prop: string | number, currentValue: any) => GetterResult | undefined; +const getterPlugins: GetterPlugin[] = []; + +export namespace Plugins { + export function addGetterPlugin(plugin: GetterPlugin) { + getterPlugins.push(plugin); + } +} + +const _setterImpl = action(function (target: any, prop: string | symbol | number, value: any, receiver: any): boolean { + //console.log("-set " + target[SelfProxy].title + "(" + target[SelfProxy][prop] + ")." + prop.toString() + " = " + value); + if (SerializationHelper.IsSerializing()) { + target[prop] = value; + return true; + } + + if (typeof prop === "symbol") { + target[prop] = value; + return true; + } + if (value !== undefined) { + value = value[SelfProxy] || value; + } + const curValue = target.__fields[prop]; + if (curValue === value || (curValue instanceof ProxyField && value instanceof RefField && curValue.fieldId === value[Id])) { + // TODO This kind of checks correctly in the case that curValue is a ProxyField and value is a RefField, but technically + // curValue should get filled in with value if it isn't already filled in, in case we fetched the referenced field some other way + return true; + } + if (value instanceof RefField) { + value = new ProxyField(value); + } + if (value instanceof ObjectField) { + if (value[Parent] && value[Parent] !== receiver && !(value instanceof PrefetchProxy)) { + throw new Error("Can't put the same object in multiple documents at the same time"); + } + value[Parent] = receiver; + value[OnUpdate] = updateFunction(target, prop, value, receiver); + } + if (curValue instanceof ObjectField) { + delete curValue[Parent]; + delete curValue[OnUpdate]; + } + const writeMode = DocServer.getFieldWriteMode(prop as string); + const fromServer = target[UpdatingFromServer]; + const sameAuthor = fromServer || (receiver.author === Doc.CurrentUserEmail); + const writeToDoc = sameAuthor || (writeMode !== DocServer.WriteMode.LiveReadonly); + const writeToServer = sameAuthor || (writeMode === DocServer.WriteMode.Default); + if (writeToDoc) { + if (value === undefined) { + delete target.__fields[prop]; + } else { + target.__fields[prop] = value; + } + if (typeof value === "object" && !(value instanceof ObjectField)) debugger; + if (writeToServer) { + if (value === undefined) target[Update]({ '$unset': { ["fields." + prop]: "" } }); + else target[Update]({ '$set': { ["fields." + prop]: value instanceof ObjectField ? SerializationHelper.Serialize(value) : (value === undefined ? null : value) } }); + } else { + DocServer.registerDocWithCachedUpdate(receiver, prop as string, curValue); + } + UndoManager.AddEvent({ + redo: () => receiver[prop] = value, + undo: () => receiver[prop] = curValue + }); + } + return true; +}); + +let _setter: (target: any, prop: string | symbol | number, value: any, receiver: any) => boolean = _setterImpl; + +export function makeReadOnly() { + _setter = _readOnlySetter; +} + +export function makeEditable() { + _setter = _setterImpl; +} + +const layoutProps = ["panX", "panY", "width", "height", "nativeWidth", "nativeHeight", "fitWidth", "fitToBox", + "LODdisable", "chromeStatus", "viewType", "gridGap", "xMargin", "yMargin", "autoHeight"]; +export function setter(target: any, in_prop: string | symbol | number, value: any, receiver: any): boolean { + let prop = in_prop; + if (typeof prop === "string" && prop !== "__id" && prop !== "__fields" && (prop.startsWith("_") || layoutProps.includes(prop))) { + if (!prop.startsWith("_")) { + console.log(prop + " is deprecated - switch to _" + prop); + prop = "_" + prop; + } + if (target.__LAYOUT__) { + target.__LAYOUT__[prop] = value; + return true; + } + } + if (target.__fields[prop] instanceof ComputedField && target.__fields[prop].setterscript) { + return ScriptCast(target.__fields[prop])?.setterscript?.run({ self: target[SelfProxy], this: target[SelfProxy], value }).success ? true : false; + } + return _setter(target, prop, value, receiver); +} + +export function getter(target: any, in_prop: string | symbol | number, receiver: any): any { + let prop = in_prop; + if (prop === LayoutSym) { + return target.__LAYOUT__; + } + if (typeof prop === "string" && prop !== "__id" && prop !== "__fields" && (prop.startsWith("_") || layoutProps.includes(prop))) { + if (!prop.startsWith("_")) { + console.log(prop + " is deprecated - switch to _" + prop); + prop = "_" + prop; + } + if (target.__LAYOUT__) return target.__LAYOUT__[prop]; + } + if (prop === "then") {//If we're being awaited + return undefined; + } + if (typeof prop === "symbol") { + return target.__fields[prop] || target[prop]; + } + if (SerializationHelper.IsSerializing()) { + return target[prop]; + } + return getFieldImpl(target, prop, receiver); +} + +function getFieldImpl(target: any, prop: string | number, receiver: any, ignoreProto: boolean = false): any { + receiver = receiver || target[SelfProxy]; + let field = target.__fields[prop]; + for (const plugin of getterPlugins) { + const res = plugin(receiver, prop, field); + if (res === undefined) continue; + if (res.shouldReturn) { + return res.value; + } else { + field = res.value; + } + } + if (field === undefined && !ignoreProto && prop !== "proto") { + const proto = getFieldImpl(target, "proto", receiver, true);//TODO tfs: instead of receiver we could use target[SelfProxy]... I don't which semantics we want or if it really matters + if (proto instanceof Doc) { + return getFieldImpl(proto[Self], prop, receiver, ignoreProto); + } + return undefined; + } + return field; + +} +export function getField(target: any, prop: string | number, ignoreProto: boolean = false): any { + return getFieldImpl(target, prop, undefined, ignoreProto); +} + +export function deleteProperty(target: any, prop: string | number | symbol) { + if (typeof prop === "symbol") { + delete target[prop]; + return true; + } + target[SelfProxy][prop] = undefined; + return true; +} + +export function updateFunction(target: any, prop: any, value: any, receiver: any) { + let current = ObjectField.MakeCopy(value); + return (diff?: any) => { + if (true || !diff) { + diff = { '$set': { ["fields." + prop]: SerializationHelper.Serialize(value) } }; + const oldValue = current; + const newValue = ObjectField.MakeCopy(value); + current = newValue; + UndoManager.AddEvent({ + redo() { receiver[prop] = newValue; }, + undo() { receiver[prop] = oldValue; } + }); + } + target[Update](diff); + }; +} \ No newline at end of file diff --git a/src/mobile/ImageUpload.tsx b/src/mobile/ImageUpload.tsx index f30e9869a..231870531 100644 --- a/src/mobile/ImageUpload.tsx +++ b/src/mobile/ImageUpload.tsx @@ -4,10 +4,10 @@ import { Docs } from '../client/documents/Documents'; import "./ImageUpload.scss"; import React = require('react'); import { DocServer } from '../client/DocServer'; -import { Opt, Doc } from '../new_fields/Doc'; -import { Cast } from '../new_fields/Types'; -import { listSpec } from '../new_fields/Schema'; -import { List } from '../new_fields/List'; +import { Opt, Doc } from '../fields/Doc'; +import { Cast } from '../fields/Types'; +import { listSpec } from '../fields/Schema'; +import { List } from '../fields/List'; import { observer } from 'mobx-react'; import { observable } from 'mobx'; import { Utils } from '../Utils'; diff --git a/src/mobile/MobileInkOverlay.tsx b/src/mobile/MobileInkOverlay.tsx index 1537ae034..973931615 100644 --- a/src/mobile/MobileInkOverlay.tsx +++ b/src/mobile/MobileInkOverlay.tsx @@ -4,11 +4,11 @@ import { MobileInkOverlayContent, GestureContent, UpdateMobileInkOverlayPosition import { observable, action } from "mobx"; import { GestureUtils } from "../pen-gestures/GestureUtils"; import "./MobileInkOverlay.scss"; -import { StrCast, Cast } from '../new_fields/Types'; +import { StrCast, Cast } from '../fields/Types'; import { DragManager } from "../client/util/DragManager"; import { DocServer } from '../client/DocServer'; -import { Doc, DocListCastAsync } from '../new_fields/Doc'; -import { listSpec } from '../new_fields/Schema'; +import { Doc, DocListCastAsync } from '../fields/Doc'; +import { listSpec } from '../fields/Schema'; @observer diff --git a/src/mobile/MobileInterface.tsx b/src/mobile/MobileInterface.tsx index 9d4d58ad1..6c2e797d6 100644 --- a/src/mobile/MobileInterface.tsx +++ b/src/mobile/MobileInterface.tsx @@ -16,12 +16,12 @@ import { InkingControl } from '../client/views/InkingControl'; import { DocumentView } from '../client/views/nodes/DocumentView'; import { RadialMenu } from '../client/views/nodes/RadialMenu'; import { PreviewCursor } from '../client/views/PreviewCursor'; -import { Doc, DocListCast, FieldResult } from '../new_fields/Doc'; -import { Id } from '../new_fields/FieldSymbols'; -import { InkTool } from '../new_fields/InkField'; -import { listSpec } from '../new_fields/Schema'; -import { Cast, FieldValue } from '../new_fields/Types'; -import { WebField } from "../new_fields/URLField"; +import { Doc, DocListCast, FieldResult } from '../fields/Doc'; +import { Id } from '../fields/FieldSymbols'; +import { InkTool } from '../fields/InkField'; +import { listSpec } from '../fields/Schema'; +import { Cast, FieldValue } from '../fields/Types'; +import { WebField } from "../fields/URLField"; import { CurrentUserUtils } from '../client/util/CurrentUserUtils'; import { emptyFunction, emptyPath, returnEmptyString, returnFalse, returnOne, returnTrue, returnZero } from '../Utils'; import "./MobileInterface.scss"; diff --git a/src/new_fields/CursorField.ts b/src/new_fields/CursorField.ts deleted file mode 100644 index 28467377b..000000000 --- a/src/new_fields/CursorField.ts +++ /dev/null @@ -1,66 +0,0 @@ -import { ObjectField } from "./ObjectField"; -import { observable } from "mobx"; -import { Deserializable } from "../client/util/SerializationHelper"; -import { serializable, createSimpleSchema, object, date } from "serializr"; -import { OnUpdate, ToScriptString, ToString, Copy } from "./FieldSymbols"; - -export type CursorPosition = { - x: number, - y: number -}; - -export type CursorMetadata = { - id: string, - identifier: string, - timestamp: number -}; - -export type CursorData = { - metadata: CursorMetadata, - position: CursorPosition -}; - -const PositionSchema = createSimpleSchema({ - x: true, - y: true -}); - -const MetadataSchema = createSimpleSchema({ - id: true, - identifier: true, - timestamp: true -}); - -const CursorSchema = createSimpleSchema({ - metadata: object(MetadataSchema), - position: object(PositionSchema) -}); - -@Deserializable("cursor") -export default class CursorField extends ObjectField { - - @serializable(object(CursorSchema)) - readonly data: CursorData; - - constructor(data: CursorData) { - super(); - this.data = data; - } - - setPosition(position: CursorPosition) { - this.data.position = position; - this.data.metadata.timestamp = Date.now(); - this[OnUpdate](); - } - - [Copy]() { - return new CursorField(this.data); - } - - [ToScriptString]() { - return "invalid"; - } - [ToString]() { - return "invalid"; - } -} \ No newline at end of file diff --git a/src/new_fields/DateField.ts b/src/new_fields/DateField.ts deleted file mode 100644 index a925148c2..000000000 --- a/src/new_fields/DateField.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { Deserializable } from "../client/util/SerializationHelper"; -import { serializable, date } from "serializr"; -import { ObjectField } from "./ObjectField"; -import { Copy, ToScriptString, ToString } from "./FieldSymbols"; -import { scriptingGlobal, Scripting } from "../client/util/Scripting"; - -@scriptingGlobal -@Deserializable("date") -export class DateField extends ObjectField { - @serializable(date()) - readonly date: Date; - - constructor(date: Date = new Date()) { - super(); - this.date = date; - } - - [Copy]() { - return new DateField(this.date); - } - - toString() { - return `${this.date.toISOString()}`; - } - - [ToScriptString]() { - return `new DateField(new Date(${this.date.toISOString()}))`; - } - [ToString]() { - return this.date.toISOString(); - } -} - -Scripting.addGlobal(function d(...dateArgs: any[]) { - return new DateField(new (Date as any)(...dateArgs)); -}); diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts deleted file mode 100644 index a1e1e11b1..000000000 --- a/src/new_fields/Doc.ts +++ /dev/null @@ -1,1109 +0,0 @@ -import { action, computed, observable, ObservableMap, runInAction } from "mobx"; -import { computedFn } from "mobx-utils"; -import { alias, map, serializable } from "serializr"; -import { DocServer } from "../client/DocServer"; -import { DocumentType } from "../client/documents/DocumentTypes"; -import { Scripting, scriptingGlobal } from "../client/util/Scripting"; -import { afterDocDeserialize, autoObject, Deserializable, SerializationHelper } from "../client/util/SerializationHelper"; -import { UndoManager } from "../client/util/UndoManager"; -import { intersectRect, Utils } from "../Utils"; -import { HandleUpdate, Id, OnUpdate, Parent, Self, SelfProxy, ToScriptString, ToString, Update, Copy } from "./FieldSymbols"; -import { List } from "./List"; -import { ObjectField } from "./ObjectField"; -import { PrefetchProxy, ProxyField } from "./Proxy"; -import { FieldId, RefField } from "./RefField"; -import { RichTextField } from "./RichTextField"; -import { listSpec } from "./Schema"; -import { ComputedField, ScriptField } from "./ScriptField"; -import { Cast, FieldValue, NumCast, StrCast, ToConstructor, ScriptCast } from "./Types"; -import { deleteProperty, getField, getter, makeEditable, makeReadOnly, setter, updateFunction } from "./util"; -import { Docs, DocumentOptions } from "../client/documents/Documents"; -import { PdfField, VideoField, AudioField, ImageField } from "./URLField"; -import { LinkManager } from "../client/util/LinkManager"; - -export namespace Field { - export function toKeyValueString(doc: Doc, key: string): string { - const onDelegate = Object.keys(doc).includes(key); - - const field = ComputedField.WithoutComputed(() => FieldValue(doc[key])); - if (Field.IsField(field)) { - return (onDelegate ? "=" : "") + (field instanceof ComputedField ? `:=${field.script.originalScript}` : Field.toScriptString(field)); - } - return ""; - } - export function toScriptString(field: Field): string { - if (typeof field === "string") { - return `"${field}"`; - } else if (typeof field === "number" || typeof field === "boolean") { - return String(field); - } else { - return field[ToScriptString](); - } - } - export function toString(field: Field): string { - if (typeof field === "string") { - return field; - } else if (typeof field === "number" || typeof field === "boolean") { - return String(field); - } else if (field instanceof ObjectField) { - return field[ToString](); - } else if (field instanceof RefField) { - return field[ToString](); - } - return ""; - } - export function IsField(field: any): field is Field; - export function IsField(field: any, includeUndefined: true): field is Field | undefined; - export function IsField(field: any, includeUndefined: boolean = false): field is Field | undefined { - return (typeof field === "string") - || (typeof field === "number") - || (typeof field === "boolean") - || (field instanceof ObjectField) - || (field instanceof RefField) - || (includeUndefined && field === undefined); - } -} -export type Field = number | string | boolean | ObjectField | RefField; -export type Opt = T | undefined; -export type FieldWaiting = T extends undefined ? never : Promise; -export type FieldResult = Opt | FieldWaiting>; - -/** - * Cast any field to either a List of Docs or undefined if the given field isn't a List of Docs. - * If a default value is given, that will be returned instead of undefined. - * If a default value is given, the returned value should not be modified as it might be a temporary value. - * If no default value is given, and the returned value is not undefined, it can be safely modified. - */ -export function DocListCastAsync(field: FieldResult): Promise; -export function DocListCastAsync(field: FieldResult, defaultValue: Doc[]): Promise; -export function DocListCastAsync(field: FieldResult, defaultValue?: Doc[]) { - const list = Cast(field, listSpec(Doc)); - return list ? Promise.all(list).then(() => list) : Promise.resolve(defaultValue); -} - -export async function DocCastAsync(field: FieldResult): Promise> { - return Cast(field, Doc); -} - -export function DocListCast(field: FieldResult): Doc[] { - return Cast(field, listSpec(Doc), []).filter(d => d instanceof Doc) as Doc[]; -} - -export const WidthSym = Symbol("Width"); -export const HeightSym = Symbol("Height"); -export const DataSym = Symbol("Data"); -export const LayoutSym = Symbol("Layout"); -export const UpdatingFromServer = Symbol("UpdatingFromServer"); -const CachedUpdates = Symbol("Cached updates"); - - -function fetchProto(doc: Doc) { - const proto = doc.proto; - if (proto instanceof Promise) { - return proto; - } -} - -@scriptingGlobal -@Deserializable("Doc", fetchProto).withFields(["id"]) -export class Doc extends RefField { - constructor(id?: FieldId, forceSave?: boolean) { - super(id); - const doc = new Proxy(this, { - set: setter, - get: getter, - // getPrototypeOf: (target) => Cast(target[SelfProxy].proto, Doc) || null, // TODO this might be able to replace the proto logic in getter - has: (target, key) => key in target.__fields, - ownKeys: target => { - const obj = {} as any; - Object.assign(obj, target.___fields); - runInAction(() => obj.__LAYOUT__ = target.__LAYOUT__); - return Object.keys(obj); - }, - getOwnPropertyDescriptor: (target, prop) => { - if (prop.toString() === "__LAYOUT__") { - return Reflect.getOwnPropertyDescriptor(target, prop); - } - if (prop in target.__fields) { - return { - configurable: true,//TODO Should configurable be true? - enumerable: true, - value: target.__fields[prop] - }; - } - return Reflect.getOwnPropertyDescriptor(target, prop); - }, - deleteProperty: deleteProperty, - defineProperty: () => { throw new Error("Currently properties can't be defined on documents using Object.defineProperty"); }, - }); - this[SelfProxy] = doc; - if (!id || forceSave) { - DocServer.CreateField(doc); - } - return doc; - } - - proto: Opt; - [key: string]: FieldResult; - - @serializable(alias("fields", map(autoObject(), { afterDeserialize: afterDocDeserialize }))) - private get __fields() { return this.___fields; } - private set __fields(value) { - this.___fields = value; - for (const key in value) { - const field = value[key]; - if (!(field instanceof ObjectField)) continue; - field[Parent] = this[Self]; - field[OnUpdate] = updateFunction(this[Self], key, field, this[SelfProxy]); - } - } - - @observable - //{ [key: string]: Field | FieldWaiting | undefined } - private ___fields: any = {}; - - private [UpdatingFromServer]: boolean = false; - - private [Update] = (diff: any) => { - !this[UpdatingFromServer] && DocServer.UpdateField(this[Id], diff); - } - - private [Self] = this; - private [SelfProxy]: any; - public [WidthSym] = () => NumCast(this[SelfProxy]._width); - public [HeightSym] = () => NumCast(this[SelfProxy]._height); - public get [LayoutSym]() { return this[SelfProxy].__LAYOUT__; } - public get [DataSym]() { - const self = this[SelfProxy]; - return self.resolvedDataDoc && !self.isTemplateForField ? self : - Doc.GetProto(Cast(Doc.Layout(self).resolvedDataDoc, Doc, null) || self); - } - @computed get __LAYOUT__() { - const templateLayoutDoc = Cast(Doc.LayoutField(this[SelfProxy]), Doc, null); - if (templateLayoutDoc) { - let renderFieldKey: any; - const layoutField = templateLayoutDoc[StrCast(templateLayoutDoc.layoutKey, "layout")]; - if (typeof layoutField === "string") { - renderFieldKey = layoutField.split("fieldKey={'")[1].split("'")[0];//layoutField.split("'")[1]; - } else { - return Cast(layoutField, Doc, null); - } - return Cast(this[SelfProxy][renderFieldKey + "-layout[" + templateLayoutDoc[Id] + "]"], Doc, null) || templateLayoutDoc; - } - return undefined; - } - - [ToScriptString]() { return `DOC-"${this[Self][Id]}"-`; } - [ToString]() { return `Doc(${this.title})`; } - - private [CachedUpdates]: { [key: string]: () => void | Promise } = {}; - public static CurrentUserEmail: string = ""; - public async [HandleUpdate](diff: any) { - const set = diff.$set; - const sameAuthor = this.author === Doc.CurrentUserEmail; - if (set) { - for (const key in set) { - if (!key.startsWith("fields.")) { - continue; - } - const fKey = key.substring(7); - const fn = async () => { - const value = await SerializationHelper.Deserialize(set[key]); - this[UpdatingFromServer] = true; - this[fKey] = value; - this[UpdatingFromServer] = false; - }; - if (sameAuthor || DocServer.getFieldWriteMode(fKey) !== DocServer.WriteMode.Playground) { - delete this[CachedUpdates][fKey]; - await fn(); - } else { - this[CachedUpdates][fKey] = fn; - } - } - } - const unset = diff.$unset; - if (unset) { - for (const key in unset) { - if (!key.startsWith("fields.")) { - continue; - } - const fKey = key.substring(7); - const fn = () => { - this[UpdatingFromServer] = true; - delete this[fKey]; - this[UpdatingFromServer] = false; - }; - if (sameAuthor || DocServer.getFieldWriteMode(fKey) !== DocServer.WriteMode.Playground) { - delete this[CachedUpdates][fKey]; - await fn(); - } else { - this[CachedUpdates][fKey] = fn; - } - } - } - } -} - -export namespace Doc { - // export function GetAsync(doc: Doc, key: string, ignoreProto: boolean = false): Promise { - // const self = doc[Self]; - // return new Promise(res => getField(self, key, ignoreProto, res)); - // } - // export function GetTAsync(doc: Doc, key: string, ctor: ToConstructor, ignoreProto: boolean = false): Promise { - // return new Promise(async res => { - // const field = await GetAsync(doc, key, ignoreProto); - // return Cast(field, ctor); - // }); - // } - - export function RunCachedUpdate(doc: Doc, field: string) { - const update = doc[CachedUpdates][field]; - if (update) { - update(); - delete doc[CachedUpdates][field]; - } - } - export function AddCachedUpdate(doc: Doc, field: string, oldValue: any) { - const val = oldValue; - doc[CachedUpdates][field] = () => { - doc[UpdatingFromServer] = true; - doc[field] = val; - doc[UpdatingFromServer] = false; - }; - } - export function MakeReadOnly(): { end(): void } { - makeReadOnly(); - return { - end() { - makeEditable(); - } - }; - } - - export function Get(doc: Doc, key: string, ignoreProto: boolean = false): FieldResult { - try { - return getField(doc[Self], key, ignoreProto); - } catch { - return doc; - } - } - export function GetT(doc: Doc, key: string, ctor: ToConstructor, ignoreProto: boolean = false): FieldResult { - return Cast(Get(doc, key, ignoreProto), ctor) as FieldResult; - } - export function IsPrototype(doc: Doc) { - return GetT(doc, "isPrototype", "boolean", true); - } - export function IsBaseProto(doc: Doc) { - return GetT(doc, "baseProto", "boolean", true); - } - export async function SetInPlace(doc: Doc, key: string, value: Field | undefined, defaultProto: boolean) { - const hasProto = doc.proto instanceof Doc; - const onDeleg = Object.getOwnPropertyNames(doc).indexOf(key) !== -1; - const onProto = hasProto && Object.getOwnPropertyNames(doc.proto).indexOf(key) !== -1; - if (onDeleg || !hasProto || (!onProto && !defaultProto)) { - doc[key] = value; - } else doc.proto![key] = value; - } - export async function SetOnPrototype(doc: Doc, key: string, value: Field) { - const proto = Object.getOwnPropertyNames(doc).indexOf("isPrototype") === -1 ? doc.proto : doc; - - if (proto) { - proto[key] = value; - } - } - export function GetAllPrototypes(doc: Doc): Doc[] { - const protos: Doc[] = []; - let d: Opt = doc; - while (d) { - protos.push(d); - d = FieldValue(d.proto); - } - return protos; - } - - /** - * This function is intended to model Object.assign({}, {}) [https://mzl.la/1Mo3l21], which copies - * the values of the properties of a source object into the target. - * - * This is just a specific, Dash-authored version that serves the same role for our - * Doc class. - * - * @param doc the target document into which you'd like to insert the new fields - * @param fields the fields to project onto the target. Its type signature defines a mapping from some string key - * to a potentially undefined field, where each entry in this mapping is optional. - */ - export function assign(doc: Doc, fields: Partial>>, skipUndefineds: boolean = false) { - for (const key in fields) { - if (fields.hasOwnProperty(key)) { - const value = fields[key]; - if (!skipUndefineds || value !== undefined) { // Do we want to filter out undefineds? - doc[key] = value; - } - } - } - return doc; - } - - // compare whether documents or their protos match - export function AreProtosEqual(doc?: Doc, other?: Doc) { - if (!doc || !other) return false; - const r = (doc === other); - const r2 = (Doc.GetProto(doc) === other); - const r3 = (Doc.GetProto(other) === doc); - const r4 = (Doc.GetProto(doc) === Doc.GetProto(other) && Doc.GetProto(other) !== undefined); - return r || r2 || r3 || r4; - } - - // Gets the data document for the document. Note: this is mis-named -- it does not specifically - // return the doc's proto, but rather recursively searches through the proto inheritance chain - // and returns the document who's proto is undefined or whose proto is marked as a base prototype ('isPrototype'). - export function GetProto(doc: Doc): Doc { - if (doc instanceof Promise) { - console.log("GetProto: error: got Promise insead of Doc"); - } - const proto = doc && (Doc.GetT(doc, "isPrototype", "boolean", true) ? doc : (doc.proto || doc)); - return proto === doc ? proto : Doc.GetProto(proto); - } - export function GetDataDoc(doc: Doc): Doc { - const proto = Doc.GetProto(doc); - return proto === doc ? proto : Doc.GetDataDoc(proto); - } - - export function allKeys(doc: Doc): string[] { - const results: Set = new Set; - - let proto: Doc | undefined = doc; - while (proto) { - Object.keys(proto).forEach(key => results.add(key)); - proto = proto.proto; - } - - return Array.from(results); - } - - export function IndexOf(toFind: Doc, list: Doc[], allowProtos: boolean = true) { - let index = list.reduce((p, v, i) => (v instanceof Doc && v === toFind) ? i : p, -1); - index = allowProtos && index !== -1 ? index : list.reduce((p, v, i) => (v instanceof Doc && Doc.AreProtosEqual(v, toFind)) ? i : p, -1); - return index; // list.findIndex(doc => doc === toFind || Doc.AreProtosEqual(doc, toFind)); - } - export function RemoveDocFromList(listDoc: Doc, fieldKey: string | undefined, doc: Doc) { - const key = fieldKey ? fieldKey : Doc.LayoutFieldKey(listDoc); - if (listDoc[key] === undefined) { - Doc.GetProto(listDoc)[key] = new List(); - } - const list = Cast(listDoc[key], listSpec(Doc)); - if (list) { - const ind = list.indexOf(doc); - if (ind !== -1) { - list.splice(ind, 1); - return true; - } - } - return false; - } - export function AddDocToList(listDoc: Doc, fieldKey: string | undefined, doc: Doc, relativeTo?: Doc, before?: boolean, first?: boolean, allowDuplicates?: boolean, reversed?: boolean) { - const key = fieldKey ? fieldKey : Doc.LayoutFieldKey(listDoc); - if (listDoc[key] === undefined) { - Doc.GetProto(listDoc)[key] = new List(); - } - const list = Cast(listDoc[key], listSpec(Doc)); - if (list) { - if (allowDuplicates !== true) { - const pind = list.reduce((l, d, i) => d instanceof Doc && d[Id] === doc[Id] ? i : l, -1); - if (pind !== -1) { - list.splice(pind, 1); - } - } - if (first) { - list.splice(0, 0, doc); - } - else { - const ind = relativeTo ? list.indexOf(relativeTo) : -1; - if (ind === -1) { - if (reversed) list.splice(0, 0, doc); - else list.push(doc); - } - else { - if (reversed) list.splice(before ? (list.length - ind) + 1 : list.length - ind, 0, doc); - else list.splice(before ? ind : ind + 1, 0, doc); - } - } - return true; - } - return false; - } - - // - // Computes the bounds of the contents of a set of documents. - // - export function ComputeContentBounds(docList: Doc[]) { - const bounds = docList.reduce((bounds, doc) => { - const [sptX, sptY] = [NumCast(doc.x), NumCast(doc.y)]; - const [bptX, bptY] = [sptX + doc[WidthSym](), sptY + doc[HeightSym]()]; - return { - x: Math.min(sptX, bounds.x), y: Math.min(sptY, bounds.y), - r: Math.max(bptX, bounds.r), b: Math.max(bptY, bounds.b) - }; - }, { x: Number.MAX_VALUE, y: Number.MAX_VALUE, r: -Number.MAX_VALUE, b: -Number.MAX_VALUE }); - return bounds; - } - - export function MakeAlias(doc: Doc, id?: string) { - const alias = !GetT(doc, "isPrototype", "boolean", true) ? Doc.MakeCopy(doc, undefined, id) : Doc.MakeDelegate(doc, id); - const layout = Doc.LayoutField(alias); - if (layout instanceof Doc && layout !== alias && layout === Doc.Layout(alias)) { - Doc.SetLayout(alias, Doc.MakeAlias(layout)); - } - alias.aliasOf = doc; - alias.title = ComputedField.MakeFunction(`renameAlias(this, ${Doc.GetProto(doc).aliasNumber = NumCast(Doc.GetProto(doc).aliasNumber) + 1})`); - return alias; - } - - // - // Determines whether the layout needs to be expanded (as a template). - // template expansion is rquired when the layout is a template doc/field and there's a datadoc which isn't equal to the layout template - // - export function WillExpandTemplateLayout(layoutDoc: Doc, dataDoc?: Doc) { - return (layoutDoc.isTemplateForField || layoutDoc.isTemplateDoc) && dataDoc && layoutDoc !== dataDoc; - } - - const _pendingMap: Map = new Map(); - // - // Returns an expanded template layout for a target data document if there is a template relationship - // between the two. If so, the layoutDoc is expanded into a new document that inherits the properties - // of the original layout while allowing for individual layout properties to be overridden in the expanded layout. - // templateArgs should be equivalent to the layout key that generates the template since that's where the template parameters are stored in ()'s at the end of the key. - // NOTE: the template will have references to "@params" -- the template arguments will be assigned to the '@params' field - // so that when the @params key is accessed, it will be rewritten as the key that is stored in the 'params' field and - // the derefence will then occur on the rootDocument (the original document). - // in the future, field references could be written as @ and then arguments would be passed in the layout key as: - // layout_mytemplate(somparam=somearg). - // then any references to @someparam would be rewritten as accesses to 'somearg' on the rootDocument - export function expandTemplateLayout(templateLayoutDoc: Doc, targetDoc?: Doc, templateArgs?: string) { - const args = templateArgs?.match(/\(([a-zA-Z0-9._\-]*)\)/)?.[1].replace("()", "") || StrCast(templateLayoutDoc.PARAMS); - if (!args && !WillExpandTemplateLayout(templateLayoutDoc, targetDoc) || !targetDoc) return templateLayoutDoc; - - const templateField = StrCast(templateLayoutDoc.isTemplateForField); // the field that the template renders - // First it checks if an expanded layout already exists -- if so it will be stored on the dataDoc - // using the template layout doc's id as the field key. - // If it doesn't find the expanded layout, then it makes a delegate of the template layout and - // saves it on the data doc indexed by the template layout's id. - // - const params = args.split("=").length > 1 ? args.split("=")[0] : "PARAMS"; - const layoutFielddKey = Doc.LayoutFieldKey(templateLayoutDoc); - const expandedLayoutFieldKey = (templateField || layoutFielddKey) + "-layout[" + templateLayoutDoc[Id] + (args ? `(${args})` : "") + "]"; - let expandedTemplateLayout = targetDoc?.[expandedLayoutFieldKey]; - - if (templateLayoutDoc.resolvedDataDoc instanceof Promise) { - expandedTemplateLayout = undefined; - _pendingMap.set(targetDoc[Id] + expandedLayoutFieldKey, true); - } - else if (expandedTemplateLayout === undefined && !_pendingMap.get(targetDoc[Id] + expandedLayoutFieldKey + args)) { - if (templateLayoutDoc.resolvedDataDoc === (targetDoc.rootDocument || Doc.GetProto(targetDoc)) && templateLayoutDoc.PARAMS === StrCast(targetDoc.PARAMS)) { - expandedTemplateLayout = templateLayoutDoc; // reuse an existing template layout if its for the same document with the same params - } else { - _pendingMap.set(targetDoc[Id] + expandedLayoutFieldKey + args, true); - templateLayoutDoc.resolvedDataDoc && (templateLayoutDoc = Cast(templateLayoutDoc.proto, Doc, null) || templateLayoutDoc); // if the template has already been applied (ie, a nested template), then use the template's prototype - setTimeout(action(() => { - if (!targetDoc[expandedLayoutFieldKey]) { - const newLayoutDoc = Doc.MakeDelegate(templateLayoutDoc, undefined, "[" + templateLayoutDoc.title + "]"); - // the template's arguments are stored in params which is derefenced to find - // the actual field key where the parameterized template data is stored. - newLayoutDoc[params] = args !== "..." ? args : ""; // ... signifies the layout has sub template(s) -- so we have to expand the layout for them so that they can get the correct 'rootDocument' field, but we don't need to reassign their params. it would be better if the 'rootDocument' field could be passed dynamically to avoid have to create instances - newLayoutDoc.rootDocument = targetDoc; - targetDoc[expandedLayoutFieldKey] = newLayoutDoc; - const dataDoc = Doc.GetProto(targetDoc); - newLayoutDoc.resolvedDataDoc = dataDoc; - if (dataDoc[templateField] === undefined && templateLayoutDoc[templateField] instanceof List) { - dataDoc[templateField] = ComputedField.MakeFunction(`ObjectField.MakeCopy(templateLayoutDoc["${templateField}"] as List)`, { templateLayoutDoc: Doc.name }, { templateLayoutDoc }); - } - _pendingMap.delete(targetDoc[Id] + expandedLayoutFieldKey + args); - } - }), 0); - } - } - return expandedTemplateLayout instanceof Doc ? expandedTemplateLayout : undefined; // layout is undefined if the expandedTemplateLayout is pending. - } - - // if the childDoc is a template for a field, then this will return the expanded layout with its data doc. - // otherwise, it just returns the childDoc - export function GetLayoutDataDocPair(containerDoc: Doc, containerDataDoc: Opt, childDoc: Doc) { - if (!childDoc || childDoc instanceof Promise || !Doc.GetProto(childDoc)) { - console.log("No, no, no!"); - return { layout: childDoc, data: childDoc }; - } - const resolvedDataDoc = (Doc.AreProtosEqual(containerDataDoc, containerDoc) || (!childDoc.isTemplateDoc && !childDoc.isTemplateForField && !childDoc.PARAMS) ? undefined : containerDataDoc); - return { layout: Doc.expandTemplateLayout(childDoc, resolvedDataDoc, "(" + StrCast(containerDoc.PARAMS) + ")"), data: resolvedDataDoc }; - } - - export function Overwrite(doc: Doc, overwrite: Doc, copyProto: boolean = false): Doc { - Object.keys(doc).forEach(key => { - const field = ProxyField.WithoutProxy(() => doc[key]); - if (key === "proto" && copyProto) { - if (doc.proto instanceof Doc && overwrite.proto instanceof Doc) { - overwrite[key] = Doc.Overwrite(doc[key]!, overwrite.proto); - } - } else { - if (field instanceof RefField) { - overwrite[key] = field; - } else if (field instanceof ObjectField) { - overwrite[key] = ObjectField.MakeCopy(field); - } else if (field instanceof Promise) { - debugger; //This shouldn't happend... - } else { - overwrite[key] = field; - } - } - }); - - return overwrite; - } - - export function MakeCopy(doc: Doc, copyProto: boolean = false, copyProtoId?: string): Doc { - const copy = new Doc(copyProtoId, true); - const exclude = Cast(doc.excludeFields, listSpec("string"), []); - Object.keys(doc).forEach(key => { - if (exclude.includes(key)) return; - const cfield = ComputedField.WithoutComputed(() => FieldValue(doc[key])); - const field = ProxyField.WithoutProxy(() => doc[key]); - if (key === "proto" && copyProto) { - if (doc[key] instanceof Doc) { - copy[key] = Doc.MakeCopy(doc[key]!, false); - } - } else { - if (field instanceof RefField) { - copy[key] = field; - } else if (cfield instanceof ComputedField) { - copy[key] = ComputedField.MakeFunction(cfield.script.originalScript); - } else if (field instanceof ObjectField) { - copy[key] = doc[key] instanceof Doc ? - key.includes("layout[") ? Doc.MakeCopy(doc[key] as Doc, false) : doc[key] : // reference documents except copy documents that are expanded teplate fields - ObjectField.MakeCopy(field); - } else if (field instanceof Promise) { - debugger; //This shouldn't happend... - } else { - copy[key] = field; - } - } - }); - - return copy; - } - - export function MakeClone(doc: Doc): Doc { - const cloneMap = new Map(); - const rtfMap: { copy: Doc, key: string, field: RichTextField }[] = []; - const copy = Doc.makeClone(doc, cloneMap, rtfMap); - rtfMap.map(({ copy, key, field }) => { - const replacer = (match: any, attr: string, id: string, offset: any, string: any) => { - const mapped = cloneMap.get(id); - return attr + "\"" + (mapped ? mapped[Id] : id) + "\""; - }; - const replacer2 = (match: any, href: string, id: string, offset: any, string: any) => { - const mapped = cloneMap.get(id); - return href + (mapped ? mapped[Id] : id); - }; - const regex = `(${Utils.prepend("/doc/")})([^"]*)`; - const re = new RegExp(regex, "g"); - copy[key] = new RichTextField(field.Data.replace(/("docid":|"targetId":|"linkId":)"([^"]+)"/g, replacer).replace(re, replacer2), field.Text); - }); - return copy; - } - - export function makeClone(doc: Doc, cloneMap: Map, rtfs: { copy: Doc, key: string, field: RichTextField }[]): Doc { - if (Doc.IsBaseProto(doc)) return doc; - if (cloneMap.get(doc[Id])) return cloneMap.get(doc[Id])!; - const copy = new Doc(undefined, true); - cloneMap.set(doc[Id], copy); - if (LinkManager.Instance.getAllLinks().includes(doc) && LinkManager.Instance.getAllLinks().indexOf(copy) === -1) LinkManager.Instance.addLink(copy); - const exclude = Cast(doc.excludeFields, listSpec("string"), []); - Object.keys(doc).forEach(key => { - if (exclude.includes(key)) return; - const cfield = ComputedField.WithoutComputed(() => FieldValue(doc[key])); - const field = ProxyField.WithoutProxy(() => doc[key]); - const copyObjectField = (field: ObjectField) => { - const list = Cast(doc[key], listSpec(Doc)); - if (list !== undefined && !(list instanceof Promise)) { - copy[key] = new List(list.filter(d => d instanceof Doc).map(d => Doc.makeClone(d as Doc, cloneMap, rtfs))); - } else if (doc[key] instanceof Doc) { - copy[key] = key.includes("layout[") ? undefined : Doc.makeClone(doc[key] as Doc, cloneMap, rtfs); // reference documents except copy documents that are expanded teplate fields - } else { - copy[key] = ObjectField.MakeCopy(field); - if (field instanceof RichTextField) { - if (field.Data.includes('"docid":') || field.Data.includes('"targetId":') || field.Data.includes('"linkId":')) { - rtfs.push({ copy, key, field }); - } - } - } - }; - if (key === "proto") { - if (doc[key] instanceof Doc) { - copy[key] = Doc.makeClone(doc[key]!, cloneMap, rtfs); - } - } else { - if (field instanceof RefField) { - copy[key] = field; - } else if (cfield instanceof ComputedField) { - copy[key] = ComputedField.MakeFunction(cfield.script.originalScript); - (key === "links" && field instanceof ObjectField) && copyObjectField(field); - } else if (field instanceof ObjectField) { - copyObjectField(field); - } else if (field instanceof Promise) { - debugger; //This shouldn't happend... - } else { - copy[key] = field; - } - } - }); - Doc.SetInPlace(copy, "title", "CLONE: " + doc.title, true); - copy.cloneOf = doc; - cloneMap.set(doc[Id], copy); - return copy; - } - - export function MakeDelegate(doc: Doc, id?: string, title?: string): Doc; - export function MakeDelegate(doc: Opt, id?: string, title?: string): Opt; - export function MakeDelegate(doc: Opt, id?: string, title?: string): Opt { - if (doc) { - const delegate = new Doc(id, true); - delegate.proto = doc; - title && (delegate.title = title); - return delegate; - } - return undefined; - } - - let _applyCount: number = 0; - export function ApplyTemplate(templateDoc: Doc) { - if (templateDoc) { - const target = Doc.MakeDelegate(new Doc()); - const targetKey = StrCast(templateDoc.layoutKey, "layout"); - const applied = ApplyTemplateTo(templateDoc, target, targetKey, templateDoc.title + "(..." + _applyCount++ + ")"); - target.layoutKey = targetKey; - applied && (Doc.GetProto(applied).type = templateDoc.type); - return applied; - } - return undefined; - } - export function ApplyTemplateTo(templateDoc: Doc, target: Doc, targetKey: string, titleTarget: string | undefined) { - if (!Doc.AreProtosEqual(target[targetKey] as Doc, templateDoc)) { - if (target.resolvedDataDoc) { - target[targetKey] = new PrefetchProxy(templateDoc); - } else { - titleTarget && (Doc.GetProto(target).title = titleTarget); - Doc.GetProto(target)[targetKey] = new PrefetchProxy(templateDoc); - } - } - return target; - } - - // - // This function converts a generic field layout display into a field layout that displays a specific - // metadata field indicated by the title of the template field (not the default field that it was rendering) - // - export function MakeMetadataFieldTemplate(templateField: Doc, templateDoc: Opt): boolean { - - // find the metadata field key that this template field doc will display (indicated by its title) - const metadataFieldKey = StrCast(templateField.isTemplateForField) || StrCast(templateField.title).replace(/^-/, ""); - - // update the original template to mark it as a template - templateField.isTemplateForField = metadataFieldKey; - templateField.title = metadataFieldKey; - - const templateFieldValue = templateField[metadataFieldKey] || templateField[Doc.LayoutFieldKey(templateField)]; - const templateCaptionValue = templateField.caption; - // move any data that the template field had been rendering over to the template doc so that things will still be rendered - // when the template field is adjusted to point to the new metadatafield key. - // note 1: if the template field contained a list of documents, each of those documents will be converted to templates as well. - // note 2: this will not overwrite any field that already exists on the template doc at the field key - if (!templateDoc?.[metadataFieldKey] && templateFieldValue instanceof ObjectField) { - Cast(templateFieldValue, listSpec(Doc), [])?.map(d => d instanceof Doc && MakeMetadataFieldTemplate(d, templateDoc)); - (Doc.GetProto(templateField)[metadataFieldKey] = ObjectField.MakeCopy(templateFieldValue)); - } - // copy the textTemplates from 'this' (not 'self') because the layout contains the template info, not the original doc - if (templateCaptionValue instanceof RichTextField && !templateCaptionValue.Empty()) { - templateField["caption-textTemplate"] = ComputedField.MakeFunction(`copyField(this.caption)`); - } - if (templateFieldValue instanceof RichTextField && !templateFieldValue.Empty()) { - templateField[metadataFieldKey + "-textTemplate"] = ComputedField.MakeFunction(`copyField(this.${metadataFieldKey})`); - } - - // get the layout string that the template uses to specify its layout - const templateFieldLayoutString = StrCast(Doc.LayoutField(Doc.Layout(templateField))); - - // change it to render the target metadata field instead of what it was rendering before and assign it to the template field layout document. - Doc.Layout(templateField).layout = templateFieldLayoutString.replace(/fieldKey={'[^']*'}/, `fieldKey={'${metadataFieldKey}'}`); - - // assign the template field doc a delegate of any extension document that was previously used to render the template field (since extension doc's carry rendering informatino) - Doc.Layout(templateField)[metadataFieldKey + "_ext"] = Doc.MakeDelegate(templateField[templateFieldLayoutString?.split("'")[1] + "_ext"] as Doc); - - return true; - } - - export function overlapping(doc1: Doc, doc2: Doc, clusterDistance: number) { - const doc2Layout = Doc.Layout(doc2); - const doc1Layout = Doc.Layout(doc1); - const x2 = NumCast(doc2.x) - clusterDistance; - const y2 = NumCast(doc2.y) - clusterDistance; - const w2 = NumCast(doc2Layout._width) + clusterDistance; - const h2 = NumCast(doc2Layout._height) + clusterDistance; - const x = NumCast(doc1.x) - clusterDistance; - const y = NumCast(doc1.y) - clusterDistance; - const w = NumCast(doc1Layout._width) + clusterDistance; - const h = NumCast(doc1Layout._height) + clusterDistance; - return doc1.z === doc2.z && intersectRect({ left: x, top: y, width: w, height: h }, { left: x2, top: y2, width: w2, height: h2 }); - } - - export function isBrushedHighlightedDegree(doc: Doc) { - if (Doc.IsHighlighted(doc)) { - return 6; - } - else { - return Doc.IsBrushedDegree(doc); - } - } - - export class DocBrush { - BrushedDoc: ObservableMap = new ObservableMap(); - } - const brushManager = new DocBrush(); - - export class DocData { - @observable _user_doc: Doc = undefined!; - @observable _searchQuery: string = ""; - } - - // the document containing the view layout information - will be the Document itself unless the Document has - // a layout field or 'layout' is given. - export function Layout(doc: Doc, layout?: Doc): Doc { - const overrideLayout = layout && Cast(doc[`${StrCast(layout.isTemplateForField, "data")}-layout[` + layout[Id] + "]"], Doc, null); - return overrideLayout || doc[LayoutSym] || doc; - } - export function SetLayout(doc: Doc, layout: Doc | string) { doc[StrCast(doc.layoutKey, "layout")] = layout; } - export function LayoutField(doc: Doc) { return doc[StrCast(doc.layoutKey, "layout")]; } - export function LayoutFieldKey(doc: Doc): string { return StrCast(Doc.Layout(doc).layout).split("'")[1]; } - const manager = new DocData(); - export function SearchQuery(): string { return manager._searchQuery; } - export function SetSearchQuery(query: string) { runInAction(() => manager._searchQuery = query); } - export function UserDoc(): Doc { return manager._user_doc; } - export function SetUserDoc(doc: Doc) { manager._user_doc = doc; } - export function IsBrushed(doc: Doc) { - return computedFn(function IsBrushed(doc: Doc) { - return brushManager.BrushedDoc.has(doc) || brushManager.BrushedDoc.has(Doc.GetProto(doc)); - })(doc); - } - // don't bother memoizing (caching) the result if called from a non-reactive context. (plus this avoids a warning message) - export function IsBrushedDegreeUnmemoized(doc: Doc) { - return brushManager.BrushedDoc.has(doc) ? 2 : brushManager.BrushedDoc.has(Doc.GetProto(doc)) ? 1 : 0; - } - export function IsBrushedDegree(doc: Doc) { - return computedFn(function IsBrushDegree(doc: Doc) { - return Doc.IsBrushedDegreeUnmemoized(doc); - })(doc); - } - export function BrushDoc(doc: Doc) { - brushManager.BrushedDoc.set(doc, true); - brushManager.BrushedDoc.set(Doc.GetProto(doc), true); - return doc; - } - export function UnBrushDoc(doc: Doc) { - brushManager.BrushedDoc.delete(doc); - brushManager.BrushedDoc.delete(Doc.GetProto(doc)); - return doc; - } - - - export function LinkOtherAnchor(linkDoc: Doc, anchorDoc: Doc) { return Doc.AreProtosEqual(anchorDoc, Cast(linkDoc.anchor1, Doc) as Doc) ? Cast(linkDoc.anchor2, Doc) as Doc : Cast(linkDoc.anchor1, Doc) as Doc; } - export function LinkEndpoint(linkDoc: Doc, anchorDoc: Doc) { return Doc.AreProtosEqual(anchorDoc, Cast(linkDoc.anchor1, Doc) as Doc) ? "1" : "2"; } - - export function linkFollowUnhighlight() { - Doc.UnhighlightAll(); - document.removeEventListener("pointerdown", linkFollowUnhighlight); - } - - let _lastDate = 0; - export function linkFollowHighlight(destDoc: Doc, dataAndDisplayDocs = true) { - linkFollowUnhighlight(); - Doc.HighlightDoc(destDoc, dataAndDisplayDocs); - document.removeEventListener("pointerdown", linkFollowUnhighlight); - document.addEventListener("pointerdown", linkFollowUnhighlight); - const lastDate = _lastDate = Date.now(); - window.setTimeout(() => _lastDate === lastDate && linkFollowUnhighlight(), 5000); - } - - export class HighlightBrush { - @observable HighlightedDoc: Map = new Map(); - } - const highlightManager = new HighlightBrush(); - export function IsHighlighted(doc: Doc) { - return highlightManager.HighlightedDoc.get(doc) || highlightManager.HighlightedDoc.get(Doc.GetProto(doc)); - } - export function HighlightDoc(doc: Doc, dataAndDisplayDocs = true) { - runInAction(() => { - highlightManager.HighlightedDoc.set(doc, true); - dataAndDisplayDocs && highlightManager.HighlightedDoc.set(Doc.GetProto(doc), true); - }); - } - export function UnHighlightDoc(doc: Doc) { - runInAction(() => { - highlightManager.HighlightedDoc.set(doc, false); - highlightManager.HighlightedDoc.set(Doc.GetProto(doc), false); - }); - } - export function UnhighlightAll() { - const mapEntries = highlightManager.HighlightedDoc.keys(); - let docEntry: IteratorResult; - while (!(docEntry = mapEntries.next()).done) { - const targetDoc = docEntry.value; - targetDoc && Doc.UnHighlightDoc(targetDoc); - } - - } - export function UnBrushAllDocs() { - brushManager.BrushedDoc.clear(); - } - - export function getDocTemplate(doc?: Doc) { - return doc?.isTemplateDoc ? doc : - Cast(doc?.dragFactory, Doc, null)?.isTemplateDoc ? doc?.dragFactory : - Cast(doc?.layout, Doc, null)?.isTemplateDoc ? doc?.layout : undefined; - } - - export function matchFieldValue(doc: Doc, key: string, value: any): boolean { - const fieldVal = doc[key]; - if (Cast(fieldVal, listSpec("string"), []).length) { - const vals = Cast(fieldVal, listSpec("string"), []); - return vals.some(v => v === value); - } - const fieldStr = Field.toString(fieldVal as Field); - return fieldStr === value; - } - - export function deiconifyView(doc: any) { - StrCast(doc.layoutKey).split("_")[1] === "icon" && setNativeView(doc); - } - - export function setNativeView(doc: any) { - const prevLayout = StrCast(doc.layoutKey).split("_")[1]; - const deiconify = prevLayout === "icon" && StrCast(doc.deiconifyLayout) ? "layout_" + StrCast(doc.deiconifyLayout) : ""; - prevLayout === "icon" && (doc.deiconifyLayout = undefined); - doc.layoutKey = deiconify || "layout"; - } - export function setDocFilterRange(target: Doc, key: string, range?: number[]) { - const docRangeFilters = Cast(target._docRangeFilters, listSpec("string"), []); - for (let i = 0; i < docRangeFilters.length; i += 3) { - if (docRangeFilters[i] === key) { - docRangeFilters.splice(i, 3); - break; - } - } - if (range !== undefined) { - docRangeFilters.push(key); - docRangeFilters.push(range[0].toString()); - docRangeFilters.push(range[1].toString()); - target._docRangeFilters = new List(docRangeFilters); - } - } - - export function aliasDocs(field: any) { - return new List(field.map((d: any) => Doc.MakeAlias(d))); - } - - // filters document in a container collection: - // all documents with the specified value for the specified key are included/excluded - // based on the modifiers :"check", "x", undefined - export function setDocFilter(container: Doc, key: string, value: any, modifiers?: "check" | "x" | undefined) { - const docFilters = Cast(container._docFilters, listSpec("string"), []); - for (let i = 0; i < docFilters.length; i += 3) { - if (docFilters[i] === key && docFilters[i + 1] === value) { - docFilters.splice(i, 3); - break; - } - } - if (typeof modifiers === "string") { - docFilters.push(key); - docFilters.push(value); - docFilters.push(modifiers); - container._docFilters = new List(docFilters); - } - } - export function readDocRangeFilter(doc: Doc, key: string) { - const docRangeFilters = Cast(doc._docRangeFilters, listSpec("string"), []); - for (let i = 0; i < docRangeFilters.length; i += 3) { - if (docRangeFilters[i] === key) { - return [Number(docRangeFilters[i + 1]), Number(docRangeFilters[i + 2])]; - } - } - } - export function assignDocToField(doc: Doc, field: string, id: string) { - DocServer.GetRefField(id).then(layout => layout instanceof Doc && (doc[field] = layout)); - return id; - } - - export function toggleNativeDimensions(layoutDoc: Doc, contentScale: number, panelWidth: number, panelHeight: number) { - runInAction(() => { - if (layoutDoc._nativeWidth || layoutDoc._nativeHeight) { - layoutDoc.scale = NumCast(layoutDoc.scale, 1) * contentScale; - layoutDoc._nativeWidth = undefined; - layoutDoc._nativeHeight = undefined; - } - else { - layoutDoc._autoHeight = false; - if (!layoutDoc._nativeWidth) { - layoutDoc._nativeWidth = NumCast(layoutDoc._width, panelWidth); - layoutDoc._nativeHeight = NumCast(layoutDoc._height, panelHeight); - } - } - }); - } - - export function isDocPinned(doc: Doc) { - //add this new doc to props.Document - const curPres = Cast(Doc.UserDoc().activePresentation, Doc) as Doc; - if (curPres) { - return DocListCast(curPres.data).findIndex((val) => Doc.AreProtosEqual(val, doc)) !== -1; - } - return false; - } - - // 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, options: DocumentOptions, id?: string) => Doc>, templateSignature: string = "custom", docLayoutTemplate?: Doc) { - const batch = UndoManager.StartBatch("makeCustomViewClicked"); - runInAction(() => { - doc.layoutKey = "layout_" + templateSignature; - if (doc[doc.layoutKey] === undefined) { - createCustomView(doc, creator, templateSignature, docLayoutTemplate); - } - }); - batch.end(); - } - export function findTemplate(templateName: string, type: string, signature: string) { - let docLayoutTemplate: Opt; - const iconViews = DocListCast(Cast(Doc.UserDoc()["template-icons"], Doc, null)?.data); - const templBtns = DocListCast(Cast(Doc.UserDoc()["template-buttons"], Doc, null)?.data); - const noteTypes = DocListCast(Cast(Doc.UserDoc()["template-notes"], Doc, null)?.data); - const clickFuncs = DocListCast(Cast(Doc.UserDoc().clickFuncs, Doc, null)?.data); - const allTemplates = iconViews.concat(templBtns).concat(noteTypes).concat(clickFuncs).map(btnDoc => (btnDoc.dragFactory as Doc) || btnDoc).filter(doc => doc.isTemplateDoc); - // bcz: this is hacky -- want to have different templates be applied depending on the "type" of a document. but type is not reliable and there could be other types of template searches so this should be generalized - // first try to find a template that matches the specific document type (_). otherwise, fallback to a general match on - !docLayoutTemplate && allTemplates.forEach(tempDoc => StrCast(tempDoc.title) === templateName + "_" + type && (docLayoutTemplate = tempDoc)); - !docLayoutTemplate && allTemplates.forEach(tempDoc => StrCast(tempDoc.title) === templateName && (docLayoutTemplate = tempDoc)); - return docLayoutTemplate; - } - export function createCustomView(doc: Doc, creator: Opt<(documents: Array, options: DocumentOptions, id?: string) => Doc>, templateSignature: string = "custom", docLayoutTemplate?: Doc) { - const templateName = templateSignature.replace(/\(.*\)/, ""); - docLayoutTemplate = docLayoutTemplate || findTemplate(templateName, StrCast(doc.type), templateSignature); - - const customName = "layout_" + templateSignature; - const _width = NumCast(doc._width); - const _height = NumCast(doc._height); - const options = { title: "data", backgroundColor: StrCast(doc.backgroundColor), _autoHeight: true, _width, x: -_width / 2, y: - _height / 2, _showSidebar: false }; - - let fieldTemplate: Opt; - if (doc.data instanceof RichTextField || typeof (doc.data) === "string") { - fieldTemplate = Docs.Create.TextDocument("", options); - } else if (doc.data instanceof PdfField) { - fieldTemplate = Docs.Create.PdfDocument("http://www.msn.com", options); - } else if (doc.data instanceof VideoField) { - fieldTemplate = Docs.Create.VideoDocument("http://www.cs.brown.edu", options); - } else if (doc.data instanceof AudioField) { - fieldTemplate = Docs.Create.AudioDocument("http://www.cs.brown.edu", options); - } else if (doc.data instanceof ImageField) { - fieldTemplate = Docs.Create.ImageDocument("http://www.cs.brown.edu", options); - } - const docTemplate = docLayoutTemplate || creator?.(fieldTemplate ? [fieldTemplate] : [], { title: customName + "(" + doc.title + ")", isTemplateDoc: true, _width: _width + 20, _height: Math.max(100, _height + 45) }); - - fieldTemplate && Doc.MakeMetadataFieldTemplate(fieldTemplate, docTemplate ? Doc.GetProto(docTemplate) : docTemplate); - docTemplate && Doc.ApplyTemplateTo(docTemplate, doc, customName, undefined); - } - export function makeCustomView(doc: Doc, custom: boolean, layout: string) { - Doc.setNativeView(doc); - if (custom) { - makeCustomViewClicked(doc, Docs.Create.StackingDocument, layout, undefined); - } - } - export function iconify(doc: Doc) { - const layoutKey = Cast(doc.layoutKey, "string", null); - Doc.makeCustomViewClicked(doc, Docs.Create.StackingDocument, "icon", undefined); - if (layoutKey && layoutKey !== "layout" && layoutKey !== "layout_icon") doc.deiconifyLayout = layoutKey.replace("layout_", ""); - } - - export function pileup(selected: Doc[], x: number, y: number) { - const newCollection = Docs.Create.PileDocument(selected, { title: "pileup", x: x - 55, y: y - 55, _width: 110, _height: 100, _LODdisable: true }); - let w = 0, h = 0; - selected.forEach((d, i) => { - Doc.iconify(d); - w = Math.max(d[WidthSym](), w); - h = Math.max(d[HeightSym](), h); - }); - h = Math.max(h, w * 4 / 3); // converting to an icon does not update the height right away. so this is a fallback hack to try to do something reasonable - selected.forEach((d, i) => { - d.x = Math.cos(Math.PI * 2 * i / selected.length) * 10 - w / 2; - d.y = Math.sin(Math.PI * 2 * i / selected.length) * 10 - h / 2; - d.displayTimecode = undefined; // bcz: this should be automatic somehow.. along with any other properties that were logically associated with the original collection - }); - newCollection.x = NumCast(newCollection.x) + NumCast(newCollection._width) / 2 - 55; - newCollection.y = NumCast(newCollection.y) + NumCast(newCollection._height) / 2 - 55; - newCollection._width = newCollection._height = 110; - //newCollection.borderRounding = "40px"; - newCollection._jitterRotation = 10; - newCollection._backgroundColor = "gray"; - newCollection._overflow = "visible"; - return newCollection; - } - - - export async function addFieldEnumerations(doc: Opt, enumeratedFieldKey: string, enumerations: { title: string, _backgroundColor?: string, color?: string }[]) { - let optionsCollection = await DocServer.GetRefField(enumeratedFieldKey); - if (!(optionsCollection instanceof Doc)) { - optionsCollection = Docs.Create.StackingDocument([], { title: `${enumeratedFieldKey} field set` }, enumeratedFieldKey); - Doc.AddDocToList((Doc.UserDoc().fieldTypes as Doc), "data", optionsCollection as Doc); - } - const options = optionsCollection as Doc; - const targetDoc = doc && Doc.GetProto(Cast(doc.rootDocument, Doc, null) || doc); - const docFind = `options.data.find(doc => doc.title === (this.rootDocument||this)["${enumeratedFieldKey}"])?`; - targetDoc && (targetDoc.backgroundColor = ComputedField.MakeFunction(docFind + `._backgroundColor || "white"`, undefined, { options })); - targetDoc && (targetDoc.color = ComputedField.MakeFunction(docFind + `.color || "black"`, undefined, { options })); - targetDoc && (targetDoc.borderRounding = ComputedField.MakeFunction(docFind + `.borderRounding`, undefined, { options })); - enumerations.map(enumeration => { - const found = DocListCast(options.data).find(d => d.title === enumeration.title); - if (found) { - found._backgroundColor = enumeration._backgroundColor || found._backgroundColor; - found._color = enumeration.color || found._color; - } else { - Doc.AddDocToList(options, "data", Docs.Create.TextDocument(enumeration.title, enumeration)); - } - }); - return optionsCollection; - } -} - -Scripting.addGlobal(function renameAlias(doc: any, n: any) { return StrCast(Doc.GetProto(doc).title).replace(/\([0-9]*\)/, "") + `(${n})`; }); -Scripting.addGlobal(function getProto(doc: any) { return Doc.GetProto(doc); }); -Scripting.addGlobal(function getDocTemplate(doc?: any) { return Doc.getDocTemplate(doc); }); -Scripting.addGlobal(function getAlias(doc: any) { return Doc.MakeAlias(doc); }); -Scripting.addGlobal(function getCopy(doc: any, copyProto: any) { return doc.isTemplateDoc ? Doc.ApplyTemplate(doc) : Doc.MakeCopy(doc, copyProto); }); -Scripting.addGlobal(function copyField(field: any) { return ObjectField.MakeCopy(field); }); -Scripting.addGlobal(function aliasDocs(field: any) { return Doc.aliasDocs(field); }); -Scripting.addGlobal(function docList(field: any) { return DocListCast(field); }); -Scripting.addGlobal(function setInPlace(doc: any, field: any, value: any) { return Doc.SetInPlace(doc, field, value, false); }); -Scripting.addGlobal(function sameDocs(doc1: any, doc2: any) { return Doc.AreProtosEqual(doc1, doc2); }); -Scripting.addGlobal(function deiconifyView(doc: any) { Doc.deiconifyView(doc); }); -Scripting.addGlobal(function undo() { return UndoManager.Undo(); }); -Scripting.addGlobal(function redo() { return UndoManager.Redo(); }); -Scripting.addGlobal(function DOC(id: string) { console.log("Can't parse a document id in a script"); return "invalid"; }); -Scripting.addGlobal(function assignDoc(doc: Doc, field: string, id: string) { return Doc.assignDocToField(doc, field, id); }); -Scripting.addGlobal(function docCast(doc: FieldResult): any { return DocCastAsync(doc); }); -Scripting.addGlobal(function activePresentationItem() { - const curPres = Doc.UserDoc().activePresentation as Doc; - return curPres && DocListCast(curPres[Doc.LayoutFieldKey(curPres)])[NumCast(curPres._itemIndex)]; -}); -Scripting.addGlobal(function selectDoc(doc: any) { Doc.UserDoc().activeSelection = new List([doc]); }); -Scripting.addGlobal(function selectedDocs(container: Doc, excludeCollections: boolean, prevValue: any) { - const docs = DocListCast(Doc.UserDoc().activeSelection). - filter(d => !Doc.AreProtosEqual(d, container) && !d.annotationOn && d.type !== DocumentType.DOCHOLDER && d.type !== DocumentType.KVP && - (!excludeCollections || d.type !== DocumentType.COL || !Cast(d.data, listSpec(Doc), null))); - return docs.length ? new List(docs) : prevValue; -}); -Scripting.addGlobal(function setDocFilter(container: Doc, key: string, value: any, modifiers?: "check" | "x" | undefined) { Doc.setDocFilter(container, key, value, modifiers); }); -Scripting.addGlobal(function setDocFilterRange(container: Doc, key: string, range: number[]) { Doc.setDocFilterRange(container, key, range); }); \ No newline at end of file diff --git a/src/new_fields/FieldSymbols.ts b/src/new_fields/FieldSymbols.ts deleted file mode 100644 index 8d040f493..000000000 --- a/src/new_fields/FieldSymbols.ts +++ /dev/null @@ -1,12 +0,0 @@ - -export const Update = Symbol("Update"); -export const Self = Symbol("Self"); -export const SelfProxy = Symbol("SelfProxy"); -export const HandleUpdate = Symbol("HandleUpdate"); -export const Id = Symbol("Id"); -export const OnUpdate = Symbol("OnUpdate"); -export const Parent = Symbol("Parent"); -export const Copy = Symbol("Copy"); -export const ToScriptString = Symbol("ToScriptString"); -export const ToPlainText = Symbol("ToPlainText"); -export const ToString = Symbol("ToString"); diff --git a/src/new_fields/HtmlField.ts b/src/new_fields/HtmlField.ts deleted file mode 100644 index 6e8bba977..000000000 --- a/src/new_fields/HtmlField.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { Deserializable } from "../client/util/SerializationHelper"; -import { serializable, primitive } from "serializr"; -import { ObjectField } from "./ObjectField"; -import { Copy, ToScriptString, ToString} from "./FieldSymbols"; - -@Deserializable("html") -export class HtmlField extends ObjectField { - @serializable(primitive()) - readonly html: string; - - constructor(html: string) { - super(); - this.html = html; - } - - [Copy]() { - return new HtmlField(this.html); - } - - [ToScriptString]() { - return "invalid"; - } - [ToString]() { - return this.html; - } -} diff --git a/src/new_fields/IconField.ts b/src/new_fields/IconField.ts deleted file mode 100644 index 76c4ddf1b..000000000 --- a/src/new_fields/IconField.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { Deserializable } from "../client/util/SerializationHelper"; -import { serializable, primitive } from "serializr"; -import { ObjectField } from "./ObjectField"; -import { Copy, ToScriptString, ToString } from "./FieldSymbols"; - -@Deserializable("icon") -export class IconField extends ObjectField { - @serializable(primitive()) - readonly icon: string; - - constructor(icon: string) { - super(); - this.icon = icon; - } - - [Copy]() { - return new IconField(this.icon); - } - - [ToScriptString]() { - return "invalid"; - } - [ToString]() { - return "ICONfield"; - } -} diff --git a/src/new_fields/InkField.ts b/src/new_fields/InkField.ts deleted file mode 100644 index bb93de5ac..000000000 --- a/src/new_fields/InkField.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { Deserializable } from "../client/util/SerializationHelper"; -import { serializable, custom, createSimpleSchema, list, object, map } from "serializr"; -import { ObjectField } from "./ObjectField"; -import { Copy, ToScriptString, ToString } from "./FieldSymbols"; - -export enum InkTool { - None, - Pen, - Highlighter, - Eraser, - Stamp -} - -export interface PointData { - X: number; - Y: number; -} - -export type InkData = Array; - -const pointSchema = createSimpleSchema({ - X: true, Y: true -}); - -const strokeDataSchema = createSimpleSchema({ - pathData: list(object(pointSchema)), - "*": true -}); - -@Deserializable("ink") -export class InkField extends ObjectField { - @serializable(list(object(strokeDataSchema))) - readonly inkData: InkData; - - constructor(data: InkData) { - super(); - this.inkData = data; - } - - [Copy]() { - return new InkField(this.inkData); - } - - [ToScriptString]() { - return "invalid"; - } - [ToString]() { - return "InkField"; - } -} diff --git a/src/new_fields/List.ts b/src/new_fields/List.ts deleted file mode 100644 index fdabea365..000000000 --- a/src/new_fields/List.ts +++ /dev/null @@ -1,330 +0,0 @@ -import { Deserializable, autoObject, afterDocDeserialize } from "../client/util/SerializationHelper"; -import { Field } from "./Doc"; -import { setter, getter, deleteProperty, updateFunction } from "./util"; -import { serializable, alias, list } from "serializr"; -import { observable, action, runInAction } from "mobx"; -import { ObjectField } from "./ObjectField"; -import { RefField } from "./RefField"; -import { ProxyField } from "./Proxy"; -import { Self, Update, Parent, OnUpdate, SelfProxy, ToScriptString, ToString, Copy, Id } from "./FieldSymbols"; -import { Scripting } from "../client/util/Scripting"; -import { DocServer } from "../client/DocServer"; - -const listHandlers: any = { - /// Mutator methods - copyWithin() { - throw new Error("copyWithin not supported yet"); - }, - fill(value: any, start?: number, end?: number) { - if (value instanceof RefField) { - throw new Error("fill with RefFields not supported yet"); - } - const res = this[Self].__fields.fill(value, start, end); - this[Update](); - return res; - }, - pop(): any { - const field = toRealField(this[Self].__fields.pop()); - this[Update](); - return field; - }, - push: action(function (this: any, ...items: any[]) { - items = items.map(toObjectField); - const list = this[Self]; - const length = list.__fields.length; - for (let i = 0; i < items.length; i++) { - const item = items[i]; - //TODO Error checking to make sure parent doesn't already exist - if (item instanceof ObjectField) { - item[Parent] = list; - item[OnUpdate] = updateFunction(list, i + length, item, this); - } - } - const res = list.__fields.push(...items); - this[Update](); - return res; - }), - reverse() { - const res = this[Self].__fields.reverse(); - this[Update](); - return res; - }, - shift() { - const res = toRealField(this[Self].__fields.shift()); - this[Update](); - return res; - }, - sort(cmpFunc: any) { - this[Self].__realFields(); // coerce retrieving entire array - const res = this[Self].__fields.sort(cmpFunc ? (first: any, second: any) => cmpFunc(toRealField(first), toRealField(second)) : undefined); - this[Update](); - return res; - }, - splice: action(function (this: any, start: number, deleteCount: number, ...items: any[]) { - this[Self].__realFields(); // coerce retrieving entire array - items = items.map(toObjectField); - const list = this[Self]; - for (let i = 0; i < items.length; i++) { - const item = items[i]; - //TODO Error checking to make sure parent doesn't already exist - //TODO Need to change indices of other fields in array - if (item instanceof ObjectField) { - item[Parent] = list; - item[OnUpdate] = updateFunction(list, i + start, item, this); - } - } - const res = list.__fields.splice(start, deleteCount, ...items); - this[Update](); - return res.map(toRealField); - }), - unshift(...items: any[]) { - items = items.map(toObjectField); - const list = this[Self]; - const length = list.__fields.length; - for (let i = 0; i < items.length; i++) { - const item = items[i]; - //TODO Error checking to make sure parent doesn't already exist - //TODO Need to change indices of other fields in array - if (item instanceof ObjectField) { - item[Parent] = list; - item[OnUpdate] = updateFunction(list, i, item, this); - } - } - const res = this[Self].__fields.unshift(...items); - this[Update](); - return res; - - }, - /// Accessor methods - concat: action(function (this: any, ...items: any[]) { - this[Self].__realFields(); - return this[Self].__fields.map(toRealField).concat(...items); - }), - includes(valueToFind: any, fromIndex: number) { - if (valueToFind instanceof RefField) { - return this[Self].__realFields().includes(valueToFind, fromIndex); - } else { - return this[Self].__fields.includes(valueToFind, fromIndex); - } - }, - indexOf(valueToFind: any, fromIndex: number) { - if (valueToFind instanceof RefField) { - return this[Self].__realFields().indexOf(valueToFind, fromIndex); - } else { - return this[Self].__fields.indexOf(valueToFind, fromIndex); - } - }, - join(separator: any) { - this[Self].__realFields(); - return this[Self].__fields.map(toRealField).join(separator); - }, - lastIndexOf(valueToFind: any, fromIndex: number) { - if (valueToFind instanceof RefField) { - return this[Self].__realFields().lastIndexOf(valueToFind, fromIndex); - } else { - return this[Self].__fields.lastIndexOf(valueToFind, fromIndex); - } - }, - slice(begin: number, end: number) { - this[Self].__realFields(); - return this[Self].__fields.slice(begin, end).map(toRealField); - }, - - /// Iteration methods - entries() { - return this[Self].__realFields().entries(); - }, - every(callback: any, thisArg: any) { - return this[Self].__realFields().every(callback, thisArg); - // TODO This is probably more efficient, but technically the callback can take the array, which would mean we would have to map the actual array anyway. - // If we don't want to support the array parameter, we should use this version instead - // return this[Self].__fields.every((element:any, index:number, array:any) => callback(toRealField(element), index, array), thisArg); - }, - filter(callback: any, thisArg: any) { - return this[Self].__realFields().filter(callback, thisArg); - // TODO This is probably more efficient, but technically the callback can take the array, which would mean we would have to map the actual array anyway. - // If we don't want to support the array parameter, we should use this version instead - // return this[Self].__fields.filter((element:any, index:number, array:any) => callback(toRealField(element), index, array), thisArg); - }, - find(callback: any, thisArg: any) { - return this[Self].__realFields().find(callback, thisArg); - // TODO This is probably more efficient, but technically the callback can take the array, which would mean we would have to map the actual array anyway. - // If we don't want to support the array parameter, we should use this version instead - // return this[Self].__fields.find((element:any, index:number, array:any) => callback(toRealField(element), index, array), thisArg); - }, - findIndex(callback: any, thisArg: any) { - return this[Self].__realFields().findIndex(callback, thisArg); - // TODO This is probably more efficient, but technically the callback can take the array, which would mean we would have to map the actual array anyway. - // If we don't want to support the array parameter, we should use this version instead - // return this[Self].__fields.findIndex((element:any, index:number, array:any) => callback(toRealField(element), index, array), thisArg); - }, - forEach(callback: any, thisArg: any) { - return this[Self].__realFields().forEach(callback, thisArg); - // TODO This is probably more efficient, but technically the callback can take the array, which would mean we would have to map the actual array anyway. - // If we don't want to support the array parameter, we should use this version instead - // return this[Self].__fields.forEach((element:any, index:number, array:any) => callback(toRealField(element), index, array), thisArg); - }, - map(callback: any, thisArg: any) { - return this[Self].__realFields().map(callback, thisArg); - // TODO This is probably more efficient, but technically the callback can take the array, which would mean we would have to map the actual array anyway. - // If we don't want to support the array parameter, we should use this version instead - // return this[Self].__fields.map((element:any, index:number, array:any) => callback(toRealField(element), index, array), thisArg); - }, - reduce(callback: any, initialValue: any) { - return this[Self].__realFields().reduce(callback, initialValue); - // TODO This is probably more efficient, but technically the callback can take the array, which would mean we would have to map the actual array anyway. - // If we don't want to support the array parameter, we should use this version instead - // return this[Self].__fields.reduce((acc:any, element:any, index:number, array:any) => callback(acc, toRealField(element), index, array), initialValue); - }, - reduceRight(callback: any, initialValue: any) { - return this[Self].__realFields().reduceRight(callback, initialValue); - // TODO This is probably more efficient, but technically the callback can take the array, which would mean we would have to map the actual array anyway. - // If we don't want to support the array parameter, we should use this version instead - // return this[Self].__fields.reduceRight((acc:any, element:any, index:number, array:any) => callback(acc, toRealField(element), index, array), initialValue); - }, - some(callback: any, thisArg: any) { - return this[Self].__realFields().some(callback, thisArg); - // TODO This is probably more efficient, but technically the callback can take the array, which would mean we would have to map the actual array anyway. - // If we don't want to support the array parameter, we should use this version instead - // return this[Self].__fields.some((element:any, index:number, array:any) => callback(toRealField(element), index, array), thisArg); - }, - values() { - return this[Self].__realFields().values(); - }, - [Symbol.iterator]() { - return this[Self].__realFields().values(); - } -}; - -function toObjectField(field: Field) { - return field instanceof RefField ? new ProxyField(field) : field; -} - -function toRealField(field: Field) { - return field instanceof ProxyField ? field.value() : field; -} - -function listGetter(target: any, prop: string | number | symbol, receiver: any): any { - if (listHandlers.hasOwnProperty(prop)) { - return listHandlers[prop]; - } - return getter(target, prop, receiver); -} - -interface ListSpliceUpdate { - type: "splice"; - index: number; - added: T[]; - removedCount: number; -} - -interface ListIndexUpdate { - type: "update"; - index: number; - newValue: T; -} - -type ListUpdate = ListSpliceUpdate | ListIndexUpdate; - -type StoredType = T extends RefField ? ProxyField : T; - -@Deserializable("list") -class ListImpl extends ObjectField { - constructor(fields?: T[]) { - super(); - const list = new Proxy(this, { - set: setter, - get: listGetter, - ownKeys: target => Object.keys(target.__fields), - getOwnPropertyDescriptor: (target, prop) => { - if (prop in target.__fields) { - return { - configurable: true,//TODO Should configurable be true? - enumerable: true, - }; - } - return Reflect.getOwnPropertyDescriptor(target, prop); - }, - deleteProperty: deleteProperty, - defineProperty: () => { throw new Error("Currently properties can't be defined on documents using Object.defineProperty"); }, - }); - this[SelfProxy] = list; - if (fields) { - (list as any).push(...fields); - } - return list; - } - - [key: number]: T | (T extends RefField ? Promise : never); - - // this requests all ProxyFields at the same time to avoid the overhead - // of separate network requests and separate updates to the React dom. - private __realFields() { - const waiting = this.__fields.filter(f => f instanceof ProxyField && f.promisedValue()); - const promised = waiting.map(f => f instanceof ProxyField ? f.promisedValue() : ""); - // if we find any ProxyFields that don't have a current value, then - // start the server request for all of them - if (promised.length) { - const promise = DocServer.GetRefFields(promised); - // as soon as we get the fields from the server, set all the list values in one - // action to generate one React dom update. - promise.then(fields => runInAction(() => { - waiting.map((w, i) => w instanceof ProxyField && w.setValue(fields[promised[i]])); - })); - // we also have to mark all lists items with this promise so that any calls to them - // will await the batch request. - // This counts on the handler for 'promise' in the call above being invoked before the - // handler for 'promise' in the lines below. - waiting.map((w, i) => { - w instanceof ProxyField && w.setPromise(promise.then(fields => fields[promised[i]])); - }); - } - return this.__fields.map(toRealField); - } - - @serializable(alias("fields", list(autoObject(), { afterDeserialize: afterDocDeserialize }))) - private get __fields() { - return this.___fields; - } - - private set __fields(value) { - this.___fields = value; - for (const key in value) { - const field = value[key]; - if (!(field instanceof ObjectField)) continue; - (field as ObjectField)[Parent] = this[Self]; - (field as ObjectField)[OnUpdate] = updateFunction(this[Self], key, field, this[SelfProxy]); - } - } - - [Copy]() { - const copiedData = this[Self].__fields.map(f => f instanceof ObjectField ? f[Copy]() : f); - const deepCopy = new ListImpl(copiedData as any); - return deepCopy; - } - - // @serializable(alias("fields", list(autoObject()))) - @observable - private ___fields: StoredType[] = []; - - private [Update] = (diff: any) => { - // console.log(diff); - const update = this[OnUpdate]; - // update && update(diff); - update?.(); - } - - private [Self] = this; - private [SelfProxy]: any; - - [ToScriptString]() { - return `new List([${(this as any).map((field: any) => Field.toScriptString(field))}])`; - } - [ToString]() { - return "List"; - } -} -export type List = ListImpl & (T | (T extends RefField ? Promise : never))[]; -export const List: { new (fields?: T[]): List } = ListImpl as any; - -Scripting.addGlobal("List", List); \ No newline at end of file diff --git a/src/new_fields/ListSpec.ts b/src/new_fields/ListSpec.ts deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/new_fields/ObjectField.ts b/src/new_fields/ObjectField.ts deleted file mode 100644 index 9aa1c9b04..000000000 --- a/src/new_fields/ObjectField.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { RefField } from "./RefField"; -import { OnUpdate, Parent, Copy, ToScriptString, ToString } from "./FieldSymbols"; -import { Scripting } from "../client/util/Scripting"; - -export abstract class ObjectField { - protected [OnUpdate](diff?: any) { } - private [Parent]?: RefField | ObjectField; - abstract [Copy](): ObjectField; - - abstract [ToScriptString](): string; - abstract [ToString](): string; -} - -export namespace ObjectField { - export function MakeCopy(field: T) { - return field?.[Copy](); - } -} - -Scripting.addGlobal(ObjectField); \ No newline at end of file diff --git a/src/new_fields/PresField.ts b/src/new_fields/PresField.ts deleted file mode 100644 index f236a04fd..000000000 --- a/src/new_fields/PresField.ts +++ /dev/null @@ -1,6 +0,0 @@ -//insert code here -import { ObjectField } from "./ObjectField"; - -export abstract class PresField extends ObjectField { - -} \ No newline at end of file diff --git a/src/new_fields/Proxy.ts b/src/new_fields/Proxy.ts deleted file mode 100644 index 555faaad0..000000000 --- a/src/new_fields/Proxy.ts +++ /dev/null @@ -1,126 +0,0 @@ -import { Deserializable } from "../client/util/SerializationHelper"; -import { FieldWaiting } from "./Doc"; -import { primitive, serializable } from "serializr"; -import { observable, action, runInAction } from "mobx"; -import { DocServer } from "../client/DocServer"; -import { RefField } from "./RefField"; -import { ObjectField } from "./ObjectField"; -import { Id, Copy, ToScriptString, ToString } from "./FieldSymbols"; -import { scriptingGlobal } from "../client/util/Scripting"; -import { Plugins } from "./util"; - -@Deserializable("proxy") -export class ProxyField extends ObjectField { - constructor(); - constructor(value: T); - constructor(fieldId: string); - constructor(value?: T | string) { - super(); - if (typeof value === "string") { - this.fieldId = value; - } else if (value) { - this.cache = value; - this.fieldId = value[Id]; - } - } - - [Copy]() { - if (this.cache) return new ProxyField(this.cache); - return new ProxyField(this.fieldId); - } - - [ToScriptString]() { - return "invalid"; - } - [ToString]() { - return "ProxyField"; - } - - @serializable(primitive()) - readonly fieldId: string = ""; - - // This getter/setter and nested object thing is - // because mobx doesn't play well with observable proxies - @observable.ref - private _cache: { readonly field: T | undefined } = { field: undefined }; - private get cache(): T | undefined { - return this._cache.field; - } - private set cache(field: T | undefined) { - this._cache = { field }; - } - - private failed = false; - private promise?: Promise; - - value(): T | undefined | FieldWaiting { - if (this.cache) { - return this.cache; - } - if (this.failed) { - return undefined; - } - if (!this.promise) { - const cached = DocServer.GetCachedRefField(this.fieldId); - if (cached !== undefined) { - runInAction(() => this.cache = cached as any); - return cached as any; - } - this.promise = DocServer.GetRefField(this.fieldId).then(action((field: any) => { - this.promise = undefined; - this.cache = field; - if (field === undefined) this.failed = true; - return field; - })); - } - return this.promise as any; - } - promisedValue(): string { return !this.cache && !this.failed && !this.promise ? this.fieldId : ""; } - setPromise(promise: any) { - this.promise = promise; - } - @action - setValue(field: any) { - this.promise = undefined; - this.cache = field; - if (field === undefined) this.failed = true; - return field; - } -} - -export namespace ProxyField { - let useProxy = true; - export function DisableProxyFields() { - useProxy = false; - } - - export function EnableProxyFields() { - useProxy = true; - } - - export function WithoutProxy(fn: () => T) { - DisableProxyFields(); - try { - return fn(); - } finally { - EnableProxyFields(); - } - } - - export function initPlugin() { - Plugins.addGetterPlugin((doc, _, value) => { - if (useProxy && value instanceof ProxyField) { - return { value: value.value() }; - } - }); - } -} - -function prefetchValue(proxy: PrefetchProxy) { - return proxy.value() as any; -} - -@scriptingGlobal -@Deserializable("prefetch_proxy", prefetchValue) -export class PrefetchProxy extends ProxyField { -} diff --git a/src/new_fields/RefField.ts b/src/new_fields/RefField.ts deleted file mode 100644 index b6ef69750..000000000 --- a/src/new_fields/RefField.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { serializable, primitive, alias } from "serializr"; -import { Utils } from "../Utils"; -import { Id, HandleUpdate, ToScriptString, ToString } from "./FieldSymbols"; -import { afterDocDeserialize } from "../client/util/SerializationHelper"; - -export type FieldId = string; -export abstract class RefField { - @serializable(alias("id", primitive({ afterDeserialize: afterDocDeserialize }))) - private __id: FieldId; - readonly [Id]: FieldId; - - constructor(id?: FieldId) { - this.__id = id || Utils.GenerateGuid(); - this[Id] = this.__id; - } - - protected [HandleUpdate]?(diff: any): void | Promise; - - abstract [ToScriptString](): string; - abstract [ToString](): string; -} diff --git a/src/new_fields/RichTextField.ts b/src/new_fields/RichTextField.ts deleted file mode 100644 index 5cf0e0cc3..000000000 --- a/src/new_fields/RichTextField.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { ObjectField } from "./ObjectField"; -import { serializable } from "serializr"; -import { Deserializable } from "../client/util/SerializationHelper"; -import { Copy, ToScriptString, ToPlainText, ToString } from "./FieldSymbols"; -import { scriptingGlobal } from "../client/util/Scripting"; - -@scriptingGlobal -@Deserializable("RichTextField") -export class RichTextField extends ObjectField { - @serializable(true) - readonly Data: string; - - @serializable(true) - readonly Text: string; - - constructor(data: string, text: string = "") { - super(); - this.Data = data; - this.Text = text; - } - - Empty() { - return !(this.Text || this.Data.toString().includes("dashField")); - } - - [Copy]() { - return new RichTextField(this.Data, this.Text); - } - - [ToScriptString]() { - return `new RichTextField("${this.Data}", "${this.Text}")`; - } - [ToString]() { - return this.Text; - } - - public static DashField(fieldKey: string) { - return new RichTextField(`{"doc":{"type":"doc","content":[{"type":"paragraph","attrs":{"align":null,"color":null,"id":null,"indent":null,"inset":null,"lineSpacing":null,"paddingBottom":null,"paddingTop":null},"content":[{"type":"dashField","attrs":{"fieldKey":"${fieldKey}","docid":""}}]}]},"selection":{"type":"text","anchor":2,"head":2},"storedMarks":[]}`, ""); - } - -} \ No newline at end of file diff --git a/src/new_fields/RichTextUtils.ts b/src/new_fields/RichTextUtils.ts deleted file mode 100644 index c475d0d73..000000000 --- a/src/new_fields/RichTextUtils.ts +++ /dev/null @@ -1,519 +0,0 @@ -import { AssertionError } from "assert"; -import { docs_v1 } from "googleapis"; -import { Fragment, Mark, Node } from "prosemirror-model"; -import { sinkListItem } from "prosemirror-schema-list"; -import { Utils } from "../Utils"; -import { Docs } from "../client/documents/Documents"; -import { schema } from "../client/views/nodes/formattedText/schema_rts"; -import { GooglePhotos } from "../client/apis/google_docs/GooglePhotosClientUtils"; -import { DocServer } from "../client/DocServer"; -import { Networking } from "../client/Network"; -import { FormattedTextBox } from "../client/views/nodes/formattedText/FormattedTextBox"; -import { Doc, Opt } from "./Doc"; -import { Id } from "./FieldSymbols"; -import { RichTextField } from "./RichTextField"; -import { Cast, StrCast } from "./Types"; -import Color = require('color'); -import { EditorState, TextSelection, Transaction } from "prosemirror-state"; -import { GoogleApiClientUtils } from "../client/apis/google_docs/GoogleApiClientUtils"; - -export namespace RichTextUtils { - - const delimiter = "\n"; - const joiner = ""; - - - export const Initialize = (initial?: string) => { - const content: any[] = []; - const state = { - doc: { - type: "doc", - content, - }, - selection: { - type: "text", - anchor: 0, - head: 0 - } - }; - if (initial && initial.length) { - content.push({ - type: "paragraph", - content: { - type: "text", - text: initial - } - }); - state.selection.anchor = state.selection.head = initial.length + 1; - } - return JSON.stringify(state); - }; - - export const Synthesize = (plainText: string, oldState?: RichTextField) => { - return new RichTextField(ToProsemirrorState(plainText, oldState), plainText); - }; - - export const ToPlainText = (state: EditorState) => { - // Because we're working with plain text, just concatenate all paragraphs - const content = state.doc.content; - const paragraphs: Node[] = []; - content.forEach(node => node.type.name === "paragraph" && paragraphs.push(node)); - - // Functions to flatten ProseMirror paragraph objects (and their components) to plain text - // Concatentate paragraphs and string the result together - const textParagraphs: string[] = paragraphs.map(paragraph => { - const text: string[] = []; - paragraph.content.forEach(node => node.text && text.push(node.text)); - return text.join(joiner) + delimiter; - }); - const plainText = textParagraphs.join(joiner); - return plainText.substring(0, plainText.length - 1); - }; - - export const ToProsemirrorState = (plainText: string, oldState?: RichTextField) => { - // Remap the text, creating blocks split on newlines - const elements = plainText.split(delimiter); - - // Google Docs adds in an extra carriage return automatically, so this counteracts it - !elements[elements.length - 1].length && elements.pop(); - - // Preserve the current state, but re-write the content to be the blocks - const parsed = JSON.parse(oldState ? oldState.Data : Initialize()); - parsed.doc.content = elements.map(text => { - const paragraph: any = { type: "paragraph" }; - text.length && (paragraph.content = [{ type: "text", marks: [], text }]); // An empty paragraph gets treated as a line break - return paragraph; - }); - - // If the new content is shorter than the previous content and selection is unchanged, may throw an out of bounds exception, so we reset it - parsed.selection = { type: "text", anchor: 1, head: 1 }; - - // Export the ProseMirror-compatible state object we've just built - return JSON.stringify(parsed); - }; - - export namespace GoogleDocs { - - export const Export = async (state: EditorState): Promise => { - const nodes: (Node | null)[] = []; - const text = ToPlainText(state); - state.doc.content.forEach(node => { - if (!node.childCount) { - nodes.push(null); - } else { - node.content.forEach(child => nodes.push(child)); - } - }); - const requests = await marksToStyle(nodes); - return { text, requests }; - }; - - interface ImageTemplate { - width: number; - title: string; - url: string; - agnostic: string; - } - - const parseInlineObjects = async (document: docs_v1.Schema$Document): Promise> => { - const inlineObjectMap = new Map(); - const inlineObjects = document.inlineObjects; - - if (inlineObjects) { - const objects = Object.keys(inlineObjects).map(objectId => inlineObjects[objectId]); - const mediaItems: MediaItem[] = objects.map(object => { - const embeddedObject = object.inlineObjectProperties!.embeddedObject!; - return { baseUrl: embeddedObject.imageProperties!.contentUri! }; - }); - - const uploads = await Networking.PostToServer("/googlePhotosMediaGet", { mediaItems }); - - if (uploads.length !== mediaItems.length) { - throw new AssertionError({ expected: mediaItems.length, actual: uploads.length, message: "Error with internally uploading inlineObjects!" }); - } - - for (let i = 0; i < objects.length; i++) { - const object = objects[i]; - const { accessPaths } = uploads[i]; - const { agnostic, _m } = accessPaths; - const embeddedObject = object.inlineObjectProperties!.embeddedObject!; - const size = embeddedObject.size!; - const width = size.width!.magnitude!; - - inlineObjectMap.set(object.objectId!, { - title: embeddedObject.title || `Imported Image from ${document.title}`, - width, - url: Utils.prepend(_m.client), - agnostic: Utils.prepend(agnostic.client) - }); - } - } - return inlineObjectMap; - }; - - type BulletPosition = { value: number, sinks: number }; - - interface MediaItem { - baseUrl: string; - } - - export const Import = async (documentId: GoogleApiClientUtils.Docs.DocumentId, textNote: Doc): Promise> => { - const document = await GoogleApiClientUtils.Docs.retrieve({ documentId }); - if (!document) { - return undefined; - } - const inlineObjectMap = await parseInlineObjects(document); - const title = document.title!; - const { text, paragraphs } = GoogleApiClientUtils.Docs.Utils.extractText(document); - let state = FormattedTextBox.blankState(); - const structured = parseLists(paragraphs); - - let position = 3; - const lists: ListGroup[] = []; - const indentMap = new Map(); - let globalOffset = 0; - const nodes: Node[] = []; - for (const element of structured) { - if (Array.isArray(element)) { - lists.push(element); - const positions: BulletPosition[] = []; - const items = element.map(paragraph => { - const item = listItem(state.schema, paragraph.contents); - const sinks = paragraph.bullet!; - positions.push({ - value: position + globalOffset, - sinks - }); - position += item.nodeSize; - globalOffset += 2 * sinks; - return item; - }); - indentMap.set(element, positions); - nodes.push(list(state.schema, items)); - } else { - if (element.contents.some(child => "inlineObjectId" in child)) { - const group = element.contents; - group.forEach((child, i) => { - let node: Opt>; - if ("inlineObjectId" in child) { - node = imageNode(state.schema, inlineObjectMap.get(child.inlineObjectId!)!, textNote); - } else if ("content" in child && (i !== group.length - 1 || child.content!.removeTrailingNewlines().length)) { - node = paragraphNode(state.schema, [child]); - } - if (node) { - position += node.nodeSize; - nodes.push(node); - } - }); - } else { - const paragraph = paragraphNode(state.schema, element.contents); - nodes.push(paragraph); - position += paragraph.nodeSize; - } - } - } - state = state.apply(state.tr.replaceWith(0, 2, nodes)); - - const sink = sinkListItem(state.schema.nodes.list_item); - const dispatcher = (tr: Transaction) => state = state.apply(tr); - for (const list of lists) { - for (const pos of indentMap.get(list)!) { - const resolved = state.doc.resolve(pos.value); - state = state.apply(state.tr.setSelection(new TextSelection(resolved))); - for (let i = 0; i < pos.sinks; i++) { - sink(state, dispatcher); - } - } - } - - return { title, text, state }; - }; - - type Paragraph = GoogleApiClientUtils.Docs.Utils.DeconstructedParagraph; - type ListGroup = Paragraph[]; - type PreparedParagraphs = (ListGroup | Paragraph)[]; - - const parseLists = (paragraphs: ListGroup) => { - const groups: PreparedParagraphs = []; - let group: ListGroup = []; - for (const paragraph of paragraphs) { - if (paragraph.bullet !== undefined) { - group.push(paragraph); - } else { - if (group.length) { - groups.push(group); - group = []; - } - groups.push(paragraph); - } - } - group.length && groups.push(group); - return groups; - }; - - const listItem = (schema: any, runs: docs_v1.Schema$TextRun[]): Node => { - return schema.node("list_item", null, paragraphNode(schema, runs)); - }; - - const list = (schema: any, items: Node[]): Node => { - return schema.node("bullet_list", null, items); - }; - - const paragraphNode = (schema: any, runs: docs_v1.Schema$TextRun[]): Node => { - const children = runs.map(run => textNode(schema, run)).filter(child => child !== undefined); - const fragment = children.length ? Fragment.from(children) : undefined; - return schema.node("paragraph", null, fragment); - }; - - const imageNode = (schema: any, image: ImageTemplate, textNote: Doc) => { - const { url: src, width, agnostic } = image; - let docid: string; - const guid = Utils.GenerateDeterministicGuid(agnostic); - const backingDocId = StrCast(textNote[guid]); - if (!backingDocId) { - const backingDoc = Docs.Create.ImageDocument(agnostic, { _width: 300, _height: 300 }); - Doc.makeCustomViewClicked(backingDoc, Docs.Create.FreeformDocument); - docid = backingDoc[Id]; - textNote[guid] = docid; - } else { - docid = backingDocId; - } - return schema.node("image", { src, agnostic, width, docid, float: null, location: "onRight" }); - }; - - const textNode = (schema: any, run: docs_v1.Schema$TextRun) => { - const text = run.content!.removeTrailingNewlines(); - return text.length ? schema.text(text, styleToMarks(schema, run.textStyle)) : undefined; - }; - - const StyleToMark = new Map([ - ["bold", "strong"], - ["italic", "em"], - ["foregroundColor", "pFontColor"], - ["fontSize", "pFontSize"] - ]); - - const styleToMarks = (schema: any, textStyle?: docs_v1.Schema$TextStyle) => { - if (!textStyle) { - return undefined; - } - const marks: Mark[] = []; - Object.keys(textStyle).forEach(key => { - let value: any; - const targeted = key as keyof docs_v1.Schema$TextStyle; - if (value = textStyle[targeted]) { - const attributes: any = {}; - let converted = StyleToMark.get(targeted) || targeted; - - value.url && (attributes.href = value.url); - if (value.color) { - const object = value.color.rgbColor; - attributes.color = Color.rgb(["red", "green", "blue"].map(color => object[color] * 255 || 0)).hex(); - } - if (value.magnitude) { - attributes.fontSize = value.magnitude; - } - - if (converted === "weightedFontFamily") { - converted = ImportFontFamilyMapping.get(value.fontFamily) || "timesNewRoman"; - } - - const mapped = schema.marks[converted]; - if (!mapped) { - alert(`No mapping found for ${converted}!`); - return; - } - - const mark = schema.mark(mapped, attributes); - mark && marks.push(mark); - } - }); - return marks; - }; - - const MarkToStyle = new Map([ - ["strong", "bold"], - ["em", "italic"], - ["pFontColor", "foregroundColor"], - ["pFontSize", "fontSize"], - ["timesNewRoman", "weightedFontFamily"], - ["georgia", "weightedFontFamily"], - ["comicSans", "weightedFontFamily"], - ["tahoma", "weightedFontFamily"], - ["impact", "weightedFontFamily"] - ]); - - const ExportFontFamilyMapping = new Map([ - ["timesNewRoman", "Times New Roman"], - ["arial", "Arial"], - ["georgia", "Georgia"], - ["comicSans", "Comic Sans MS"], - ["tahoma", "Tahoma"], - ["impact", "Impact"] - ]); - - const ImportFontFamilyMapping = new Map([ - ["Times New Roman", "timesNewRoman"], - ["Arial", "arial"], - ["Georgia", "georgia"], - ["Comic Sans MS", "comicSans"], - ["Tahoma", "tahoma"], - ["Impact", "impact"] - ]); - - const ignored = ["user_mark"]; - - const marksToStyle = async (nodes: (Node | null)[]): Promise => { - const requests: docs_v1.Schema$Request[] = []; - let position = 1; - for (const node of nodes) { - if (node === null) { - position += 2; - continue; - } - const { marks, attrs, nodeSize } = node; - const textStyle: docs_v1.Schema$TextStyle = {}; - const information: LinkInformation = { - startIndex: position, - endIndex: position + nodeSize, - textStyle - }; - let mark: Mark; - const markMap = BuildMarkMap(marks); - for (const markName of Object.keys(schema.marks)) { - if (ignored.includes(markName) || !(mark = markMap[markName])) { - continue; - } - let converted = MarkToStyle.get(markName) || markName as keyof docs_v1.Schema$TextStyle; - let value: any = true; - if (!converted) { - continue; - } - const { attrs } = mark; - switch (converted) { - case "link": - let url = attrs.href; - const delimiter = "/doc/"; - const alreadyShared = "?sharing=true"; - if (new RegExp(window.location.origin + delimiter).test(url) && !url.endsWith(alreadyShared)) { - const linkDoc = await DocServer.GetRefField(url.split(delimiter)[1]); - if (linkDoc instanceof Doc) { - let exported = (await Cast(linkDoc.anchor2, Doc))!; - if (!exported.customLayout) { - exported = Doc.MakeAlias(exported); - Doc.makeCustomViewClicked(exported, Docs.Create.FreeformDocument); - linkDoc.anchor2 = exported; - } - url = Utils.shareUrl(exported[Id]); - } - } - value = { url }; - textStyle.foregroundColor = fromRgb.blue; - textStyle.bold = true; - break; - case "fontSize": - value = { magnitude: attrs.fontSize, unit: "PT" }; - break; - case "foregroundColor": - value = fromHex(attrs.color); - break; - case "weightedFontFamily": - value = { fontFamily: ExportFontFamilyMapping.get(markName) }; - } - let matches: RegExpExecArray | null; - if ((matches = /p(\d+)/g.exec(markName)) !== null) { - converted = "fontSize"; - value = { magnitude: parseInt(matches[1].replace("px", "")), unit: "PT" }; - } - textStyle[converted] = value; - } - if (Object.keys(textStyle).length) { - requests.push(EncodeStyleUpdate(information)); - } - if (node.type.name === "image") { - const width = attrs.width; - requests.push(await EncodeImage({ - startIndex: position + nodeSize - 1, - uri: attrs.agnostic, - width: Number(typeof width === "string" ? width.replace("px", "") : width) - })); - } - position += nodeSize; - } - return requests; - }; - - const BuildMarkMap = (marks: Mark[]) => { - const markMap: { [type: string]: Mark } = {}; - marks.forEach(mark => markMap[mark.type.name] = mark); - return markMap; - }; - - interface LinkInformation { - startIndex: number; - endIndex: number; - textStyle: docs_v1.Schema$TextStyle; - } - - interface ImageInformation { - startIndex: number; - width: number; - uri: string; - } - - namespace fromRgb { - - export const convert = (red: number, green: number, blue: number): docs_v1.Schema$OptionalColor => { - return { - color: { - rgbColor: { - red: red / 255, - green: green / 255, - blue: blue / 255 - } - } - }; - }; - - export const red = convert(255, 0, 0); - export const green = convert(0, 255, 0); - export const blue = convert(0, 0, 255); - - } - - const fromHex = (color: string): docs_v1.Schema$OptionalColor => { - const c = Color(color); - return fromRgb.convert(c.red(), c.green(), c.blue()); - }; - - const EncodeStyleUpdate = (information: LinkInformation): docs_v1.Schema$Request => { - const { startIndex, endIndex, textStyle } = information; - return { - updateTextStyle: { - fields: "*", - range: { startIndex, endIndex }, - textStyle - } as docs_v1.Schema$UpdateTextStyleRequest - }; - }; - - const EncodeImage = async ({ uri, width, startIndex }: ImageInformation) => { - if (!uri) { - return {}; - } - const source = [Docs.Create.ImageDocument(uri)]; - const baseUrls = await GooglePhotos.Transactions.UploadThenFetch(source); - if (baseUrls) { - return { - insertInlineImage: { - uri: baseUrls[0], - objectSize: { width: { magnitude: width, unit: "PT" } }, - location: { index: startIndex } - } - }; - } - return {}; - }; - } - -} \ No newline at end of file diff --git a/src/new_fields/Schema.ts b/src/new_fields/Schema.ts deleted file mode 100644 index 72bce283d..000000000 --- a/src/new_fields/Schema.ts +++ /dev/null @@ -1,120 +0,0 @@ -import { Interface, ToInterface, Cast, ToConstructor, HasTail, Head, Tail, ListSpec, ToType, DefaultFieldConstructor } from "./Types"; -import { Doc, Field } from "./Doc"; -import { ObjectField } from "./ObjectField"; -import { RefField } from "./RefField"; -import { SelfProxy } from "./FieldSymbols"; - -type AllToInterface = { - 1: ToInterface> & AllToInterface>, - 0: ToInterface> -}[HasTail extends true ? 1 : 0]; - -export const emptySchema = createSchema({}); -export const Document = makeInterface(emptySchema); -export type Document = makeInterface<[typeof emptySchema]>; - -export interface InterfaceFunc { - (docs: Doc[]): makeInterface[]; - (): makeInterface; - (doc: Doc): makeInterface; -} - -export type makeInterface = AllToInterface & Doc & { proto: Doc | undefined }; -// export function makeInterface(schemas: T): (doc: U) => All; -// export function makeInterface(schema: T): (doc: U) => makeInterface; -export function makeInterface(...schemas: T): InterfaceFunc { - const schema: Interface = {}; - for (const s of schemas) { - for (const key in s) { - schema[key] = s[key]; - } - } - const proto = new Proxy({}, { - get(target: any, prop, receiver) { - const field = receiver.doc[prop]; - if (prop in schema) { - const desc = prop === "proto" ? Doc : (schema as any)[prop]; // bcz: proto doesn't appear in schemas ... maybe it should? - if (typeof desc === "object" && "defaultVal" in desc && "type" in desc) {//defaultSpec - return Cast(field, desc.type, desc.defaultVal); - } else if (typeof desc === "function" && !ObjectField.isPrototypeOf(desc) && !RefField.isPrototypeOf(desc)) { - const doc = Cast(field, Doc); - if (doc === undefined) { - return undefined; - } else if (doc instanceof Doc) { - return desc(doc); - } else { - return doc.then(doc => doc && desc(doc)); - } - } else { - return Cast(field, desc); - } - } - return field; - }, - set(target: any, prop, value, receiver) { - receiver.doc[prop] = value; - return true; - } - }); - const fn = (doc: Doc) => { - doc = doc[SelfProxy]; - // if (!(doc instanceof Doc)) { - // throw new Error("Currently wrapping a schema in another schema isn't supported"); - // } - const obj = Object.create(proto, { doc: { value: doc, writable: false } }); - return obj; - }; - return function (doc?: Doc | Doc[]) { - doc = doc || new Doc; - if (doc instanceof Doc) { - return fn(doc); - } else { - return doc.map(fn); - } - }; -} - -export type makeStrictInterface = Partial>; -export function makeStrictInterface(schema: T): (doc: Doc) => makeStrictInterface { - const proto = {}; - for (const key in schema) { - const type = schema[key]; - Object.defineProperty(proto, key, { - get() { - return Cast(this.__doc[key], type as any); - }, - set(value) { - value = Cast(value, type as any); - if (value !== undefined) { - this.__doc[key] = value; - return; - } - throw new TypeError("Expected type " + type); - } - }); - } - return function (doc: any) { - if (!(doc instanceof Doc)) { - throw new Error("Currently wrapping a schema in another schema isn't supported"); - } - const obj = Object.create(proto); - obj.__doc = doc; - return obj; - }; -} - -export function createSchema(schema: T): T & { proto: ToConstructor } { - (schema as any).proto = Doc; - return schema as any; -} - -export function listSpec>(type: U): ListSpec> { - return { List: type as any };//TODO Types -} - -export function defaultSpec>(type: T, defaultVal: ToType): DefaultFieldConstructor> { - return { - type: type as any, - defaultVal - }; -} \ No newline at end of file diff --git a/src/new_fields/SchemaHeaderField.ts b/src/new_fields/SchemaHeaderField.ts deleted file mode 100644 index 07c90f5a2..000000000 --- a/src/new_fields/SchemaHeaderField.ts +++ /dev/null @@ -1,122 +0,0 @@ -import { Deserializable } from "../client/util/SerializationHelper"; -import { serializable, primitive } from "serializr"; -import { ObjectField } from "./ObjectField"; -import { Copy, ToScriptString, ToString, OnUpdate } from "./FieldSymbols"; -import { scriptingGlobal } from "../client/util/Scripting"; -import { ColumnType } from "../client/views/collections/CollectionSchemaView"; - -export const PastelSchemaPalette = new Map([ - // ["pink1", "#FFB4E8"], - ["pink2", "#ff9cee"], - ["pink3", "#ffccf9"], - ["pink4", "#fcc2ff"], - ["pink5", "#f6a6ff"], - ["purple1", "#b28dff"], - ["purple2", "#c5a3ff"], - ["purple3", "#d5aaff"], - ["purple4", "#ecd4ff"], - // ["purple5", "#fb34ff"], - ["purple6", "#dcd3ff"], - ["purple7", "#a79aff"], - ["purple8", "#b5b9ff"], - ["purple9", "#97a2ff"], - ["bluegreen1", "#afcbff"], - ["bluegreen2", "#aff8db"], - ["bluegreen3", "#c4faf8"], - ["bluegreen4", "#85e3ff"], - ["bluegreen5", "#ace7ff"], - // ["bluegreen6", "#6eb5ff"], - ["bluegreen7", "#bffcc6"], - ["bluegreen8", "#dbffd6"], - ["yellow1", "#f3ffe3"], - ["yellow2", "#e7ffac"], - ["yellow3", "#ffffd1"], - ["yellow4", "#fff5ba"], - // ["red1", "#ffc9de"], - ["red2", "#ffabab"], - ["red3", "#ffbebc"], - ["red4", "#ffcbc1"], - ["orange1", "#ffd5b3"], -]); - -export const RandomPastel = () => Array.from(PastelSchemaPalette.values())[Math.floor(Math.random() * PastelSchemaPalette.size)]; - -export const DarkPastelSchemaPalette = new Map([ - ["pink2", "#c932b0"], - ["purple4", "#913ad6"], - ["bluegreen1", "#3978ed"], - ["bluegreen7", "#2adb3e"], - ["bluegreen5", "#21b0eb"], - ["yellow4", "#edcc0c"], - ["red2", "#eb3636"], - ["orange1", "#f2740f"], -]); - -@scriptingGlobal -@Deserializable("schemaheader") -export class SchemaHeaderField extends ObjectField { - @serializable(primitive()) - heading: string; - @serializable(primitive()) - color: string; - @serializable(primitive()) - type: number; - @serializable(primitive()) - width: number; - @serializable(primitive()) - collapsed: boolean | undefined; - @serializable(primitive()) - desc: boolean | undefined; // boolean determines sort order, undefined when no sort - - constructor(heading: string = "", color: string = RandomPastel(), type?: ColumnType, width?: number, desc?: boolean, collapsed?: boolean) { - super(); - - this.heading = heading; - this.color = color; - this.type = type ? type : 0; - this.width = width ? width : -1; - this.desc = desc; - this.collapsed = collapsed; - } - - setHeading(heading: string) { - this.heading = heading; - this[OnUpdate](); - } - - setColor(color: string) { - this.color = color; - this[OnUpdate](); - } - - setType(type: ColumnType) { - this.type = type; - this[OnUpdate](); - } - - setWidth(width: number) { - this.width = width; - this[OnUpdate](); - } - - setDesc(desc: boolean | undefined) { - this.desc = desc; - this[OnUpdate](); - } - - setCollapsed(collapsed: boolean | undefined) { - this.collapsed = collapsed; - this[OnUpdate](); - } - - [Copy]() { - return new SchemaHeaderField(this.heading, this.color, this.type); - } - - [ToScriptString]() { - return `invalid`; - } - [ToString]() { - return `SchemaHeaderField`; - } -} \ No newline at end of file diff --git a/src/new_fields/ScriptField.ts b/src/new_fields/ScriptField.ts deleted file mode 100644 index 4b790f483..000000000 --- a/src/new_fields/ScriptField.ts +++ /dev/null @@ -1,193 +0,0 @@ -import { ObjectField } from "./ObjectField"; -import { CompiledScript, CompileScript, scriptingGlobal, ScriptOptions, CompileError, CompileResult } from "../client/util/Scripting"; -import { Copy, ToScriptString, ToString, Parent, SelfProxy } from "./FieldSymbols"; -import { serializable, createSimpleSchema, map, primitive, object, deserialize, PropSchema, custom, SKIP } from "serializr"; -import { Deserializable, autoObject } from "../client/util/SerializationHelper"; -import { Doc, Field } from "../new_fields/Doc"; -import { Plugins, setter } from "./util"; -import { computedFn } from "mobx-utils"; -import { ProxyField } from "./Proxy"; -import { Cast } from "./Types"; - -function optional(propSchema: PropSchema) { - return custom(value => { - if (value !== undefined) { - return propSchema.serializer(value); - } - return SKIP; - }, (jsonValue: any, context: any, oldValue: any, callback: (err: any, result: any) => void) => { - if (jsonValue !== undefined) { - return propSchema.deserializer(jsonValue, callback, context, oldValue); - } - return SKIP; - }); -} - -const optionsSchema = createSimpleSchema({ - requiredType: true, - addReturn: true, - typecheck: true, - editable: true, - readonly: true, - params: optional(map(primitive())) -}); - -const scriptSchema = createSimpleSchema({ - options: object(optionsSchema), - originalScript: true -}); - -async function deserializeScript(script: ScriptField) { - const captures: ProxyField = (script as any).captures; - if (captures) { - const doc = (await captures.value())!; - const captured: any = {}; - const keys = Object.keys(doc); - const vals = await Promise.all(keys.map(key => doc[key]) as any); - keys.forEach((key, i) => captured[key] = vals[i]); - (script.script.options as any).capturedVariables = captured; - } - const comp = CompileScript(script.script.originalScript, script.script.options); - if (!comp.compiled) { - throw new Error("Couldn't compile loaded script"); - } - (script as any).script = comp; -} - -@scriptingGlobal -@Deserializable("script", deserializeScript) -export class ScriptField extends ObjectField { - @serializable(object(scriptSchema)) - readonly script: CompiledScript; - @serializable(object(scriptSchema)) - readonly setterscript: CompiledScript | undefined; - - @serializable(autoObject()) - private captures?: ProxyField; - - constructor(script: CompiledScript, setterscript?: CompileResult) { - super(); - - if (script?.options.capturedVariables) { - const doc = Doc.assign(new Doc, script.options.capturedVariables); - this.captures = new ProxyField(doc); - } - this.setterscript = setterscript?.compiled ? setterscript : undefined; - this.script = script; - } - - // init(callback: (res: Field) => any) { - // const options = this.options!; - // const keys = Object.keys(options.options.capturedIds); - // Server.GetFields(keys).then(fields => { - // let captured: { [name: string]: Field } = {}; - // keys.forEach(key => captured[options.options.capturedIds[key]] = fields[key]); - // const opts: ScriptOptions = { - // addReturn: options.options.addReturn, - // params: options.options.params, - // requiredType: options.options.requiredType, - // capturedVariables: captured - // }; - // const script = CompileScript(options.script, opts); - // if (!script.compiled) { - // throw new Error("Can't compile script"); - // } - // this._script = script; - // callback(this); - // }); - // } - - [Copy](): ObjectField { - return new ScriptField(this.script); - } - toString() { - return `${this.script.originalScript}`; - } - - [ToScriptString]() { - return "script field"; - } - [ToString]() { - return this.script.originalScript; - } - public static CompileScript(script: string, params: object = {}, addReturn = false, capturedVariables?: { [name: string]: Field }) { - const compiled = CompileScript(script, { - params: { this: Doc.name, self: Doc.name, _last_: "any", ...params }, - typecheck: false, - editable: true, - addReturn: addReturn, - capturedVariables - }); - return compiled; - } - public static MakeFunction(script: string, params: object = {}, capturedVariables?: { [name: string]: Field }) { - const compiled = ScriptField.CompileScript(script, params, true, capturedVariables); - return compiled.compiled ? new ScriptField(compiled) : undefined; - } - - public static MakeScript(script: string, params: object = {}, capturedVariables?: { [name: string]: Field }) { - const compiled = ScriptField.CompileScript(script, params, false, capturedVariables); - return compiled.compiled ? new ScriptField(compiled) : undefined; - } -} - -@scriptingGlobal -@Deserializable("computed", deserializeScript) -export class ComputedField extends ScriptField { - _lastComputedResult: any; - //TODO maybe add an observable cache based on what is passed in for doc, considering there shouldn't really be that many possible values for doc - value = computedFn((doc: Doc) => this._valueOutsideReaction(doc)); - _valueOutsideReaction = (doc: Doc) => this._lastComputedResult = this.script.run({ this: doc, self: Cast(doc.rootDocument, Doc, null) || doc, _last_: this._lastComputedResult }, console.log).result; - - - constructor(script: CompiledScript, setterscript?: CompiledScript) { - super(script, - !setterscript && script?.originalScript.includes("self.timecode") ? - ScriptField.CompileScript("self['x' + self.timecode] = value", { value: "any" }, true) : setterscript); - } - - public static MakeScript(script: string, params: object = {}) { - const compiled = ScriptField.CompileScript(script, params, false); - return compiled.compiled ? new ComputedField(compiled) : undefined; - } - public static MakeFunction(script: string, params: object = {}, capturedVariables?: { [name: string]: Field }, setterScript?: string) { - const compiled = ScriptField.CompileScript(script, params, true, capturedVariables); - const setCompiled = setterScript ? ScriptField.CompileScript(setterScript, params, true, capturedVariables) : undefined; - return compiled.compiled ? new ComputedField(compiled, setCompiled?.compiled ? setCompiled : undefined) : undefined; - } - public static MakeInterpolated(fieldKey: string, interpolatorKey: string) { - const getField = ScriptField.CompileScript(`(self['${fieldKey}-indexed'])[self.${interpolatorKey}]`, {}, true, {}); - const setField = ScriptField.CompileScript(`(self['${fieldKey}-indexed'])[self.${interpolatorKey}] = value`, { value: "any" }, true, {}); - return getField.compiled ? new ComputedField(getField, setField?.compiled ? setField : undefined) : undefined; - } -} - -export namespace ComputedField { - let useComputed = true; - export function DisableComputedFields() { - useComputed = false; - } - - export function EnableComputedFields() { - useComputed = true; - } - - export const undefined = "__undefined"; - - export function WithoutComputed(fn: () => T) { - DisableComputedFields(); - try { - return fn(); - } finally { - EnableComputedFields(); - } - } - - export function initPlugin() { - Plugins.addGetterPlugin((doc, _, value) => { - if (useComputed && value instanceof ComputedField) { - return { value: value._valueOutsideReaction(doc), shouldReturn: true }; - } - }); - } -} \ No newline at end of file diff --git a/src/new_fields/Types.ts b/src/new_fields/Types.ts deleted file mode 100644 index 3d784448d..000000000 --- a/src/new_fields/Types.ts +++ /dev/null @@ -1,108 +0,0 @@ -import { Field, Opt, FieldResult, Doc } from "./Doc"; -import { List } from "./List"; -import { RefField } from "./RefField"; -import { DateField } from "./DateField"; -import { ScriptField } from "./ScriptField"; - -export type ToType = - T extends "string" ? string : - T extends "number" ? number : - T extends "boolean" ? boolean : - T extends ListSpec ? List : - // T extends { new(...args: any[]): infer R } ? (R | Promise) : never; - T extends DefaultFieldConstructor ? never : - T extends { new(...args: any[]): List } ? never : - T extends { new(...args: any[]): infer R } ? R : - T extends (doc?: Doc) => infer R ? R : never; - -export type ToConstructor = - T extends string ? "string" : - T extends number ? "number" : - T extends boolean ? "boolean" : - T extends List ? ListSpec : - new (...args: any[]) => T; - -export type ToInterface = { - [P in Exclude]: T[P] extends DefaultFieldConstructor ? Exclude, undefined> : FieldResult>; -}; - -// type ListSpec = { List: ToContructor> | ListSpec> }; -export type ListSpec = { List: ToConstructor }; - -export type DefaultFieldConstructor = { - type: ToConstructor, - defaultVal: T -}; - -// type ListType = { 0: List>>, 1: ToType> }[HasTail extends true ? 0 : 1]; - -export type Head = T extends [any, ...any[]] ? T[0] : never; -export type Tail = - ((...t: T) => any) extends ((_: any, ...tail: infer TT) => any) ? TT : []; -export type HasTail = T extends ([] | [any]) ? false : true; - -export type InterfaceValue = ToConstructor | ListSpec | DefaultFieldConstructor | ((doc?: Doc) => any); -//TODO Allow you to optionally specify default values for schemas, which should then make that field not be partial -export interface Interface { - [key: string]: InterfaceValue; - // [key: string]: ToConstructor | ListSpec; -} -export type WithoutRefField = T extends RefField ? never : T; - -export type CastCtor = ToConstructor | ListSpec; - -export function Cast(field: FieldResult, ctor: T): FieldResult>; -export function Cast(field: FieldResult, ctor: T, defaultVal: WithoutList>> | null): WithoutList>; -export function Cast(field: FieldResult, ctor: T, defaultVal?: ToType | null): FieldResult> | undefined { - if (field instanceof Promise) { - return defaultVal === undefined ? field.then(f => Cast(f, ctor) as any) as any : defaultVal === null ? undefined : defaultVal; - } - if (field !== undefined && !(field instanceof Promise)) { - if (typeof ctor === "string") { - if (typeof field === ctor) { - return field as ToType; - } - } else if (typeof ctor === "object") { - if (field instanceof List) { - return field as any; - } - } else if (field instanceof (ctor as any)) { - return field as ToType; - } - } - return defaultVal === null ? undefined : defaultVal; -} - -export function NumCast(field: FieldResult, defaultVal: number | null = 0) { - return Cast(field, "number", defaultVal); -} - -export function StrCast(field: FieldResult, defaultVal: string | null = "") { - return Cast(field, "string", defaultVal); -} - -export function BoolCast(field: FieldResult, defaultVal: boolean | null = false) { - return Cast(field, "boolean", defaultVal); -} -export function DateCast(field: FieldResult) { - return Cast(field, DateField, null); -} - -export function ScriptCast(field: FieldResult, defaultVal: ScriptField | null = null) { - return Cast(field, ScriptField, defaultVal); -} - -type WithoutList = T extends List ? (R extends RefField ? (R | Promise)[] : R[]) : T; - -export function FieldValue>(field: FieldResult, defaultValue: U): WithoutList; -export function FieldValue(field: FieldResult): Opt; -export function FieldValue(field: FieldResult, defaultValue?: T): Opt { - return (field instanceof Promise || field === undefined) ? defaultValue : field; -} - -export interface PromiseLike { - then(callback: (field: Opt) => void): void; -} -export function PromiseValue(field: FieldResult): PromiseLike> { - return field instanceof Promise ? field : { then(cb: ((field: Opt) => void)) { return cb(field); } }; -} \ No newline at end of file diff --git a/src/new_fields/URLField.ts b/src/new_fields/URLField.ts deleted file mode 100644 index fb71160ca..000000000 --- a/src/new_fields/URLField.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { Deserializable } from "../client/util/SerializationHelper"; -import { serializable, custom } from "serializr"; -import { ObjectField } from "./ObjectField"; -import { ToScriptString, ToString, Copy } from "./FieldSymbols"; -import { Scripting, scriptingGlobal } from "../client/util/Scripting"; - -function url() { - return custom( - function (value: URL) { - return value.href; - }, - function (jsonValue: string) { - return new URL(jsonValue); - } - ); -} - -export abstract class URLField extends ObjectField { - @serializable(url()) - readonly url: URL; - - constructor(url: string); - constructor(url: URL); - constructor(url: URL | string) { - super(); - if (typeof url === "string") { - url = new URL(url); - } - this.url = url; - } - - [ToScriptString]() { - return `new ${this.constructor.name}("${this.url.href}")`; - } - [ToString]() { - return this.url.href; - } - - [Copy](): this { - return new (this.constructor as any)(this.url); - } -} - -export const nullAudio = "https://actions.google.com/sounds/v1/alarms/beep_short.ogg"; - -@scriptingGlobal @Deserializable("audio") export class AudioField extends URLField { } -@scriptingGlobal @Deserializable("image") export class ImageField extends URLField { } -@scriptingGlobal @Deserializable("video") export class VideoField extends URLField { } -@scriptingGlobal @Deserializable("pdf") export class PdfField extends URLField { } -@scriptingGlobal @Deserializable("web") export class WebField extends URLField { } -@scriptingGlobal @Deserializable("youtube") export class YoutubeField extends URLField { } -@scriptingGlobal @Deserializable("webcam") export class WebCamField extends URLField { } - diff --git a/src/new_fields/documentSchemas.ts b/src/new_fields/documentSchemas.ts deleted file mode 100644 index cacba43b6..000000000 --- a/src/new_fields/documentSchemas.ts +++ /dev/null @@ -1,100 +0,0 @@ -import { makeInterface, createSchema, listSpec } from "./Schema"; -import { ScriptField } from "./ScriptField"; -import { Doc } from "./Doc"; -import { DateField } from "./DateField"; - -export const documentSchema = createSchema({ - // content properties - type: "string", // enumerated type of document -- should be template-specific (ie, start with an '_') - title: "string", // document title (can be on either data document or layout) - isTemplateForField: "string",// if specified, it indicates the document is a template that renders the specified field - creationDate: DateField, // when the document was created - links: listSpec(Doc), // computed (readonly) list of links associated with this document - - // "Location" properties in a very general sense - currentTimecode: "number", // current play back time of a temporal document (video / audio) - displayTimecode: "number", // the time that a document should be displayed (e.g., time an annotation should be displayed on a video) - inOverlay: "boolean", // whether the document is rendered in an OverlayView which handles selection/dragging differently - x: "number", // x coordinate when in a freeform view - y: "number", // y coordinate when in a freeform view - z: "number", // z "coordinate" - non-zero specifies the overlay layer of a freeformview - zIndex: "number", // zIndex of a document in a freeform view - scrollY: "number", // "command" to scroll a document to a position on load (the value will be reset to 0 after that ) - scrollTop: "number", // scroll position of a scrollable document (pdf, text, web) - - // appearance properties on the layout - _autoHeight: "boolean", // whether the height of the document should be computed automatically based on its contents - _nativeWidth: "number", // native width of document which determines how much document contents are scaled when the document's width is set - _nativeHeight: "number", // " - _width: "number", // width of document in its container's coordinate system - _height: "number", // " - _xPadding: "number", // pixels of padding on left/right of collectionfreeformview contents when fitToBox is set - _yPadding: "number", // pixels of padding on top/bottom of collectionfreeformview contents when fitToBox is set - _xMargin: "number", // margin added on left/right of most documents to add separation from their container - _yMargin: "number", // margin added on top/bottom of most documents to add separation from their container - _overflow: "string", // sets overflow behvavior for CollectionFreeForm views - _showCaption: "string", // whether editable caption text is overlayed at the bottom of the document - _showTitle: "string", // the fieldkey whose contents should be displayed at the top of the document - _showTitleHover: "string", // the showTitle should be shown only on hover - _showAudio: "boolean", // whether to show the audio record icon on documents - _freeformLayoutEngine: "string",// the string ID for the layout engine to use to layout freeform view documents - _LODdisable: "boolean", // whether to disbale LOD switching for CollectionFreeFormViews - _pivotField: "string", // specifies which field key should be used as the timeline/pivot axis - _replacedChrome: "string", // what the default chrome is replaced with. Currently only supports the value of 'replaced' for PresBox's. - _chromeStatus: "string", // determines the state of the collection chrome. values allowed are 'replaced', 'enabled', 'disabled', 'collapsed' - _fontSize: "number", - _fontFamily: "string", - _sidebarWidthPercent: "string", // percent of text window width taken up by sidebar - - // appearance properties on the data document - backgroundColor: "string", // background color of document - borderRounding: "string", // border radius rounding of document - boxShadow: "string", // the amount of shadow around the perimeter of a document - color: "string", // foreground color of document - fitToBox: "boolean", // whether freeform view contents should be zoomed/panned to fill the area of the document view - fontSize: "string", - layout: "string", // this is the native layout string for the document. templates can be added using other fields and setting layoutKey below - layoutKey: "string", // holds the field key for the field that actually holds the current lyoat - letterSpacing: "string", - opacity: "number", // opacity of document - strokeWidth: "number", - textTransform: "string", - treeViewOpen: "boolean", // flag denoting whether the documents sub-tree (contents) is visible or hidden - treeViewExpandedView: "string", // name of field whose contents are being displayed as the document's subtree - treeViewPreventOpen: "boolean", // ignores the treeViewOpen flag (for allowing a view to not be slaved to other views of the document) - - // interaction and linking properties - ignoreClick: "boolean", // whether documents ignores input clicks (but does not ignore manipulation and other events) - onClick: ScriptField, // script to run when document is clicked (can be overriden by an onClick prop) - onPointerDown: ScriptField, // script to run when document is clicked (can be overriden by an onClick prop) - onPointerUp: ScriptField, // script to run when document is clicked (can be overriden by an onClick prop) - onDragStart: ScriptField, // script to run when document is dragged (without being selected). the script should return the Doc to be dropped. - followLinkLocation: "string",// flag for where to place content when following a click interaction (e.g., onRight, inPlace, inTab, ) - isInPlaceContainer: "boolean",// whether the marked object will display addDocTab() calls that target "inPlace" destinations - isLinkButton: "boolean", // whether document functions as a link follow button to follow the first link on the document when clicked - isBackground: "boolean", // whether document is a background element and ignores input events (can only select with marquee) - lockedPosition: "boolean", // whether the document can be moved (dragged) - lockedTransform: "boolean", // whether the document can be panned/zoomed - - // drag drop properties - dragFactory: Doc, // the document that serves as the "template" for the onDragStart script. ie, to drag out copies of the dragFactory document. - dropAction: "string", // override specifying what should happen when this document is dropped (can be "alias", "copy", "move") - targetDropAction: "string", // allows the target of a drop event to specify the dropAction ("alias", "copy", "move") NOTE: if the document is dropped within the same collection, the dropAction is coerced to 'move' - childDropAction: "string", // specify the override for what should happen when the child of a collection is dragged from it and dropped (can be "alias" or "copy") - removeDropProperties: listSpec("string"), // properties that should be removed from the alias/copy/etc of this document when it is dropped -}); - - -export const collectionSchema = createSchema({ - childLayoutTemplateName: "string", // the name of a template to use to override the layoutKey when rendering a document -- ONLY used in DocHolderBox - childLayoutTemplate: Doc, // layout template to use to render children of a collecion - childLayoutString: "string", //layout string to use to render children of a collection - childClickedOpenTemplateView: Doc, // layout template to apply to a child when its clicked on in a collection and opened (requires onChildClick or other script to read this value and apply template) - dontRegisterChildViews: "boolean", // whether views made of this document are registered so that they can be found when drawing links scrollToLinkID: "string", // id of link being traversed. allows this doc to scroll/highlight/etc its link anchor. scrollToLinkID should be set to undefined by this doc after it sets up its scroll,etc. - onChildClick: ScriptField, // script to run for each child when its clicked - onChildDoubleClick: ScriptField, // script to run for each child when its clicked - onCheckedClick: ScriptField, // script to run when a checkbox is clicked next to a child in a tree view -}); - -export type Document = makeInterface<[typeof documentSchema]>; -export const Document = makeInterface(documentSchema); diff --git a/src/new_fields/util.ts b/src/new_fields/util.ts deleted file mode 100644 index a287b0210..000000000 --- a/src/new_fields/util.ts +++ /dev/null @@ -1,199 +0,0 @@ -import { UndoManager } from "../client/util/UndoManager"; -import { Doc, Field, FieldResult, UpdatingFromServer, LayoutSym } from "./Doc"; -import { SerializationHelper } from "../client/util/SerializationHelper"; -import { ProxyField, PrefetchProxy } from "./Proxy"; -import { RefField } from "./RefField"; -import { ObjectField } from "./ObjectField"; -import { action, trace } from "mobx"; -import { Parent, OnUpdate, Update, Id, SelfProxy, Self } from "./FieldSymbols"; -import { DocServer } from "../client/DocServer"; -import { ComputedField } from "./ScriptField"; -import { ScriptCast } from "./Types"; - -function _readOnlySetter(): never { - throw new Error("Documents can't be modified in read-only mode"); -} - -const tracing = false; -export function TraceMobx() { - tracing && trace(); -} - -export interface GetterResult { - value: FieldResult; - shouldReturn?: boolean; -} -export type GetterPlugin = (receiver: any, prop: string | number, currentValue: any) => GetterResult | undefined; -const getterPlugins: GetterPlugin[] = []; - -export namespace Plugins { - export function addGetterPlugin(plugin: GetterPlugin) { - getterPlugins.push(plugin); - } -} - -const _setterImpl = action(function (target: any, prop: string | symbol | number, value: any, receiver: any): boolean { - //console.log("-set " + target[SelfProxy].title + "(" + target[SelfProxy][prop] + ")." + prop.toString() + " = " + value); - if (SerializationHelper.IsSerializing()) { - target[prop] = value; - return true; - } - - if (typeof prop === "symbol") { - target[prop] = value; - return true; - } - if (value !== undefined) { - value = value[SelfProxy] || value; - } - const curValue = target.__fields[prop]; - if (curValue === value || (curValue instanceof ProxyField && value instanceof RefField && curValue.fieldId === value[Id])) { - // TODO This kind of checks correctly in the case that curValue is a ProxyField and value is a RefField, but technically - // curValue should get filled in with value if it isn't already filled in, in case we fetched the referenced field some other way - return true; - } - if (value instanceof RefField) { - value = new ProxyField(value); - } - if (value instanceof ObjectField) { - if (value[Parent] && value[Parent] !== receiver && !(value instanceof PrefetchProxy)) { - throw new Error("Can't put the same object in multiple documents at the same time"); - } - value[Parent] = receiver; - value[OnUpdate] = updateFunction(target, prop, value, receiver); - } - if (curValue instanceof ObjectField) { - delete curValue[Parent]; - delete curValue[OnUpdate]; - } - const writeMode = DocServer.getFieldWriteMode(prop as string); - const fromServer = target[UpdatingFromServer]; - const sameAuthor = fromServer || (receiver.author === Doc.CurrentUserEmail); - const writeToDoc = sameAuthor || (writeMode !== DocServer.WriteMode.LiveReadonly); - const writeToServer = sameAuthor || (writeMode === DocServer.WriteMode.Default); - if (writeToDoc) { - if (value === undefined) { - delete target.__fields[prop]; - } else { - target.__fields[prop] = value; - } - if (typeof value === "object" && !(value instanceof ObjectField)) debugger; - if (writeToServer) { - if (value === undefined) target[Update]({ '$unset': { ["fields." + prop]: "" } }); - else target[Update]({ '$set': { ["fields." + prop]: value instanceof ObjectField ? SerializationHelper.Serialize(value) : (value === undefined ? null : value) } }); - } else { - DocServer.registerDocWithCachedUpdate(receiver, prop as string, curValue); - } - UndoManager.AddEvent({ - redo: () => receiver[prop] = value, - undo: () => receiver[prop] = curValue - }); - } - return true; -}); - -let _setter: (target: any, prop: string | symbol | number, value: any, receiver: any) => boolean = _setterImpl; - -export function makeReadOnly() { - _setter = _readOnlySetter; -} - -export function makeEditable() { - _setter = _setterImpl; -} - -const layoutProps = ["panX", "panY", "width", "height", "nativeWidth", "nativeHeight", "fitWidth", "fitToBox", - "LODdisable", "chromeStatus", "viewType", "gridGap", "xMargin", "yMargin", "autoHeight"]; -export function setter(target: any, in_prop: string | symbol | number, value: any, receiver: any): boolean { - let prop = in_prop; - if (typeof prop === "string" && prop !== "__id" && prop !== "__fields" && (prop.startsWith("_") || layoutProps.includes(prop))) { - if (!prop.startsWith("_")) { - console.log(prop + " is deprecated - switch to _" + prop); - prop = "_" + prop; - } - if (target.__LAYOUT__) { - target.__LAYOUT__[prop] = value; - return true; - } - } - if (target.__fields[prop] instanceof ComputedField && target.__fields[prop].setterscript) { - return ScriptCast(target.__fields[prop])?.setterscript?.run({ self: target[SelfProxy], this: target[SelfProxy], value }).success ? true : false; - } - return _setter(target, prop, value, receiver); -} - -export function getter(target: any, in_prop: string | symbol | number, receiver: any): any { - let prop = in_prop; - if (prop === LayoutSym) { - return target.__LAYOUT__; - } - if (typeof prop === "string" && prop !== "__id" && prop !== "__fields" && (prop.startsWith("_") || layoutProps.includes(prop))) { - if (!prop.startsWith("_")) { - console.log(prop + " is deprecated - switch to _" + prop); - prop = "_" + prop; - } - if (target.__LAYOUT__) return target.__LAYOUT__[prop]; - } - if (prop === "then") {//If we're being awaited - return undefined; - } - if (typeof prop === "symbol") { - return target.__fields[prop] || target[prop]; - } - if (SerializationHelper.IsSerializing()) { - return target[prop]; - } - return getFieldImpl(target, prop, receiver); -} - -function getFieldImpl(target: any, prop: string | number, receiver: any, ignoreProto: boolean = false): any { - receiver = receiver || target[SelfProxy]; - let field = target.__fields[prop]; - for (const plugin of getterPlugins) { - const res = plugin(receiver, prop, field); - if (res === undefined) continue; - if (res.shouldReturn) { - return res.value; - } else { - field = res.value; - } - } - if (field === undefined && !ignoreProto && prop !== "proto") { - const proto = getFieldImpl(target, "proto", receiver, true);//TODO tfs: instead of receiver we could use target[SelfProxy]... I don't which semantics we want or if it really matters - if (proto instanceof Doc) { - return getFieldImpl(proto[Self], prop, receiver, ignoreProto); - } - return undefined; - } - return field; - -} -export function getField(target: any, prop: string | number, ignoreProto: boolean = false): any { - return getFieldImpl(target, prop, undefined, ignoreProto); -} - -export function deleteProperty(target: any, prop: string | number | symbol) { - if (typeof prop === "symbol") { - delete target[prop]; - return true; - } - target[SelfProxy][prop] = undefined; - return true; -} - -export function updateFunction(target: any, prop: any, value: any, receiver: any) { - let current = ObjectField.MakeCopy(value); - return (diff?: any) => { - if (true || !diff) { - diff = { '$set': { ["fields." + prop]: SerializationHelper.Serialize(value) } }; - const oldValue = current; - const newValue = ObjectField.MakeCopy(value); - current = newValue; - UndoManager.AddEvent({ - redo() { receiver[prop] = newValue; }, - undo() { receiver[prop] = oldValue; } - }); - } - target[Update](diff); - }; -} \ No newline at end of file diff --git a/src/pen-gestures/GestureUtils.ts b/src/pen-gestures/GestureUtils.ts index b8a82ab4d..3b6170f68 100644 --- a/src/pen-gestures/GestureUtils.ts +++ b/src/pen-gestures/GestureUtils.ts @@ -1,9 +1,9 @@ import { NDollarRecognizer } from "./ndollar"; import { Type } from "typescript"; -import { InkField, PointData } from "../new_fields/InkField"; +import { InkField, PointData } from "../fields/InkField"; import { Docs } from "../client/documents/Documents"; -import { Doc, WidthSym, HeightSym } from "../new_fields/Doc"; -import { NumCast } from "../new_fields/Types"; +import { Doc, WidthSym, HeightSym } from "../fields/Doc"; +import { NumCast } from "../fields/Types"; import { CollectionFreeFormView } from "../client/views/collections/collectionFreeForm/CollectionFreeFormView"; import { Rect } from "react-measure"; import { Scripting } from "../client/util/Scripting"; diff --git a/src/server/ApiManagers/GooglePhotosManager.ts b/src/server/ApiManagers/GooglePhotosManager.ts index 11841a603..be17b698e 100644 --- a/src/server/ApiManagers/GooglePhotosManager.ts +++ b/src/server/ApiManagers/GooglePhotosManager.ts @@ -3,7 +3,7 @@ import { Method, _error, _success, _invalid } from "../RouteManager"; import * as path from "path"; import { GoogleApiServerUtils } from "../apis/google/GoogleApiServerUtils"; import { BatchedArray, TimeUnit } from "array-batcher"; -import { Opt } from "../../new_fields/Doc"; +import { Opt } from "../../fields/Doc"; import { DashUploadUtils, InjectSize, SizeSuffix } from "../DashUploadUtils"; import { Database } from "../database"; import { red } from "colors"; diff --git a/src/server/ApiManagers/UserManager.ts b/src/server/ApiManagers/UserManager.ts index 68b3107ae..0d1d8f218 100644 --- a/src/server/ApiManagers/UserManager.ts +++ b/src/server/ApiManagers/UserManager.ts @@ -3,7 +3,7 @@ import { Method } from "../RouteManager"; import { Database } from "../database"; import { msToTime } from "../ActionUtilities"; import * as bcrypt from "bcrypt-nodejs"; -import { Opt } from "../../new_fields/Doc"; +import { Opt } from "../../fields/Doc"; export const timeMap: { [id: string]: number } = {}; interface ActivityUnit { diff --git a/src/server/DashUploadUtils.ts b/src/server/DashUploadUtils.ts index 8567631cd..b74904ada 100644 --- a/src/server/DashUploadUtils.ts +++ b/src/server/DashUploadUtils.ts @@ -4,7 +4,7 @@ import * as path from 'path'; import * as sharp from 'sharp'; import request = require('request-promise'); import { ExifImage } from 'exif'; -import { Opt } from '../new_fields/Doc'; +import { Opt } from '../fields/Doc'; import { AcceptibleMedia, Upload } from './SharedMediaTypes'; import { filesDirectory, publicDirectory } from '.'; import { File } from 'formidable'; diff --git a/src/server/Message.ts b/src/server/Message.ts index 01aae5de7..80f372733 100644 --- a/src/server/Message.ts +++ b/src/server/Message.ts @@ -1,6 +1,6 @@ import { Utils } from "../Utils"; import { Point } from "../pen-gestures/ndollar"; -import { Doc } from "../new_fields/Doc"; +import { Doc } from "../fields/Doc"; import { Image } from "canvas"; import { AnalysisResult, ImportResults } from "../scraping/buxton/final/BuxtonImporter"; diff --git a/src/server/Recommender.ts b/src/server/Recommender.ts index aacdb4053..423ce9b46 100644 --- a/src/server/Recommender.ts +++ b/src/server/Recommender.ts @@ -1,6 +1,6 @@ -// //import { Doc } from "../new_fields/Doc"; -// //import { StrCast } from "../new_fields/Types"; -// //import { List } from "../new_fields/List"; +// //import { Doc } from "../fields/Doc"; +// //import { StrCast } from "../fields/Types"; +// //import { List } from "../fields/List"; // //import { CognitiveServices } from "../client/cognitive_services/CognitiveServices"; // // var w2v = require('word2vec'); diff --git a/src/server/apis/google/GoogleApiServerUtils.ts b/src/server/apis/google/GoogleApiServerUtils.ts index 2e4811c86..20f96f432 100644 --- a/src/server/apis/google/GoogleApiServerUtils.ts +++ b/src/server/apis/google/GoogleApiServerUtils.ts @@ -1,6 +1,6 @@ import { google } from "googleapis"; import { OAuth2Client, Credentials, OAuth2ClientOptions } from "google-auth-library"; -import { Opt } from "../../../new_fields/Doc"; +import { Opt } from "../../../fields/Doc"; import { GaxiosResponse } from "gaxios"; import request = require('request-promise'); import * as qs from "query-string"; diff --git a/src/server/database.ts b/src/server/database.ts index ed9a246e3..a5f23c4b1 100644 --- a/src/server/database.ts +++ b/src/server/database.ts @@ -1,6 +1,6 @@ import * as mongodb from 'mongodb'; import { Transferable } from './Message'; -import { Opt } from '../new_fields/Doc'; +import { Opt } from '../fields/Doc'; import { Utils, emptyFunction } from '../Utils'; import { Credentials } from 'google-auth-library'; import { GoogleApiServerUtils } from './apis/google/GoogleApiServerUtils'; diff --git a/test/test.ts b/test/test.ts index 245733e9b..5fc156b46 100644 --- a/test/test.ts +++ b/test/test.ts @@ -8,10 +8,10 @@ const dom = new JSDOM("", { import { autorun, reaction } from "mobx"; -import { Doc } from '../src/new_fields/Doc'; -import { Cast } from '../src/new_fields/Types'; -import { createSchema, makeInterface, defaultSpec } from '../src/new_fields/Schema'; -import { ImageField } from '../src/new_fields/URLField'; +import { Doc } from '../src/fields/Doc'; +import { Cast } from '../src/fields/Types'; +import { createSchema, makeInterface, defaultSpec } from '../src/fields/Schema'; +import { ImageField } from '../src/fields/URLField'; describe("Document", () => { it('should hold fields', () => { const key = "Test"; -- cgit v1.2.3-70-g09d2 From fb922ed8ddad8e088f44886385772d55ea7971bb Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Fri, 15 May 2020 11:05:04 -0400 Subject: fixed frame animation --- .../views/collections/collectionFreeForm/CollectionFreeFormView.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/client/views/collections') diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 3a55e805e..84a5bd733 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -128,7 +128,7 @@ export class CollectionFreeFormView extends CollectionSubView { doc["x-indexed"] = new List(numberRange(timecode + 1).map(i => NumCast(doc.x))); - doc["x-indexed"] = new List(numberRange(timecode + 1).map(i => NumCast(doc.y))); + doc["y-indexed"] = new List(numberRange(timecode + 1).map(i => NumCast(doc.y))); doc.timecode = ComputedField.MakeFunction("collection.timecode", {}, { collection: this.props.Document }); doc.x = ComputedField.MakeInterpolated("x", "timecode"); doc.y = ComputedField.MakeInterpolated("y", "timecode"); @@ -1160,8 +1160,8 @@ export class CollectionFreeFormView extends CollectionSubView { const xindexed = Cast(doc['x-indexed'], listSpec("number"), null); const yindexed = Cast(doc['y-indexed'], listSpec("number"), null); - xindexed.length <= timecode && xindexed.push(NumCast(doc.x)); - yindexed.length <= timecode && yindexed.push(NumCast(doc.y)); + xindexed.length <= timecode + 1 && xindexed.push(NumCast(doc.x)); + yindexed.length <= timecode + 1 && yindexed.push(NumCast(doc.y)); }); this.childDocs.map(doc => doc.transition = "transform 1s"); this.props.Document.timecode = Math.max(0, timecode + 1); -- cgit v1.2.3-70-g09d2 From 61dcd6a0e23384e68a7d7f2f9e0143741f5cbf56 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Fri, 15 May 2020 17:36:39 -0400 Subject: moving toward a proper slide transition system --- src/client/views/DocumentDecorations.tsx | 2 +- src/client/views/MainView.tsx | 5 +- .../views/collections/CollectionCarouselView.tsx | 5 +- .../CollectionFreeFormLayoutEngines.tsx | 4 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 118 ++++++++++----------- .../views/nodes/CollectionFreeFormDocumentView.tsx | 58 +++++++++- src/fields/ScriptField.ts | 8 +- 7 files changed, 128 insertions(+), 72 deletions(-) (limited to 'src/client/views/collections') diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index fc7c16296..6639f1cce 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -483,7 +483,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
{`${this.selectionTitle}`}
- + ; bounds.x = Math.max(0, bounds.x - this._resizeBorderWidth / 2) + this._resizeBorderWidth / 2; bounds.y = Math.max(0, bounds.y - this._resizeBorderWidth / 2 - this._titleHeight) + this._resizeBorderWidth / 2 + this._titleHeight; diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 978cf7868..f58313f06 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -1,6 +1,6 @@ import { library } from '@fortawesome/fontawesome-svg-core'; import { - faTrashAlt, faAngleRight, faBell, faTrash, faCamera, faExpand, faCaretDown, faCaretRight, faCaretSquareDown, faCaretSquareRight, faArrowsAltH, faPlus, faMinus, + faTrashAlt, faAngleRight, faBell, faTrash, faCamera, faExpand, faCaretDown, faCaretLeft, faCaretRight, faCaretSquareDown, faCaretSquareRight, faArrowsAltH, faPlus, faMinus, faTerminal, faToggleOn, faFile as fileSolid, faExternalLinkAlt, faLocationArrow, faSearch, faFileDownload, faStop, faCalculator, faWindowMaximize, faAddressCard, faQuestionCircle, faArrowLeft, faArrowRight, faArrowDown, faArrowUp, faBolt, faBullseye, faCaretUp, faCat, faCheck, faChevronRight, faClipboard, faClone, faCloudUploadAlt, faCommentAlt, faCompressArrowsAlt, faCut, faEllipsisV, faEraser, faExclamation, faFileAlt, faFileAudio, faFilePdf, faFilm, faFilter, faFont, faGlobeAsia, faHighlighter, @@ -121,6 +121,8 @@ export class MainView extends React.Component { library.add(faCamera); library.add(faExpand); library.add(faCaretDown); + library.add(faCaretUp); + library.add(faCaretLeft); library.add(faCaretRight); library.add(faCaretSquareDown); library.add(faCaretSquareRight); @@ -168,7 +170,6 @@ export class MainView extends React.Component { library.add(faThumbtack); library.add(faLongArrowAltRight); library.add(faCheck); - library.add(faCaretUp); library.add(faFilter); library.add(faBullseye); library.add(faArrowLeft); diff --git a/src/client/views/collections/CollectionCarouselView.tsx b/src/client/views/collections/CollectionCarouselView.tsx index 39bb9bc23..f65a89422 100644 --- a/src/client/views/collections/CollectionCarouselView.tsx +++ b/src/client/views/collections/CollectionCarouselView.tsx @@ -9,7 +9,6 @@ import { DragManager } from '../../util/DragManager'; import { ContentFittingDocumentView } from '../nodes/ContentFittingDocumentView'; import "./CollectionCarouselView.scss"; import { CollectionSubView } from './CollectionSubView'; -import { faCaretLeft, faCaretRight } from '@fortawesome/free-solid-svg-icons'; import { Doc } from '../../../fields/Doc'; import { FormattedTextBox } from '../nodes/formattedText/FormattedTextBox'; import { ContextMenu } from '../ContextMenu'; @@ -76,10 +75,10 @@ export class CollectionCarouselView extends CollectionSubView(CarouselDocument) @computed get buttons() { return <>
- +
- +
; } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx index 3860ce2d7..a4fd5384f 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx @@ -25,6 +25,7 @@ export interface ViewDefBounds { fontSize?: number; highlight?: boolean; color?: string; + opacity?: number; replica?: string; pair?: { layout: Doc, data?: Doc }; } @@ -37,6 +38,7 @@ export interface PoolData { width?: number; height?: number; color?: string; + opacity?: number; transition?: string; highlight?: boolean; replica: string; @@ -416,7 +418,7 @@ function normalizeResults( height: newPosRaw.height! * scale, pair: ele[1].pair }; - poolData.set(newPos.pair.layout[Id] + (newPos.replica || ""), { transition: "transform 1s", ...newPos }); + poolData.set(newPos.pair.layout[Id] + (newPos.replica || ""), { transition: "all 1s", ...newPos }); } }); diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index bf679309c..751ee03d2 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -46,6 +46,7 @@ import React = require("react"); import { CollectionViewType } from "../CollectionView"; import { Timeline } from "../../animationtimeline/Timeline"; import { SnappingManager } from "../../../util/SnappingManager"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; library.add(faEye as any, faTable, faPaintBrush, faExpandArrowsAlt, faCompressArrowsAlt, faCompass, faUpload, faBraille, faChalkboard, faFileUpload); @@ -53,6 +54,7 @@ export const panZoomSchema = createSchema({ _panX: "number", _panY: "number", scale: "number", + timecode: "number", arrangeScript: ScriptField, arrangeInit: ScriptField, useClusters: "boolean", @@ -124,15 +126,8 @@ export class CollectionFreeFormView extends CollectionSubView { - const timecode = Cast(this.props.Document.timecode, "number", null); - if (timecode !== undefined) { - ((newBox instanceof Doc) ? [newBox] : newBox).map(doc => { - doc["x-indexed"] = new List(numberRange(timecode + 1).map(i => NumCast(doc.x))); - doc["y-indexed"] = new List(numberRange(timecode + 1).map(i => NumCast(doc.y))); - doc.timecode = ComputedField.MakeFunction("collection.timecode", {}, { collection: this.props.Document }); - doc.x = ComputedField.MakeInterpolated("x", "timecode"); - doc.y = ComputedField.MakeInterpolated("y", "timecode"); - }); + if (this.Document.timecode !== undefined) { + CollectionFreeFormDocumentView.setupKeyframes((newBox instanceof Doc) ? [newBox] : newBox, this.Document.timecode, this.props.Document); } if (newBox instanceof Doc) { @@ -145,6 +140,25 @@ export class CollectionFreeFormView extends CollectionSubView { + if (this.props.Document.timecode === undefined) { + this.props.Document.timecode = 0; + CollectionFreeFormDocumentView.setupKeyframes(this.childDocs, 0, this.props.Document); + } + const timecode = NumCast(this.props.Document.timecode); + CollectionFreeFormDocumentView.updateKeyframe(this.childDocs, timecode); + this.props.Document.timecode = Math.max(0, timecode + 1); + } + @undoBatch + @action + prevKeyframe = (): void => { + CollectionFreeFormDocumentView.gotoKeyframe(this.childDocs.slice()); + this.props.Document.timecode = Math.max(0, NumCast(this.props.Document.timecode) - 1); + } + private selectDocuments = (docs: Doc[]) => { SelectionManager.DeselectAll(); docs.map(doc => DocumentManager.Instance.getDocumentView(doc)).map(dv => dv && SelectionManager.SelectDoc(dv, true)); @@ -185,8 +199,12 @@ export class CollectionFreeFormView extends CollectionSubView { - if (this.props.Document.timecode === undefined) { - this.childDocs.map(doc => { - this.props.Document.timecode = 0; - doc["x-indexed"] = new List([NumCast(doc.x)]); - doc["y-indexed"] = new List([NumCast(doc.y)]); - doc.timecode = ComputedField.MakeFunction("collection.timecode", {}, { collection: this.props.Document }); - doc.x = ComputedField.MakeInterpolated("x", "timecode"); - doc.y = ComputedField.MakeInterpolated("y", "timecode"); - }); - } - const timecode = NumCast(this.props.Document.timecode); - this.childDocs.map(doc => { - const xindexed = Cast(doc['x-indexed'], listSpec("number"), null); - const yindexed = Cast(doc['y-indexed'], listSpec("number"), null); - xindexed.length <= timecode + 1 && xindexed.push(NumCast(doc.x)); - yindexed.length <= timecode + 1 && yindexed.push(NumCast(doc.y)); - }); - this.childDocs.map(doc => doc.transition = "transform 1s"); - this.props.Document.timecode = Math.max(0, timecode + 1); - setTimeout(() => this.childDocs.map(doc => doc.transition = undefined), 1010); - } - @undoBatch - @action - backupInterpolated = (): void => { - this.childDocs.map(doc => doc.transition = "transform 1s"); - this.props.Document.timecode = Math.max(0, NumCast(this.props.Document.timecode) - 1); - setTimeout(() => this.childDocs.map(doc => doc.transition = undefined), 1010); - } - - private thumbIdentifier?: number; onContextMenu = (e: React.MouseEvent) => { @@ -1185,8 +1175,8 @@ export class CollectionFreeFormView extends CollectionSubView 0 ? this.placeholder : this.marqueeView} - + {this.isAnnotationOverlay ? (null) : + <> +
+ +
+
+ {NumCast(this.props.Document.timecode)} +
+
+ +
+ }
{ x: number, y: number, zIndex?: number, highlight?: boolean, z: number, transition?: string } | undefined; + dataProvider?: (doc: Doc, replica: string) => { x: number, y: number, zIndex?: number, opacity?: number, highlight?: boolean, z: number, transition?: string } | undefined; sizeProvider?: (doc: Doc, replica: string) => { width: number, height: number } | undefined; zIndex?: number; highlight?: boolean; @@ -35,6 +40,7 @@ export class CollectionFreeFormDocumentView extends DocComponent (i <= time && x !== undefined) || p === undefined ? x : p, undefined as any as number), + y: Cast(doc["y-indexed"], listSpec("number"), []).reduce((p, y, i) => (i <= time && y !== undefined) || p === undefined ? y : p, undefined as any as number), + opacity: Cast(doc["opacity-indexed"], listSpec("number"), []).reduce((p, o, i) => i <= time || p === undefined ? o : p, undefined as any as number), + }); + } + + public static setValues(timecode: number, d: Doc, x?: number, y?: number, opacity?: number) { + Cast(d["x-indexed"], listSpec("number"), [])[timecode] = x as any as number; + Cast(d["y-indexed"], listSpec("number"), null)[timecode] = y as any as number; + Cast(d["opacity-indexed"], listSpec("number"), null)[timecode] = opacity as any as number; + } + public static updateKeyframe(docs: Doc[], timecode: number) { + docs.forEach(doc => { + const xindexed = Cast(doc['x-indexed'], listSpec("number"), null); + const yindexed = Cast(doc['y-indexed'], listSpec("number"), null); + const opacityindexed = Cast(doc['opacity-indexed'], listSpec("number"), null); + xindexed.length <= timecode + 1 && xindexed.push(undefined as any as number); + yindexed.length <= timecode + 1 && yindexed.push(undefined as any as number); + opacityindexed.length <= timecode + 1 && opacityindexed.push(undefined as any as number); + doc.transition = "all 1s"; + }); + setTimeout(() => docs.forEach(doc => doc.transition = undefined), 1010); + } + + public static gotoKeyframe(docs: Doc[]) { + docs.forEach(doc => doc.transition = "all 1s"); + setTimeout(() => docs.forEach(doc => doc.transition = undefined), 1010); + } + + public static setupKeyframes(docs: Doc[], timecode: number, collection: Doc) { + docs.forEach(doc => { + doc["x-indexed"] = new List(numberRange(timecode).map(i => undefined) as any as number[]); + doc["y-indexed"] = new List(numberRange(timecode).map(i => undefined) as any as number[]); + doc["opacity-indexed"] = new List(numberRange(timecode).map(i => 0)); + (doc["x-indexed"] as any).push(NumCast(doc.x)); + (doc["y-indexed"] as any).push(NumCast(doc.y)); + (doc["opacity-indexed"] as any).push(NumCast(doc.opacity, 1)); + doc.timecode = ComputedField.MakeFunction("collection.timecode", {}, { collection }); + doc.x = ComputedField.MakeInterpolated("x", "timecode"); + doc.y = ComputedField.MakeInterpolated("y", "timecode"); + doc.opacity = ComputedField.MakeInterpolated("opacity", "timecode"); + }); + } + nudge = (x: number, y: number) => { this.props.Document.x = NumCast(this.props.Document.x) + x; this.props.Document.y = NumCast(this.props.Document.y) + y; @@ -79,7 +132,7 @@ export class CollectionFreeFormDocumentView extends DocComponent (i <= index && x !== undefined) || p === undefined ? x : p, undefined as any) +}); + export namespace ComputedField { let useComputed = true; export function DisableComputedFields() { -- cgit v1.2.3-70-g09d2 From b9a3c4adb81b38f550f0ab18be5c40a38aea4597 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Fri, 15 May 2020 20:59:35 -0400 Subject: cleaned up frame animation buttons. Added server code for https? removed unused devserver from webpack.config --- .../collectionFreeForm/CollectionFreeFormView.scss | 18 ++++++ .../collectionFreeForm/CollectionFreeFormView.tsx | 6 +- src/server/server_Initialization.ts | 17 +++++ webpack.config.js | 74 +++++++++------------- 4 files changed, 69 insertions(+), 46 deletions(-) (limited to 'src/client/views/collections') diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss index 60c39c825..7a84fcde1 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss @@ -41,6 +41,24 @@ // touch action none means that the browser will handle none of the touch actions. this allows us to implement our own actions. touch-action: none; + .fwdKeyframe, .numKeyframe, .backKeyframe{ + cursor: pointer; + position: absolute; + width: 20; + height:20; + bottom:0; + background:gray; + } + .backKeyframe { + right:45; + } + .numKeyframe { + right:25; + } + .fwdKeyframe { + right:5; + } + .collectionfreeformview-placeholder { background: gray; width: 100%; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 751ee03d2..4be671a76 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1352,13 +1352,13 @@ export class CollectionFreeFormView extends CollectionSubView {this.isAnnotationOverlay ? (null) : <> -
+
-
+
{NumCast(this.props.Document.timecode)}
-
+
} diff --git a/src/server/server_Initialization.ts b/src/server/server_Initialization.ts index 4b3094616..14b0dedc3 100644 --- a/src/server/server_Initialization.ts +++ b/src/server/server_Initialization.ts @@ -53,6 +53,23 @@ export default async function InitializeServer(routeSetter: RouteSetter) { logPort("server", serverPort); console.log(); }); + + // var express = require('express') + // var fs = require('fs') + // var https = require('https') + // var app = express() + + // app.get('/', function (req, res) { + // res.send('hello world') + // }) + + // https.createServer({ + // key: fs.readFileSync('server.key'), + // cert: fs.readFileSync('server.cert') + // }, app) + // .listen(3000, function () { + // console.log('Example app listening on port 3000! Go to https://localhost:3000/') + // }) disconnect = async () => new Promise(resolve => server.close(resolve)); return isRelease; diff --git a/webpack.config.js b/webpack.config.js index 67d492e1f..480ed7aa3 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -63,57 +63,45 @@ module.exports = { }, module: { rules: [{ - test: [/\.tsx?$/], - use: [{ - loader: 'ts-loader', - options: { - transpileOnly: true - } - }] + test: [/\.tsx?$/], + use: [{ + loader: 'ts-loader', + options: { + transpileOnly: true + } + }] + }, + { + test: /\.scss|css$/, + use: [{ + loader: "style-loader" }, { - test: /\.scss|css$/, - use: [{ - loader: "style-loader" - }, - { - loader: "css-loader" - }, - { - loader: "sass-loader" - } - ] + loader: "css-loader" }, { - test: /\.(jpg|png|pdf)$/, - use: [{ - loader: 'file-loader' - }] - }, - { - test: /\.(png|jpg|gif)$/i, - use: [{ - loader: 'url-loader', - options: { - limit: 8192 - } - }] + loader: "sass-loader" } + ] + }, + { + test: /\.(jpg|png|pdf)$/, + use: [{ + loader: 'file-loader' + }] + }, + { + test: /\.(png|jpg|gif)$/i, + use: [{ + loader: 'url-loader', + options: { + limit: 8192 + } + }] + } ] }, plugins, - devServer: { - compress: false, - host: "localhost", - contentBase: path.join(__dirname, 'deploy'), - port: 4321, - hot: true, - https: false, - overlay: { - warnings: true, - errors: true - } - }, externals: [ 'child_process' ] -- cgit v1.2.3-70-g09d2 From a0dc46dc565418fef9a257508a92c788c4ec50af Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Sat, 16 May 2020 00:01:06 -0400 Subject: fixed some issues with frame animation. added comic rendering mode. added server certficate keys to get SSL to work? --- src/client/views/MainView.tsx | 6 ++-- .../collectionFreeForm/CollectionFreeFormView.tsx | 16 +++++---- .../collections/collectionFreeForm/MarqueeView.tsx | 2 +- .../views/nodes/CollectionFreeFormDocumentView.tsx | 14 ++++++-- src/client/views/nodes/DocumentView.tsx | 2 +- .../views/nodes/formattedText/FormattedTextBox.tsx | 3 +- src/server/server_Initialization.ts | 39 +++++++++++----------- 7 files changed, 48 insertions(+), 34 deletions(-) (limited to 'src/client/views/collections') diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index f58313f06..3e4833052 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -256,8 +256,9 @@ export class MainView extends React.Component { const mainDoc = 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`); - mainDoc.contextMenuScripts = new List([toggleTheme!]); - mainDoc.contextMenuLabels = new List(["Toggle Theme Colors"]); + const toggleComic = ScriptField.MakeScript(`toggleComicMode()`); + mainDoc.contextMenuScripts = new List([toggleTheme!, toggleComic!]); + mainDoc.contextMenuLabels = new List(["Toggle Theme Colors", "Toggle Comic Mode"]); Doc.AddDocToList(workspaces, "data", mainDoc); // bcz: strangely, we need a timeout to prevent exceptions/issues initializing GoldenLayout (the rendering engine for Main Container) @@ -629,3 +630,4 @@ export class MainView extends React.Component { } } 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" }); diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 4be671a76..d27f3bb0d 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -155,6 +155,10 @@ export class CollectionFreeFormView extends CollectionSubView { + if (this.props.Document.timecode === undefined) { + this.props.Document.timecode = 0; + CollectionFreeFormDocumentView.setupKeyframes(this.childDocs, 0, this.props.Document); + } CollectionFreeFormDocumentView.gotoKeyframe(this.childDocs.slice()); this.props.Document.timecode = Math.max(0, NumCast(this.props.Document.timecode) - 1); } @@ -1095,7 +1099,7 @@ export class CollectionFreeFormView extends CollectionSubView {this.isAnnotationOverlay ? (null) : <> -
- +
+
-
+
{NumCast(this.props.Document.timecode)}
-
- +
+
}
docs.forEach(doc => doc.transition = undefined), 1010); @@ -129,6 +129,7 @@ export class CollectionFreeFormDocumentView extends DocComponent this.nativeHeight; render() { TraceMobx(); + const backgroundColor = StrCast(this.layoutDoc._backgroundColor) || StrCast(this.layoutDoc.backgroundColor) || StrCast(this.Document.backgroundColor) || this.props.backgroundColor?.(this.Document); return
+ {Doc.UserDoc().renderStyle !== "comic" ? (null) : +
+ + + +
} {!this.props.fitToBox ? (Docu render() { if (!(this.props.Document instanceof Doc)) return (null); - const backgroundColor = StrCast(this.layoutDoc._backgroundColor) || StrCast(this.layoutDoc.backgroundColor) || StrCast(this.Document.backgroundColor) || this.props.backgroundColor?.(this.Document); + const backgroundColor = Doc.UserDoc().renderStyle === "comic" ? undefined : StrCast(this.layoutDoc._backgroundColor) || StrCast(this.layoutDoc.backgroundColor) || StrCast(this.Document.backgroundColor) || this.props.backgroundColor?.(this.Document); const finalColor = this.layoutDoc.type === DocumentType.FONTICON || this.layoutDoc._viewType === CollectionViewType.Linear ? undefined : backgroundColor; const fullDegree = Doc.isBrushedHighlightedDegree(this.props.Document); const borderRounding = this.layoutDoc.borderRounding; diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index 5e33e7e70..a00eb366b 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -206,6 +206,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp if ((!curTemp && !curProto) || curText || curLayout?.Data.includes("dash")) { // if no template, or there's text that didn't come from the layout template, write it to the document. (if this is driven by a template, then this overwrites the template text which is intended) if (json !== curLayout?.Data) { !curText && tx.storedMarks?.map(m => m.type.name === "pFontSize" && (Doc.UserDoc().fontSize = this.layoutDoc._fontSize = m.attrs.fontSize)); + !curText && tx.storedMarks?.map(m => m.type.name === "pFontFamily" && (Doc.UserDoc().fontFamily = this.layoutDoc._fontFamily = m.attrs.fontFamily)); this.dataDoc[this.props.fieldKey] = new RichTextField(json, curText); this.dataDoc[this.props.fieldKey + "-noTemplate"] = (curTemp?.Text || "") !== curText; // mark the data field as being split from the template if it has been edited } @@ -1230,7 +1231,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp style={{ width: "100%", height: this.props.height ? this.props.height : this.layoutDoc._autoHeight && this.props.renderDepth ? "max-content" : `calc(100% - ${this.props.ChromeHeight?.() || 0}px`, - background: this.props.background ? this.props.background : StrCast(this.layoutDoc[this.props.fieldKey + "-backgroundColor"], this.props.hideOnLeave ? "rgba(0,0,0 ,0.4)" : ""), + background: Doc.UserDoc().renderStyle === "comic" ? "transparent" : this.props.background ? this.props.background : StrCast(this.layoutDoc[this.props.fieldKey + "-backgroundColor"], this.props.hideOnLeave ? "rgba(0,0,0 ,0.4)" : ""), opacity: this.props.hideOnLeave ? (this._entered ? 1 : 0.1) : 1, color: this.props.color ? this.props.color : StrCast(this.layoutDoc[this.props.fieldKey + "-color"], this.props.hideOnLeave ? "white" : "inherit"), pointerEvents: interactive ? "none" : undefined, diff --git a/src/server/server_Initialization.ts b/src/server/server_Initialization.ts index 14b0dedc3..6866b01e3 100644 --- a/src/server/server_Initialization.ts +++ b/src/server/server_Initialization.ts @@ -22,6 +22,7 @@ import { publicDirectory } from '.'; import { logPort, } from './ActionUtilities'; import { blue, yellow } from 'colors'; import * as cors from "cors"; +var https = require('https'); /* RouteSetter is a wrapper around the server that prevents the server from being exposed. */ @@ -49,27 +50,25 @@ export default async function InitializeServer(routeSetter: RouteSetter) { registerRelativePath(app); const serverPort = isRelease ? Number(process.env.serverPort) : 1050; - const server = app.listen(serverPort, () => { - logPort("server", serverPort); - console.log(); - }); - // var express = require('express') - // var fs = require('fs') - // var https = require('https') - // var app = express() - - // app.get('/', function (req, res) { - // res.send('hello world') - // }) - - // https.createServer({ - // key: fs.readFileSync('server.key'), - // cert: fs.readFileSync('server.cert') - // }, app) - // .listen(3000, function () { - // console.log('Example app listening on port 3000! Go to https://localhost:3000/') - // }) + let server: any; + if (isRelease) { + server = https.createServer({ + key: fs.readFileSync(`./${process.env.serverName}.key`), + cert: fs.readFileSync(`./${process.env.serverName}.cert`) + }, app); + server.listen(serverPort, function () { + logPort("server", serverPort); + console.log(); + // console.log('Example app listening on port 3000! Go to https://localhost:3000/') + }); + } else { + server = app.listen(serverPort, () => { + logPort("server", serverPort); + console.log(); + }); + } + disconnect = async () => new Promise(resolve => server.close(resolve)); return isRelease; -- cgit v1.2.3-70-g09d2 From ceb616873f76ee19549306a735a09697a56291a2 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Sat, 16 May 2020 20:03:34 -0400 Subject: fixed copying of computed fields (bug when aliasing animated collections). fixed opacity for presentation view. renamed timecode to match with video timecodes. --- .../views/collections/CollectionStackingView.tsx | 1 + src/client/views/collections/CollectionSubView.tsx | 1 + src/client/views/collections/CollectionView.tsx | 1 + .../collectionFreeForm/CollectionFreeFormView.tsx | 45 +++++++++++----------- .../views/nodes/CollectionFreeFormDocumentView.tsx | 15 ++++---- src/client/views/nodes/DocumentView.tsx | 5 ++- src/client/views/nodes/PresBox.tsx | 3 +- .../views/presentationview/PresElementBox.tsx | 1 + src/fields/Doc.ts | 2 +- src/fields/ScriptField.ts | 8 +++- 10 files changed, 47 insertions(+), 35 deletions(-) (limited to 'src/client/views/collections') diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index cc6077d98..421bf90c1 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -213,6 +213,7 @@ export class CollectionStackingView extends CollectionSubView(StackingDocument) onClick={this.onChildClickHandler} onDoubleClick={this.onChildDoubleClickHandler} ScreenToLocalTransform={dxf} + opacity={this.props.childOpacity} focus={this.focusDocument} ContainingCollectionDoc={this.props.CollectionView?.props.Document} ContainingCollectionView={this.props.CollectionView} diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index c9eb08b45..0827f8782 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -44,6 +44,7 @@ export interface SubCollectionViewProps extends CollectionViewProps { CollectionView: Opt; children?: never | (() => JSX.Element[]) | React.ReactNode; ChildLayoutTemplate?: () => Doc; + childOpacity?:() => number; ChildLayoutString?: string; childClickScript?: ScriptField; childDoubleClickScript?: ScriptField; diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 3b2e5e4fc..acb66acdb 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -72,6 +72,7 @@ export interface CollectionViewCustomProps { filterAddDocument: (doc: Doc | Doc[]) => boolean; // allows a document that renders a Collection view to filter or modify any documents added to the collection (see PresBox for an example) childLayoutTemplate?: () => Opt; // specify a layout Doc template to use for children of the collection childLayoutString?: string; // specify a layout string to use for children of the collection + childOpacity?:() => number; } export interface CollectionRenderProps { diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index d27f3bb0d..e66e95d81 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -54,7 +54,8 @@ export const panZoomSchema = createSchema({ _panX: "number", _panY: "number", scale: "number", - timecode: "number", + currentTimecode: "number", + displayTimecode: "number", arrangeScript: ScriptField, arrangeInit: ScriptField, useClusters: "boolean", @@ -126,8 +127,8 @@ export class CollectionFreeFormView extends CollectionSubView { - if (this.Document.timecode !== undefined) { - CollectionFreeFormDocumentView.setupKeyframes((newBox instanceof Doc) ? [newBox] : newBox, this.Document.timecode, this.props.Document); + if (this.Document.currentTimecode !== undefined) { + CollectionFreeFormDocumentView.setupKeyframes((newBox instanceof Doc) ? [newBox] : newBox, this.Document.currentTimecode, this.props.Document); } if (newBox instanceof Doc) { @@ -144,23 +145,24 @@ export class CollectionFreeFormView extends CollectionSubView { - if (this.props.Document.timecode === undefined) { - this.props.Document.timecode = 0; + const currentTimecode = this.Document.currentTimecode; + if (currentTimecode === undefined) { + this.Document.currentTimecode = 0; CollectionFreeFormDocumentView.setupKeyframes(this.childDocs, 0, this.props.Document); } - const timecode = NumCast(this.props.Document.timecode); - CollectionFreeFormDocumentView.updateKeyframe(this.childDocs, timecode); - this.props.Document.timecode = Math.max(0, timecode + 1); + CollectionFreeFormDocumentView.updateKeyframe(this.childDocs, currentTimecode || 0); + this.Document.currentTimecode = Math.max(0, (currentTimecode || 0) + 1); } @undoBatch @action prevKeyframe = (): void => { - if (this.props.Document.timecode === undefined) { - this.props.Document.timecode = 0; + const currentTimecode = this.Document.currentTimecode; + if (currentTimecode === undefined) { + this.Document.currentTimecode = 0; CollectionFreeFormDocumentView.setupKeyframes(this.childDocs, 0, this.props.Document); } CollectionFreeFormDocumentView.gotoKeyframe(this.childDocs.slice()); - this.props.Document.timecode = Math.max(0, NumCast(this.props.Document.timecode) - 1); + this.Document.currentTimecode = Math.max(0, (currentTimecode || 0) - 1); } private selectDocuments = (docs: Doc[]) => { @@ -203,8 +205,8 @@ export class CollectionFreeFormView extends CollectionSubView) { const layoutDocs = this.childLayoutPairs.map(pair => pair.layout); const initResult = this.Document.arrangeInit && this.Document.arrangeInit.script.run({ docs: layoutDocs, collection: this.Document }, console.log); - const state = initResult && initResult.success ? initResult.result.scriptState : undefined; - const elements = initResult && initResult.success ? this.viewDefsToJSX(initResult.result.views) : []; + const state = initResult?.success ? initResult.result.scriptState : undefined; + const elements = initResult?.success ? this.viewDefsToJSX(initResult.result.views) : []; this.childLayoutPairs.filter(pair => this.isCurrent(pair.layout)).map((pair, i) => { const pos = this.getCalculatedPositions({ pair, index: i, collection: this.Document, docs: layoutDocs, state }); @@ -1075,7 +1074,7 @@ export class CollectionFreeFormView extends CollectionSubView 0 ? this.placeholder : this.marqueeView} - {this.isAnnotationOverlay ? (null) : + {this.isAnnotationOverlay || !this.props.isSelected() ? (null) : <>
- {NumCast(this.props.Document.timecode)} + {NumCast(this.props.Document.currentTimecode)}
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index c9bb543f1..5f0e28db2 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -36,11 +36,11 @@ export class CollectionFreeFormDocumentView extends DocComponent (this.sizeProvider?.height || this.props.PanelHeight?.()); getTransform = (): Transform => this.props.ScreenToLocalTransform().translate(-this.X, -this.Y).scale(1 / this.contentScaling()); focusDoc = (doc: Doc) => this.props.focus(doc, false); + opacity = () => this.Opacity; NativeWidth = () => this.nativeWidth; NativeHeight = () => this.nativeHeight; render() { @@ -144,7 +145,6 @@ export class CollectionFreeFormDocumentView extends DocComponent void; backgroundHalo?: () => boolean; backgroundColor?: (doc: Doc) => string | undefined; + opacity?: () => number; ChromeHeight?: () => number; dontRegisterView?: boolean; layoutKey?: string; @@ -1119,6 +1120,8 @@ export class DocumentView extends DocComponent(Docu render() { if (!(this.props.Document instanceof Doc)) return (null); const backgroundColor = Doc.UserDoc().renderStyle === "comic" ? undefined : StrCast(this.layoutDoc._backgroundColor) || StrCast(this.layoutDoc.backgroundColor) || StrCast(this.Document.backgroundColor) || this.props.backgroundColor?.(this.Document); + const opacity = Cast(this.layoutDoc._opacity, "number", Cast(this.layoutDoc.opacity, "number", Cast(this.Document.opacity, "number", null))); + const finalOpacity = this.props.opacity ? this.props.opacity() : opacity; const finalColor = this.layoutDoc.type === DocumentType.FONTICON || this.layoutDoc._viewType === CollectionViewType.Linear ? undefined : backgroundColor; const fullDegree = Doc.isBrushedHighlightedDegree(this.props.Document); const borderRounding = this.layoutDoc.borderRounding; @@ -1155,7 +1158,7 @@ export class DocumentView extends DocComponent(Docu border: highlighting && borderRounding ? `${highlightStyles[fullDegree]} ${highlightColors[fullDegree]} ${localScale}px` : undefined, boxShadow: this.props.Document.isTemplateForField ? "black 0.2vw 0.2vw 0.8vw" : undefined, background: finalColor, - opacity: this.Document.opacity, + opacity: finalOpacity, fontFamily: StrCast(this.Document._fontFamily, "inherit"), fontSize: Cast(this.Document._fontSize, "number", null) }}> diff --git a/src/client/views/nodes/PresBox.tsx b/src/client/views/nodes/PresBox.tsx index 342a8a215..6edcae417 100644 --- a/src/client/views/nodes/PresBox.tsx +++ b/src/client/views/nodes/PresBox.tsx @@ -5,7 +5,7 @@ import { observer } from "mobx-react"; import { Doc, DocListCast, DocCastAsync } from "../../../fields/Doc"; import { InkTool } from "../../../fields/InkField"; import { BoolCast, Cast, NumCast, StrCast } from "../../../fields/Types"; -import { returnFalse } from "../../../Utils"; +import { returnFalse, returnOne } from "../../../Utils"; import { documentSchema } from "../../../fields/documentSchemas"; import { DocumentManager } from "../../util/DocumentManager"; import { undoBatch } from "../../util/UndoManager"; @@ -316,6 +316,7 @@ export class PresBox extends ViewBoxBaseComponent PanelWidth={this.props.PanelWidth} PanelHeight={this.panelHeight} moveDocument={returnFalse} + childOpacity={returnOne} childLayoutTemplate={this.childLayoutTemplate} filterAddDocument={this.addDocumentFilter} removeDocument={returnFalse} diff --git a/src/client/views/presentationview/PresElementBox.tsx b/src/client/views/presentationview/PresElementBox.tsx index 280ba9093..26c8aa80a 100644 --- a/src/client/views/presentationview/PresElementBox.tsx +++ b/src/client/views/presentationview/PresElementBox.tsx @@ -177,6 +177,7 @@ export class PresElementBox extends ViewBoxBaseComponent this._lastComputedResult = this.script.run({ this: doc, self: Cast(doc.rootDocument, Doc, null) || doc, _last_: this._lastComputedResult }, console.log).result; + [Copy](): ObjectField { + return new ComputedField(this.script); + } + constructor(script: CompiledScript, setterscript?: CompiledScript) { super(script, - !setterscript && script?.originalScript.includes("self.timecode") ? - ScriptField.CompileScript("self['x' + self.timecode] = value", { value: "any" }, true) : setterscript); + !setterscript && script?.originalScript.includes("self.displayTimecode") ? + ScriptField.CompileScript("self['x' + self.displayTimecode] = value", { value: "any" }, true) : setterscript); } public static MakeScript(script: string, params: object = {}) { -- cgit v1.2.3-70-g09d2 From 2882dfce48e434f0c0b6a5837fc6212cad1df131 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Sun, 17 May 2020 19:43:53 -0400 Subject: fixed presentations to step through slides with "animations" --- .../collectionFreeForm/CollectionFreeFormView.tsx | 1 + src/client/views/nodes/PresBox.tsx | 24 +++++++++++++++++----- src/fields/ScriptField.ts | 6 ------ 3 files changed, 20 insertions(+), 11 deletions(-) (limited to 'src/client/views/collections') diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index e66e95d81..dc7d7918a 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -152,6 +152,7 @@ export class CollectionFreeFormView extends CollectionSubView @action next = () => { this.updateCurrentPresentation(); - if (this.childDocs[this.itemIndex + 1] !== undefined) { + const presTargetDoc = Cast(this.childDocs[this.itemIndex].presentationTargetDoc, Doc, null); + const lastFrame = Cast(presTargetDoc.lastTimecode, "number", null); + const curFrame = NumCast(presTargetDoc.currentTimecode); + if (lastFrame !== undefined && curFrame < lastFrame) { + presTargetDoc.currentTimecode = curFrame + 1; + } + else if (this.childDocs[this.itemIndex + 1] !== undefined) { let nextSelected = this.itemIndex + 1; this.gotoDocument(nextSelected, this.itemIndex); @@ -188,11 +194,15 @@ export class PresBox extends ViewBoxBaseComponent //The function that is called when a document is clicked or reached through next or back. //it'll also execute the necessary actions if presentation is playing. - public gotoDocument = (index: number, fromDoc: number) => { + public gotoDocument = action((index: number, fromDoc: number) => { this.updateCurrentPresentation(); Doc.UnBrushAllDocs(); if (index >= 0 && index < this.childDocs.length) { this.rootDoc._itemIndex = index; + const presTargetDoc = Cast(this.childDocs[this.itemIndex].presentationTargetDoc, Doc, null); + if (presTargetDoc.lastTimecode !== undefined) { + presTargetDoc.currentTimecode = 0; + } if (!this.layoutDoc.presStatus) { this.layoutDoc.presStatus = true; @@ -203,7 +213,7 @@ export class PresBox extends ViewBoxBaseComponent this.hideIfNotPresented(index); this.showAfterPresented(index); } - } + }) //The function that starts or resets presentaton functionally, depending on status flag. startOrResetPres = () => { @@ -286,7 +296,11 @@ export class PresBox extends ViewBoxBaseComponent (this.layoutDoc.forceActive || this.props.isSelected(outsideReaction) || this._isChildActive || this.props.renderDepth === 0) ? true : false) render() { - this.rootDoc.presOrderedDocs = new List(this.childDocs.map((child, i) => child)); + console.log("render = " + this.layoutDoc.title + " " + this.layoutDoc.presStatus); + const presOrderedDocs = DocListCast(this.rootDoc.presOrderedDocs); + if (presOrderedDocs.length != this.childDocs.length || presOrderedDocs.some((pd, i) => pd !== this.childDocs[i])) { + this.rootDoc.presOrderedDocs = new List(this.childDocs.slice()); + } const mode = StrCast(this.rootDoc._viewType) as CollectionViewType; return
diff --git a/src/fields/ScriptField.ts b/src/fields/ScriptField.ts index 3a4cdbdf8..566390c0d 100644 --- a/src/fields/ScriptField.ts +++ b/src/fields/ScriptField.ts @@ -144,12 +144,6 @@ export class ComputedField extends ScriptField { return new ComputedField(this.script); } - constructor(script: CompiledScript, setterscript?: CompiledScript) { - super(script, - !setterscript && script?.originalScript.includes("self.displayTimecode") ? - ScriptField.CompileScript("self['x' + self.displayTimecode] = value", { value: "any" }, true) : setterscript); - } - public static MakeScript(script: string, params: object = {}) { const compiled = ScriptField.CompileScript(script, params, false); return compiled.compiled ? new ComputedField(compiled) : undefined; -- cgit v1.2.3-70-g09d2 From 0aa4b3b260bc8debebe876488a87b2e3aba7b536 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Mon, 18 May 2020 11:00:25 -0400 Subject: fixed sizing of web boxes. added auto linking to dropped web clippings. change linkfollowing to open on right. --- src/client/util/CurrentUserUtils.ts | 2 +- src/client/views/MainView.tsx | 4 +-- src/client/views/collections/CollectionSubView.tsx | 29 +++++++++++++++++++--- src/client/views/nodes/LinkAnchorBox.tsx | 2 +- src/client/views/nodes/WebBox.tsx | 4 ++- 5 files changed, 31 insertions(+), 10 deletions(-) (limited to 'src/client/views/collections') diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 1f25ed790..67da265b3 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -317,7 +317,7 @@ export class CurrentUserUtils { { _width: 250, _height: 250, title: "container" }); } if (doc.emptyWebpage === undefined) { - doc.emptyWebpage = Docs.Create.WebDocument("", { title: "New Webpage", _width: 600, UseCors: true }); + doc.emptyWebpage = Docs.Create.WebDocument("", { title: "New Webpage", _nativeWidth: 850, _nativeHeight: 962, _width: 600, UseCors: true }); } return [ { title: "Drag a collection", label: "Col", icon: "folder", click: 'openOnRight(getCopy(this.dragFactory, true))', drag: 'getCopy(this.dragFactory, true)', dragFactory: doc.emptyCollection as Doc }, diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 481169b2f..4a20c39d4 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -138,9 +138,7 @@ export class MainView extends React.Component { globalPointerUp = () => this.isPointerDown = false; initEventListeners = () => { - window.addEventListener("drop", (e) => { - e.preventDefault(); - }, false); // drop event handler + 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); diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 0827f8782..33c75a274 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -6,14 +6,14 @@ import { Id } from "../../../fields/FieldSymbols"; import { List } from "../../../fields/List"; import { listSpec } from "../../../fields/Schema"; import { ScriptField } from "../../../fields/ScriptField"; -import { Cast, ScriptCast } from "../../../fields/Types"; +import { Cast, ScriptCast, NumCast } from "../../../fields/Types"; import { GestureUtils } from "../../../pen-gestures/GestureUtils"; import { CurrentUserUtils } from "../../util/CurrentUserUtils"; import { Upload } from "../../../server/SharedMediaTypes"; import { Utils } from "../../../Utils"; import { GooglePhotos } from "../../apis/google_docs/GooglePhotosClientUtils"; import { DocServer } from "../../DocServer"; -import { Docs, DocumentOptions } from "../../documents/Documents"; +import { Docs, DocumentOptions, DocUtils } from "../../documents/Documents"; import { DocumentType } from "../../documents/DocumentTypes"; import { Networking } from "../../Network"; import { DragManager, dropActionType } from "../../util/DragManager"; @@ -25,6 +25,8 @@ import { FieldViewProps } from "../nodes/FieldView"; import { FormattedTextBox, GoogleRef } from "../nodes/formattedText/FormattedTextBox"; import { CollectionView } from "./CollectionView"; import React = require("react"); +import { SelectionManager } from "../../util/SelectionManager"; +import { WebField } from "../../../fields/URLField"; export interface CollectionViewProps extends FieldViewProps { addDocument: (document: Doc | Doc[]) => boolean; @@ -44,7 +46,7 @@ export interface SubCollectionViewProps extends CollectionViewProps { CollectionView: Opt; children?: never | (() => JSX.Element[]) | React.ReactNode; ChildLayoutTemplate?: () => Doc; - childOpacity?:() => number; + childOpacity?: () => number; ChildLayoutString?: string; childClickScript?: ScriptField; childDoubleClickScript?: ScriptField; @@ -324,9 +326,28 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T, moreProps?: } }); } else { - const htmlDoc = Docs.Create.HtmlDocument(html, { ...options, title: "-web page-", _width: 300, _height: 300 }); + let srcUrl: string | undefined; + let srcWeb: Doc | undefined; + if (SelectionManager.SelectedDocuments().length) { + srcWeb = SelectionManager.SelectedDocuments()[0].props.Document; + srcUrl = (srcWeb.data as WebField).url.href.match(/http[s]?:\/\/[^/]*/)?.[0]; + } + let reg = new RegExp(Utils.prepend(""), "g"); + const modHtml = srcUrl ? html.replace(reg, srcUrl) : html; + const htmlDoc = Docs.Create.HtmlDocument(modHtml, { ...options, title: "-web page-", _width: 300, _height: 300 }); Doc.GetProto(htmlDoc)["data-text"] = text; this.props.addDocument(htmlDoc); + if (srcWeb) { + const focusNode = (SelectionManager.SelectedDocuments()[0].ContentDiv?.getElementsByTagName("iframe")[0].contentDocument?.getSelection()?.focusNode as any); + const rect = "getBoundingClientRect" in focusNode ? focusNode.getBoundingClientRect() : focusNode?.parentElement.getBoundingClientRect(); + const x = (rect?.x || 0); + const y = NumCast(srcWeb.scrollTop) + (rect?.y || 0); + const anchor = Docs.Create.FreeformDocument([], { _LODdisable: true, _backgroundColor: "transparent", _width: 25, _height: 25, x, y, annotationOn: srcWeb }); + anchor.context = srcWeb; + const key = Doc.LayoutFieldKey(srcWeb); + Doc.AddDocToList(srcWeb, key + "-annotations", anchor); + DocUtils.MakeLink({ doc: htmlDoc }, { doc: anchor }); + } } return; } diff --git a/src/client/views/nodes/LinkAnchorBox.tsx b/src/client/views/nodes/LinkAnchorBox.tsx index 098aa58e9..83245a89c 100644 --- a/src/client/views/nodes/LinkAnchorBox.tsx +++ b/src/client/views/nodes/LinkAnchorBox.tsx @@ -72,7 +72,7 @@ export class LinkAnchorBox extends ViewBoxBaseComponent { - DocumentManager.Instance.FollowLink(this.rootDoc, anchorContainerDoc, document => this.props.addDocTab(document, StrCast(this.layoutDoc.linkOpenLocation, "inTab")), false); + DocumentManager.Instance.FollowLink(this.rootDoc, anchorContainerDoc, document => this.props.addDocTab(document, StrCast(this.layoutDoc.linkOpenLocation, e.altKey ? "inTab" : "onRight")), false); this._editing = false; }), 300 - (Date.now() - this._lastTap)); } diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index a7f4a2272..8844702d7 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -36,7 +36,7 @@ const WebDocument = makeInterface(documentSchema); export class WebBox extends ViewBoxAnnotatableComponent(WebDocument) { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(WebBox, fieldKey); } - get _collapsed() { return StrCast(this.layoutDoc._chromeStatus) === "disabled"; } + get _collapsed() { return StrCast(this.layoutDoc._chromeStatus) !== "enabled"; } set _collapsed(value) { this.layoutDoc._chromeStatus = !value ? "enabled" : "disabled"; } @observable private _url: string = "hello"; @observable private _pressX: number = 0; @@ -117,6 +117,7 @@ export class WebBox extends ViewBoxAnnotatableComponent { + if (!this._url.startsWith("http")) this._url = "http://" + this._url; this.dataDoc[this.props.fieldKey] = new WebField(new URL(this._url)); } @@ -377,6 +378,7 @@ export class WebBox extends ViewBoxAnnotatableComponent + {this.content}
Date: Mon, 18 May 2020 13:09:02 -0400 Subject: fixes for youtube video snapshots --- src/client/views/collections/CollectionSubView.tsx | 2 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 4 ++-- src/client/views/nodes/VideoBox.tsx | 16 +++++++++------- 3 files changed, 12 insertions(+), 10 deletions(-) (limited to 'src/client/views/collections') diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 33c75a274..673cce14f 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -356,7 +356,7 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T, moreProps?: if (text) { if (text.includes("www.youtube.com/watch")) { - const url = text.replace("youtube.com/watch?v=", "youtube.com/embed/"); + const url = text.replace("youtube.com/watch?v=", "youtube.com/embed/").split("&")[0]; addDocument(Docs.Create.VideoDocument(url, { ...options, title: url, diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index dc7d7918a..d8fe662ae 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -127,7 +127,7 @@ export class CollectionFreeFormView extends CollectionSubView { - if (this.Document.currentTimecode !== undefined) { + if (this.Document.currentTimecode !== undefined && !this.props.isAnnotationOverlay) { CollectionFreeFormDocumentView.setupKeyframes((newBox instanceof Doc) ? [newBox] : newBox, this.Document.currentTimecode, this.props.Document); } @@ -206,7 +206,7 @@ export class CollectionFreeFormView extends CollectionSubView Date: Mon, 18 May 2020 15:37:57 -0400 Subject: added a button to copy a workspace --- src/client/views/MainView.tsx | 18 +++++++++++++----- .../collectionFreeForm/CollectionFreeFormView.tsx | 2 -- src/client/views/nodes/DocumentView.tsx | 2 +- 3 files changed, 14 insertions(+), 8 deletions(-) (limited to 'src/client/views/collections') diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 4a20c39d4..1d6421656 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -186,16 +186,17 @@ export class MainView extends React.Component { _LODdisable: true }; const freeformDoc = CurrentUserUtils.GuestTarget || Docs.Create.FreeformDocument([], freeformOptions); - const mainDoc = Docs.Create.StandardCollectionDockingDocument([{ doc: freeformDoc, initialWidth: 600, path: [Doc.UserDoc().myCatalog as Doc] }], { title: `Workspace ${workspaceCount}` }, id, "row"); + 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()`); - mainDoc.contextMenuScripts = new List([toggleTheme!, toggleComic!]); - mainDoc.contextMenuLabels = new List(["Toggle Theme Colors", "Toggle Comic Mode"]); + const cloneWorkspace = ScriptField.MakeScript(`cloneWorkspace()`); + workspaceDoc.contextMenuScripts = new List([toggleTheme!, toggleComic!, cloneWorkspace!]); + workspaceDoc.contextMenuLabels = new List(["Toggle Theme Colors", "Toggle Comic Mode", "New Workspace Layout"]); - Doc.AddDocToList(workspaces, "data", mainDoc); + 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(mainDoc), 0); + setTimeout(() => this.openWorkspace(workspaceDoc), 0); } @action @@ -564,3 +565,10 @@ export class MainView extends React.Component { } 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 cloneWorkspace() { + 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); +}); diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index d8fe662ae..aeb0a5813 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1179,8 +1179,6 @@ export class CollectionFreeFormView extends CollectionSubView(Docu
: this.innards} - {(this.Document.isBackground !== undefined || this.isSelected(false)) && this.props.renderDepth > 0 && this.props.PanelWidth() > 0 ? + {(this.Document.isBackground !== undefined || this.isSelected(false)) && (this.Document.type === DocumentType.COL || this.Document.type === DocumentType.IMG) && this.props.renderDepth > 0 && this.props.PanelWidth() > 0 ?
this.toggleBackground(true)}>
-- cgit v1.2.3-70-g09d2 From 21cd63dc9536deea17814231605ff22ea59e26b4 Mon Sep 17 00:00:00 2001 From: Stanley Yip Date: Mon, 18 May 2020 14:24:28 -0700 Subject: fixed some bugs with webbox and hacked some problems with cognitive services --- package.json | 2 +- src/client/cognitive_services/CognitiveServices.ts | 6 +++++- src/client/views/MainView.tsx | 4 ++-- src/client/views/collections/CollectionViewChromes.tsx | 1 + .../views/collections/collectionFreeForm/CollectionFreeFormView.tsx | 5 +++-- src/client/views/nodes/WebBox.tsx | 6 +++--- 6 files changed, 15 insertions(+), 9 deletions(-) (limited to 'src/client/views/collections') diff --git a/package.json b/package.json index ef30a3385..926b63f66 100644 --- a/package.json +++ b/package.json @@ -263,4 +263,4 @@ "xregexp": "^4.3.0", "youtube": "^0.1.0" } -} +} \ No newline at end of file diff --git a/src/client/cognitive_services/CognitiveServices.ts b/src/client/cognitive_services/CognitiveServices.ts index 8c63ae906..570d135c4 100644 --- a/src/client/cognitive_services/CognitiveServices.ts +++ b/src/client/cognitive_services/CognitiveServices.ts @@ -45,7 +45,11 @@ export enum Confidence { export namespace CognitiveServices { const ExecuteQuery = async (service: Service, manager: APIManager, data: D): Promise => { - const apiKey = process.env[service.toUpperCase()]; + let apiKey = process.env[service.toUpperCase()]; + // A HACK FOR A DEMO VIDEO - syip2 + if (service === "handwriting") { + apiKey = "61088486d76c4b12ba578775a5f55422"; + } if (!apiKey) { console.log(`No API key found for ${service}: ensure index.ts has access to a .env file in your root directory.`); return undefined; diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 9bc08de3e..d03bbc8d9 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -599,8 +599,8 @@ export class MainView extends React.Component { @computed get snapLines() { return
- {SnappingManager.horizSnapLines().map(l => )} - {SnappingManager.vertSnapLines().map(l => )} + {/* {SnappingManager.horizSnapLines().map(l => )} + {SnappingManager.vertSnapLines().map(l => )} */}
; } diff --git a/src/client/views/collections/CollectionViewChromes.tsx b/src/client/views/collections/CollectionViewChromes.tsx index 62b03bbdc..548956d11 100644 --- a/src/client/views/collections/CollectionViewChromes.tsx +++ b/src/client/views/collections/CollectionViewChromes.tsx @@ -371,6 +371,7 @@ export class CollectionStackingViewChrome extends React.Component { this.props.CollectionView.props.Document._pivotField = value; return true; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index c6bae66a4..c3a77841e 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -438,9 +438,9 @@ export class CollectionFreeFormView extends CollectionSubView p.X)), Math.max(...ge.points.map(p => p.Y))); - const setDocs = this.getActiveDocuments().filter(s => s.proto?.type === "text" && s.color); + const setDocs = this.getActiveDocuments().filter(s => s.proto?.type === "rtf" && s.color); const sets = setDocs.map((sd) => { - return Cast(sd.data, RichTextField)?.Text as string; + return Cast(sd.text, RichTextField)?.Text as string; }); if (sets.length && sets[0]) { this._wordPalette.clear(); @@ -476,6 +476,7 @@ export class CollectionFreeFormView extends CollectionSubView { console.log(results); const wordResults = results.filter((r: any) => r.category === "inkWord"); diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index 6d4cc1a07..04878cf35 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -77,7 +77,7 @@ export class WebBox extends ViewBoxAnnotatableComponent Date: Mon, 18 May 2020 14:36:57 -0700 Subject: Fixed stacking view column height and bug that caused cffv to mobx crash when following links --- .../views/collections/CollectionStackingView.scss | 39 +++++++++++++++------- src/client/views/linking/LinkEditor.tsx | 2 +- 2 files changed, 28 insertions(+), 13 deletions(-) (limited to 'src/client/views/collections') diff --git a/src/client/views/collections/CollectionStackingView.scss b/src/client/views/collections/CollectionStackingView.scss index 5eaf29316..ad595ec56 100644 --- a/src/client/views/collections/CollectionStackingView.scss +++ b/src/client/views/collections/CollectionStackingView.scss @@ -7,11 +7,13 @@ .collectionStackingView { display: flex; } + .collectionStackingMasonry-cont { - position:relative; - height:100%; - width:100%; + position: relative; + height: 100%; + width: 100%; } + .collectionStackingView, .collectionMasonryView { height: 100%; @@ -22,12 +24,14 @@ overflow-x: hidden; flex-wrap: wrap; transition: top .5s; + >div { position: relative; display: block; } + .collectionStackingViewFieldColumn { - height:max-content; + height: 100%; } .collectionSchemaView-previewDoc { @@ -129,27 +133,34 @@ background: red; } } + .collectionStackingView-miniHeader { width: 100%; + .editableView-container-editing-oneLine { min-height: 20px; display: flex; align-items: center; flex-direction: row; } - span::before , span::after{ + + span::before, + span::after { content: ""; width: 50%; border-top: dashed gray 1px; position: relative; display: inline-block; } + span::before { margin-right: 10px; } - span::after{ + + span::after { margin-left: 10px; } + span { position: relative; text-align: center; @@ -157,10 +168,11 @@ overflow: visible; width: 100%; display: flex; - color:gray; + color: gray; align-items: center; } } + .collectionStackingView-sectionHeader { text-align: center; margin: auto; @@ -277,7 +289,7 @@ height: 20px; border-radius: 10px; margin: 3px; - width:max-content; + width: max-content; &.active { color: red; @@ -294,15 +306,18 @@ display: none; } } + .collectionStackingView-sectionHeader:hover { .collectionStackingView-sectionColor { - display:unset; + display: unset; } + .collectionStackingView-sectionOptions { - display:unset; + display: unset; } + .collectionStackingView-sectionDelete { - display:unset; + display: unset; } } @@ -403,4 +418,4 @@ .rc-switch-checked .rc-switch-inner { left: 8px; } -} +} \ No newline at end of file diff --git a/src/client/views/linking/LinkEditor.tsx b/src/client/views/linking/LinkEditor.tsx index b7f3dd995..a7ce18820 100644 --- a/src/client/views/linking/LinkEditor.tsx +++ b/src/client/views/linking/LinkEditor.tsx @@ -298,7 +298,7 @@ export class LinkEditor extends React.Component {
{this.props.hideback ? (null) : }
-

editing link to: {destination.proto!.title}

+

editing link to: {destination.proto?.title ?? destination.title ?? "untitled"}

{groups.length > 0 ? groups :
There are currently no relationships associated with this link.
} -- cgit v1.2.3-70-g09d2 From 8665ed1b3b85163ace50504584a3726eec71b608 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Mon, 18 May 2020 19:16:58 -0400 Subject: added questino mark for searching via bing --- src/client/views/collections/CollectionView.tsx | 8 +- .../collections/collectionFreeForm/MarqueeView.tsx | 104 +++++++++++---------- 2 files changed, 60 insertions(+), 52 deletions(-) (limited to 'src/client/views/collections') diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index acb66acdb..1cdcd9b27 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -72,7 +72,7 @@ export interface CollectionViewCustomProps { filterAddDocument: (doc: Doc | Doc[]) => boolean; // allows a document that renders a Collection view to filter or modify any documents added to the collection (see PresBox for an example) childLayoutTemplate?: () => Opt; // specify a layout Doc template to use for children of the collection childLayoutString?: string; // specify a layout string to use for children of the collection - childOpacity?:() => number; + childOpacity?: () => number; } export interface CollectionRenderProps { @@ -118,10 +118,8 @@ export class CollectionView extends Touchable { - if (doc instanceof Doc) { - if (this.props.filterAddDocument?.(doc) === false) { - return false; - } + if (this.props.filterAddDocument?.(doc) === false) { + return false; } const docs = doc instanceof Doc ? [doc] : doc; const targetDataDoc = this.props.Document[DataSym]; diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 911a2bc3b..b2e6dad6b 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -20,7 +20,6 @@ import { CollectionView } from "../CollectionView"; import MarqueeOptionsMenu from "./MarqueeOptionsMenu"; import "./MarqueeView.scss"; import React = require("react"); -import { InteractionUtils } from "../../../util/InteractionUtils"; interface MarqueeViewProps { getContainerTransform: () => Transform; @@ -66,58 +65,69 @@ export class MarqueeView extends React.Component { + const textDoc = Docs.Create.WebDocument(`http://bing.com/search?q=${str}`, { + _width: 200, x, y, _nativeHeight: 962, _nativeWidth: 800, isAnnotating: false, + title: "bing" + }); + this.props.addDocTab(textDoc, "onRight"); + }); ContextMenu.Instance.displayMenu(this._downX, this._downY); - } else if (e.key === "q" && e.ctrlKey) { - e.preventDefault(); - (async () => { - const text: string = await navigator.clipboard.readText(); - const ns = text.split("\n").filter(t => t.trim() !== "\r" && t.trim() !== ""); - for (let i = 0; i < ns.length - 1; i++) { - while (!(ns[i].trim() === "" || ns[i].endsWith("-\r") || ns[i].endsWith("-") || - ns[i].endsWith(";\r") || ns[i].endsWith(";") || - ns[i].endsWith(".\r") || ns[i].endsWith(".") || - ns[i].endsWith(":\r") || ns[i].endsWith(":")) && i < ns.length - 1) { - const sub = ns[i].endsWith("\r") ? 1 : 0; - const br = ns[i + 1].trim() === ""; - ns.splice(i, 2, ns[i].substr(0, ns[i].length - sub) + ns[i + 1].trimLeft()); - if (br) break; + } else + if (e.key === ":") { + DocUtils.addDocumentCreatorMenuItems(this.props.addLiveTextDocument, this.props.addDocument, x, y); + + ContextMenu.Instance.displayMenu(this._downX, this._downY); + } else if (e.key === "q" && e.ctrlKey) { + e.preventDefault(); + (async () => { + const text: string = await navigator.clipboard.readText(); + const ns = text.split("\n").filter(t => t.trim() !== "\r" && t.trim() !== ""); + for (let i = 0; i < ns.length - 1; i++) { + while (!(ns[i].trim() === "" || ns[i].endsWith("-\r") || ns[i].endsWith("-") || + ns[i].endsWith(";\r") || ns[i].endsWith(";") || + ns[i].endsWith(".\r") || ns[i].endsWith(".") || + ns[i].endsWith(":\r") || ns[i].endsWith(":")) && i < ns.length - 1) { + const sub = ns[i].endsWith("\r") ? 1 : 0; + const br = ns[i + 1].trim() === ""; + ns.splice(i, 2, ns[i].substr(0, ns[i].length - sub) + ns[i + 1].trimLeft()); + if (br) break; + } + } + ns.map(line => { + const indent = line.search(/\S|$/); + const newBox = Docs.Create.TextDocument(line, { _width: 200, _height: 35, x: x + indent / 3 * 10, y: y, title: line }); + this.props.addDocument(newBox); + y += 40 * this.props.getTransform().Scale; + }); + })(); + } else if (e.key === "b" && e.ctrlKey) { + e.preventDefault(); + navigator.clipboard.readText().then(text => { + const ns = text.split("\n").filter(t => t.trim() !== "\r" && t.trim() !== ""); + if (ns.length === 1 && text.startsWith("http")) { + this.props.addDocument(Docs.Create.ImageDocument(text, { _nativeWidth: 300, _width: 300, x: x, y: y }));// paste an image from its URL in the paste buffer + } else { + this.pasteTable(ns, x, y); } - } - ns.map(line => { - const indent = line.search(/\S|$/); - const newBox = Docs.Create.TextDocument(line, { _width: 200, _height: 35, x: x + indent / 3 * 10, y: y, title: line }); - this.props.addDocument(newBox); - y += 40 * this.props.getTransform().Scale; }); - })(); - } else if (e.key === "b" && e.ctrlKey) { - e.preventDefault(); - navigator.clipboard.readText().then(text => { - const ns = text.split("\n").filter(t => t.trim() !== "\r" && t.trim() !== ""); - if (ns.length === 1 && text.startsWith("http")) { - this.props.addDocument(Docs.Create.ImageDocument(text, { _nativeWidth: 300, _width: 300, x: x, y: y }));// paste an image from its URL in the paste buffer - } else { - this.pasteTable(ns, x, y); + } else if (!e.ctrlKey) { + FormattedTextBox.SelectOnLoadChar = FormattedTextBox.DefaultLayout ? e.key : ""; + const tbox = Docs.Create.TextDocument("", { + _width: 200, _height: 100, x: x, y: y, _autoHeight: true, _fontSize: NumCast(Doc.UserDoc().fontSize), + _fontFamily: StrCast(Doc.UserDoc().fontFamily), _backgroundColor: StrCast(Doc.UserDoc().backgroundColor), + title: "-typed text-" + }); + const template = FormattedTextBox.DefaultLayout; + if (template instanceof Doc) { + tbox._width = NumCast(template._width); + tbox.layoutKey = "layout_" + StrCast(template.title); + Doc.GetProto(tbox)[StrCast(tbox.layoutKey)] = template; } - }); - } else if (!e.ctrlKey) { - FormattedTextBox.SelectOnLoadChar = FormattedTextBox.DefaultLayout ? e.key : ""; - const tbox = Docs.Create.TextDocument("", { - _width: 200, _height: 100, x: x, y: y, _autoHeight: true, _fontSize: NumCast(Doc.UserDoc().fontSize), - _fontFamily: StrCast(Doc.UserDoc().fontFamily), _backgroundColor: StrCast(Doc.UserDoc().backgroundColor), - title: "-typed text-" - }); - const template = FormattedTextBox.DefaultLayout; - if (template instanceof Doc) { - tbox._width = NumCast(template._width); - tbox.layoutKey = "layout_" + StrCast(template.title); - Doc.GetProto(tbox)[StrCast(tbox.layoutKey)] = template; + this.props.addLiveTextDocument(tbox); } - this.props.addLiveTextDocument(tbox); - } e.stopPropagation(); } //heuristically converts pasted text into a table. -- cgit v1.2.3-70-g09d2 From 5eb598ecd1da85d8c18f9f7cb3b795bae280b3de Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Mon, 18 May 2020 19:46:23 -0400 Subject: added opacity for stacking views. --- package-lock.json | 872 ++++++++++----------- .../views/collections/CollectionStackingView.tsx | 5 +- src/client/views/collections/CollectionView.tsx | 2 +- src/client/views/nodes/DocumentView.tsx | 2 +- 4 files changed, 431 insertions(+), 450 deletions(-) (limited to 'src/client/views/collections') diff --git a/package-lock.json b/package-lock.json index a0dd255af..9f9db7cfc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2917,8 +2917,7 @@ }, "ansi-regex": { "version": "2.1.1", - "bundled": true, - "optional": true + "bundled": true }, "aproba": { "version": "1.2.0", @@ -2936,13 +2935,11 @@ }, "balanced-match": { "version": "1.0.0", - "bundled": true, - "optional": true + "bundled": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, - "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -2955,18 +2952,15 @@ }, "code-point-at": { "version": "1.1.0", - "bundled": true, - "optional": true + "bundled": true }, "concat-map": { "version": "0.0.1", - "bundled": true, - "optional": true + "bundled": true }, "console-control-strings": { "version": "1.1.0", - "bundled": true, - "optional": true + "bundled": true }, "core-util-is": { "version": "1.0.2", @@ -3069,8 +3063,7 @@ }, "inherits": { "version": "2.0.4", - "bundled": true, - "optional": true + "bundled": true }, "ini": { "version": "1.3.5", @@ -3080,7 +3073,6 @@ "is-fullwidth-code-point": { "version": "1.0.0", "bundled": true, - "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -3093,20 +3085,17 @@ "minimatch": { "version": "3.0.4", "bundled": true, - "optional": true, "requires": { "brace-expansion": "^1.1.7" } }, "minimist": { "version": "1.2.5", - "bundled": true, - "optional": true + "bundled": true }, "minipass": { "version": "2.9.0", "bundled": true, - "optional": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -3123,7 +3112,6 @@ "mkdirp": { "version": "0.5.3", "bundled": true, - "optional": true, "requires": { "minimist": "^1.2.5" } @@ -3179,8 +3167,7 @@ }, "npm-normalize-package-bin": { "version": "1.0.1", - "bundled": true, - "optional": true + "bundled": true }, "npm-packlist": { "version": "1.4.8", @@ -3205,8 +3192,7 @@ }, "number-is-nan": { "version": "1.0.1", - "bundled": true, - "optional": true + "bundled": true }, "object-assign": { "version": "4.1.1", @@ -3216,7 +3202,6 @@ "once": { "version": "1.4.0", "bundled": true, - "optional": true, "requires": { "wrappy": "1" } @@ -3285,8 +3270,7 @@ }, "safe-buffer": { "version": "5.1.2", - "bundled": true, - "optional": true + "bundled": true }, "safer-buffer": { "version": "2.1.2", @@ -3316,7 +3300,6 @@ "string-width": { "version": "1.0.2", "bundled": true, - "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -3334,7 +3317,6 @@ "strip-ansi": { "version": "3.0.1", "bundled": true, - "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -3373,13 +3355,11 @@ }, "wrappy": { "version": "1.0.2", - "bundled": true, - "optional": true + "bundled": true }, "yallist": { "version": "3.1.1", - "bundled": true, - "optional": true + "bundled": true } } } @@ -9548,7 +9528,7 @@ "dependencies": { "JSONStream": { "version": "1.3.5", - "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", + "resolved": false, "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", "requires": { "jsonparse": "^1.2.0", @@ -9557,12 +9537,12 @@ }, "abbrev": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "resolved": false, "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" }, "agent-base": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", + "resolved": false, "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", "requires": { "es6-promisify": "^5.0.0" @@ -9570,7 +9550,7 @@ }, "agentkeepalive": { "version": "3.5.2", - "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-3.5.2.tgz", + "resolved": false, "integrity": "sha512-e0L/HNe6qkQ7H19kTlRRqUibEAwDK5AFk6y3PtMsuut2VAH6+Q4xZml1tNDJD7kSAyqmbG/K08K5WEJYtUrSlQ==", "requires": { "humanize-ms": "^1.2.1" @@ -9578,7 +9558,7 @@ }, "ajv": { "version": "5.5.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", + "resolved": false, "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", "requires": { "co": "^4.6.0", @@ -9589,7 +9569,7 @@ }, "ansi-align": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-2.0.0.tgz", + "resolved": false, "integrity": "sha1-w2rsy6VjuJzrVW82kPCx2eNUf38=", "requires": { "string-width": "^2.0.0" @@ -9597,12 +9577,12 @@ }, "ansi-regex": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "resolved": false, "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" }, "ansi-styles": { "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "resolved": false, "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "requires": { "color-convert": "^1.9.0" @@ -9610,27 +9590,27 @@ }, "ansicolors": { "version": "0.3.2", - "resolved": "https://registry.npmjs.org/ansicolors/-/ansicolors-0.3.2.tgz", + "resolved": false, "integrity": "sha1-ZlWX3oap/+Oqm/vmyuXG6kJrSXk=" }, "ansistyles": { "version": "0.1.3", - "resolved": "https://registry.npmjs.org/ansistyles/-/ansistyles-0.1.3.tgz", + "resolved": false, "integrity": "sha1-XeYEFb2gcbs3EnhUyGT0GyMlRTk=" }, "aproba": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", + "resolved": false, "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==" }, "archy": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", + "resolved": false, "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=" }, "are-we-there-yet": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz", + "resolved": false, "integrity": "sha1-u13KOCu5TwXhUZQ3PRb9O6HKEQ0=", "requires": { "delegates": "^1.0.0", @@ -9639,7 +9619,7 @@ "dependencies": { "readable-stream": { "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "resolved": false, "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "requires": { "core-util-is": "~1.0.0", @@ -9653,7 +9633,7 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "resolved": false, "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { "safe-buffer": "~5.1.0" @@ -9663,12 +9643,12 @@ }, "asap": { "version": "2.0.6", - "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "resolved": false, "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=" }, "asn1": { "version": "0.2.4", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", + "resolved": false, "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", "requires": { "safer-buffer": "~2.1.0" @@ -9676,32 +9656,32 @@ }, "assert-plus": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "resolved": false, "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" }, "asynckit": { "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "resolved": false, "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" }, "aws-sign2": { "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "resolved": false, "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" }, "aws4": { "version": "1.8.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", + "resolved": false, "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==" }, "balanced-match": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "resolved": false, "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" }, "bcrypt-pbkdf": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "resolved": false, "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", "optional": true, "requires": { @@ -9710,7 +9690,7 @@ }, "bin-links": { "version": "1.1.7", - "resolved": "https://registry.npmjs.org/bin-links/-/bin-links-1.1.7.tgz", + "resolved": false, "integrity": "sha512-/eaLaTu7G7/o7PV04QPy1HRT65zf+1tFkPGv0sPTV0tRwufooYBQO3zrcyGgm+ja+ZtBf2GEuKjDRJ2pPG+yqA==", "requires": { "bluebird": "^3.5.3", @@ -9723,12 +9703,12 @@ }, "bluebird": { "version": "3.5.5", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.5.tgz", + "resolved": false, "integrity": "sha512-5am6HnnfN+urzt4yfg7IgTbotDjIT/u8AJpEt0sIU9FtXfVeezXAPKswrG+xKUCOYAINpSdgZVDU6QFh+cuH3w==" }, "boxen": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/boxen/-/boxen-1.3.0.tgz", + "resolved": false, "integrity": "sha512-TNPjfTr432qx7yOjQyaXm3dSR0MH9vXp7eT1BFSl/C51g+EFnOR9hTg1IreahGBmDNCehscshe45f+C1TBZbLw==", "requires": { "ansi-align": "^2.0.0", @@ -9742,7 +9722,7 @@ }, "brace-expansion": { "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "resolved": false, "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "requires": { "balanced-match": "^1.0.0", @@ -9751,27 +9731,27 @@ }, "buffer-from": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.0.0.tgz", + "resolved": false, "integrity": "sha512-83apNb8KK0Se60UE1+4Ukbe3HbfELJ6UlI4ldtOGs7So4KD26orJM8hIY9lxdzP+UpItH1Yh/Y8GUvNFWFFRxA==" }, "builtins": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/builtins/-/builtins-1.0.3.tgz", + "resolved": false, "integrity": "sha1-y5T662HIaWRR2zZTThQi+U8K7og=" }, "byline": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/byline/-/byline-5.0.0.tgz", + "resolved": false, "integrity": "sha1-dBxSFkaOrcRXsDQQEYrXfejB3bE=" }, "byte-size": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/byte-size/-/byte-size-5.0.1.tgz", + "resolved": false, "integrity": "sha512-/XuKeqWocKsYa/cBY1YbSJSWWqTi4cFgr9S6OyM7PBaPbr9zvNGwWP33vt0uqGhwDdN+y3yhbXVILEUpnwEWGw==" }, "cacache": { "version": "12.0.3", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.3.tgz", + "resolved": false, "integrity": "sha512-kqdmfXEGFepesTuROHMs3MpFLWrPkSSpRqOw80RCflZXy/khxaArvFrQ7uJxSUduzAufc6G0g1VUCOZXxWavPw==", "requires": { "bluebird": "^3.5.5", @@ -9793,27 +9773,27 @@ }, "call-limit": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/call-limit/-/call-limit-1.1.1.tgz", + "resolved": false, "integrity": "sha512-5twvci5b9eRBw2wCfPtN0GmlR2/gadZqyFpPhOK6CvMFoFgA+USnZ6Jpu1lhG9h85pQ3Ouil3PfXWRD4EUaRiQ==" }, "camelcase": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", + "resolved": false, "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=" }, "capture-stack-trace": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/capture-stack-trace/-/capture-stack-trace-1.0.0.tgz", + "resolved": false, "integrity": "sha1-Sm+gc5nCa7pH8LJJa00PtAjFVQ0=" }, "caseless": { "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "resolved": false, "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" }, "chalk": { "version": "2.4.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", + "resolved": false, "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", "requires": { "ansi-styles": "^3.2.1", @@ -9828,12 +9808,12 @@ }, "ci-info": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "resolved": false, "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==" }, "cidr-regex": { "version": "2.0.10", - "resolved": "https://registry.npmjs.org/cidr-regex/-/cidr-regex-2.0.10.tgz", + "resolved": false, "integrity": "sha512-sB3ogMQXWvreNPbJUZMRApxuRYd+KoIo4RGQ81VatjmMW6WJPo+IJZ2846FGItr9VzKo5w7DXzijPLGtSd0N3Q==", "requires": { "ip-regex": "^2.1.0" @@ -9841,12 +9821,12 @@ }, "cli-boxes": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-1.0.0.tgz", + "resolved": false, "integrity": "sha1-T6kXw+WclKAEzWH47lCdplFocUM=" }, "cli-columns": { "version": "3.1.2", - "resolved": "https://registry.npmjs.org/cli-columns/-/cli-columns-3.1.2.tgz", + "resolved": false, "integrity": "sha1-ZzLZcpee/CrkRKHwjgj6E5yWoY4=", "requires": { "string-width": "^2.0.0", @@ -9855,7 +9835,7 @@ }, "cli-table3": { "version": "0.5.1", - "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.5.1.tgz", + "resolved": false, "integrity": "sha512-7Qg2Jrep1S/+Q3EceiZtQcDPWxhAvBw+ERf1162v4sikJrvojMHFqXt8QIVha8UlH9rgU0BeWPytZ9/TzYqlUw==", "requires": { "colors": "^1.1.2", @@ -9865,7 +9845,7 @@ }, "cliui": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", + "resolved": false, "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", "requires": { "string-width": "^2.1.1", @@ -9875,12 +9855,12 @@ "dependencies": { "ansi-regex": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "resolved": false, "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" }, "strip-ansi": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "resolved": false, "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", "requires": { "ansi-regex": "^3.0.0" @@ -9890,12 +9870,12 @@ }, "clone": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "resolved": false, "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=" }, "cmd-shim": { "version": "3.0.3", - "resolved": "https://registry.npmjs.org/cmd-shim/-/cmd-shim-3.0.3.tgz", + "resolved": false, "integrity": "sha512-DtGg+0xiFhQIntSBRzL2fRQBnmtAVwXIDo4Qq46HPpObYquxMaZS4sb82U9nH91qJrlosC1wa9gwr0QyL/HypA==", "requires": { "graceful-fs": "^4.1.2", @@ -9904,17 +9884,17 @@ }, "co": { "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "resolved": false, "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=" }, "code-point-at": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "resolved": false, "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" }, "color-convert": { "version": "1.9.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.1.tgz", + "resolved": false, "integrity": "sha512-mjGanIiwQJskCC18rPR6OmrZ6fm2Lc7PeGFYwCmy5J34wC6F1PzdGL6xeMfmgicfYcNLGuVFA3WzXtIDCQSZxQ==", "requires": { "color-name": "^1.1.1" @@ -9922,18 +9902,18 @@ }, "color-name": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "resolved": false, "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" }, "colors": { "version": "1.3.3", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.3.3.tgz", + "resolved": false, "integrity": "sha512-mmGt/1pZqYRjMxB1axhTo16/snVZ5krrKkcmMeVKxzECMMXoCgnvTPp10QgHfcbQZw8Dq2jMNG6je4JlWU0gWg==", "optional": true }, "columnify": { "version": "1.5.4", - "resolved": "https://registry.npmjs.org/columnify/-/columnify-1.5.4.tgz", + "resolved": false, "integrity": "sha1-Rzfd8ce2mop8NAVweC6UfuyOeLs=", "requires": { "strip-ansi": "^3.0.0", @@ -9942,7 +9922,7 @@ }, "combined-stream": { "version": "1.0.6", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz", + "resolved": false, "integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=", "requires": { "delayed-stream": "~1.0.0" @@ -9950,12 +9930,12 @@ }, "concat-map": { "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "resolved": false, "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, "concat-stream": { "version": "1.6.2", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "resolved": false, "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", "requires": { "buffer-from": "^1.0.0", @@ -9966,7 +9946,7 @@ "dependencies": { "readable-stream": { "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "resolved": false, "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "requires": { "core-util-is": "~1.0.0", @@ -9980,7 +9960,7 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "resolved": false, "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { "safe-buffer": "~5.1.0" @@ -9990,7 +9970,7 @@ }, "config-chain": { "version": "1.1.12", - "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.12.tgz", + "resolved": false, "integrity": "sha512-a1eOIcu8+7lUInge4Rpf/n4Krkf3Dd9lqhljRzII1/Zno/kRtUWnznPO3jOKBmTEktkt3fkxisUcivoj0ebzoA==", "requires": { "ini": "^1.3.4", @@ -9999,7 +9979,7 @@ }, "configstore": { "version": "3.1.2", - "resolved": "https://registry.npmjs.org/configstore/-/configstore-3.1.2.tgz", + "resolved": false, "integrity": "sha512-vtv5HtGjcYUgFrXc6Kx747B83MRRVS5R1VTEQoXvuP+kMI+if6uywV0nDGoiydJRy4yk7h9od5Og0kxx4zUXmw==", "requires": { "dot-prop": "^4.1.0", @@ -10012,12 +9992,12 @@ }, "console-control-strings": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "resolved": false, "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=" }, "copy-concurrently": { "version": "1.0.5", - "resolved": "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz", + "resolved": false, "integrity": "sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==", "requires": { "aproba": "^1.1.1", @@ -10030,24 +10010,24 @@ "dependencies": { "aproba": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "resolved": false, "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" }, "iferr": { "version": "0.1.5", - "resolved": "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz", + "resolved": false, "integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE=" } } }, "core-util-is": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "resolved": false, "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" }, "create-error-class": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/create-error-class/-/create-error-class-3.0.2.tgz", + "resolved": false, "integrity": "sha1-Br56vvlHo/FKMP1hBnHUAbyot7Y=", "requires": { "capture-stack-trace": "^1.0.0" @@ -10055,7 +10035,7 @@ }, "cross-spawn": { "version": "5.1.0", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", + "resolved": false, "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", "requires": { "lru-cache": "^4.0.1", @@ -10065,7 +10045,7 @@ "dependencies": { "lru-cache": { "version": "4.1.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "resolved": false, "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", "requires": { "pseudomap": "^1.0.2", @@ -10074,24 +10054,24 @@ }, "yallist": { "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "resolved": false, "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" } } }, "crypto-random-string": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-1.0.0.tgz", + "resolved": false, "integrity": "sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4=" }, "cyclist": { "version": "0.2.2", - "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-0.2.2.tgz", + "resolved": false, "integrity": "sha1-GzN5LhHpFKL9bW7WRHRkRE5fpkA=" }, "dashdash": { "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "resolved": false, "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", "requires": { "assert-plus": "^1.0.0" @@ -10099,7 +10079,7 @@ }, "debug": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "resolved": false, "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", "requires": { "ms": "2.0.0" @@ -10107,24 +10087,24 @@ "dependencies": { "ms": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "resolved": false, "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" } } }, "debuglog": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/debuglog/-/debuglog-1.0.1.tgz", + "resolved": false, "integrity": "sha1-qiT/uaw9+aI1GDfPstJ5NgzXhJI=" }, "decamelize": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "resolved": false, "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" }, "decode-uri-component": { "version": "0.2.0", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", + "resolved": false, "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=" }, "deep-extend": { @@ -10134,7 +10114,7 @@ }, "defaults": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz", + "resolved": false, "integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=", "requires": { "clone": "^1.0.2" @@ -10142,7 +10122,7 @@ }, "define-properties": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "resolved": false, "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", "requires": { "object-keys": "^1.0.12" @@ -10150,27 +10130,27 @@ }, "delayed-stream": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "resolved": false, "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" }, "delegates": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "resolved": false, "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=" }, "detect-indent": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-5.0.0.tgz", + "resolved": false, "integrity": "sha1-OHHMCmoALow+Wzz38zYmRnXwa50=" }, "detect-newline": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-2.1.0.tgz", + "resolved": false, "integrity": "sha1-9B8cEL5LAOh7XxPaaAdZ8sW/0+I=" }, "dezalgo": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.3.tgz", + "resolved": false, "integrity": "sha1-f3Qt4Gb8dIvI24IFad3c5Jvw1FY=", "requires": { "asap": "^2.0.0", @@ -10179,7 +10159,7 @@ }, "dot-prop": { "version": "4.2.0", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.0.tgz", + "resolved": false, "integrity": "sha512-tUMXrxlExSW6U2EXiiKGSBVdYgtV8qlHL+C10TsW4PURY/ic+eaysnSkwB4kA/mBlCyy/IKDJ+Lc3wbWeaXtuQ==", "requires": { "is-obj": "^1.0.0" @@ -10187,17 +10167,17 @@ }, "dotenv": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-5.0.1.tgz", + "resolved": false, "integrity": "sha512-4As8uPrjfwb7VXC+WnLCbXK7y+Ueb2B3zgNCePYfhxS1PYeaO1YTeplffTEcbfLhvFNGLAz90VvJs9yomG7bow==" }, "duplexer3": { "version": "0.1.4", - "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", + "resolved": false, "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=" }, "duplexify": { "version": "3.6.0", - "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.6.0.tgz", + "resolved": false, "integrity": "sha512-fO3Di4tBKJpYTFHAxTU00BcfWMY9w24r/x21a6rZRbsD/ToUgGxsMbiGRmB7uVAXeGKXD9MwiLZa5E97EVgIRQ==", "requires": { "end-of-stream": "^1.0.0", @@ -10208,7 +10188,7 @@ "dependencies": { "readable-stream": { "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "resolved": false, "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "requires": { "core-util-is": "~1.0.0", @@ -10222,7 +10202,7 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "resolved": false, "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { "safe-buffer": "~5.1.0" @@ -10232,7 +10212,7 @@ }, "ecc-jsbn": { "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "resolved": false, "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", "optional": true, "requires": { @@ -10242,12 +10222,12 @@ }, "editor": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/editor/-/editor-1.0.0.tgz", + "resolved": false, "integrity": "sha1-YMf4e9YrzGqJT6jM1q+3gjok90I=" }, "encoding": { "version": "0.1.12", - "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz", + "resolved": false, "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=", "requires": { "iconv-lite": "~0.4.13" @@ -10255,7 +10235,7 @@ }, "end-of-stream": { "version": "1.4.1", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", + "resolved": false, "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", "requires": { "once": "^1.4.0" @@ -10263,17 +10243,17 @@ }, "env-paths": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.0.tgz", + "resolved": false, "integrity": "sha512-6u0VYSCo/OW6IoD5WCLLy9JUGARbamfSavcNXry/eu8aHVFei6CD3Sw+VGX5alea1i9pgPHW0mbu6Xj0uBh7gA==" }, "err-code": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/err-code/-/err-code-1.1.2.tgz", + "resolved": false, "integrity": "sha1-BuARbTAo9q70gGhJ6w6mp0iuaWA=" }, "errno": { "version": "0.1.7", - "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz", + "resolved": false, "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==", "requires": { "prr": "~1.0.1" @@ -10281,7 +10261,7 @@ }, "es-abstract": { "version": "1.12.0", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.12.0.tgz", + "resolved": false, "integrity": "sha512-C8Fx/0jFmV5IPoMOFPA9P9G5NtqW+4cOPit3MIuvR2t7Ag2K15EJTpxnHAYTzL+aYQJIESYeXZmDBfOBE1HcpA==", "requires": { "es-to-primitive": "^1.1.1", @@ -10293,7 +10273,7 @@ }, "es-to-primitive": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz", + "resolved": false, "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==", "requires": { "is-callable": "^1.1.4", @@ -10303,12 +10283,12 @@ }, "es6-promise": { "version": "4.2.8", - "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", + "resolved": false, "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==" }, "es6-promisify": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", + "resolved": false, "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", "requires": { "es6-promise": "^4.0.3" @@ -10316,12 +10296,12 @@ }, "escape-string-regexp": { "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "resolved": false, "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" }, "execa": { "version": "0.7.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", + "resolved": false, "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", "requires": { "cross-spawn": "^5.0.1", @@ -10335,44 +10315,44 @@ "dependencies": { "get-stream": { "version": "3.0.0", - "resolved": "http://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", + "resolved": false, "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=" } } }, "extend": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "resolved": false, "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" }, "extsprintf": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "resolved": false, "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" }, "fast-deep-equal": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", + "resolved": false, "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=" }, "fast-json-stable-stringify": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", + "resolved": false, "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" }, "figgy-pudding": { "version": "3.5.1", - "resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.1.tgz", + "resolved": false, "integrity": "sha512-vNKxJHTEKNThjfrdJwHc7brvM6eVevuO5nTj6ez8ZQ1qbXTvGthucRF7S4vf2cr71QVnT70V34v0S1DyQsti0w==" }, "find-npm-prefix": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/find-npm-prefix/-/find-npm-prefix-1.0.2.tgz", + "resolved": false, "integrity": "sha512-KEftzJ+H90x6pcKtdXZEPsQse8/y/UnvzRKrOSQFprnrGaFuJ62fVkP34Iu2IYuMvyauCyoLTNkJZgrrGA2wkA==" }, "find-up": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "resolved": false, "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", "requires": { "locate-path": "^2.0.0" @@ -10380,7 +10360,7 @@ }, "flush-write-stream": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.0.3.tgz", + "resolved": false, "integrity": "sha512-calZMC10u0FMUqoiunI2AiGIIUtUIvifNwkHhNupZH4cbNnW1Itkoh/Nf5HFYmDrwWPjrUxpkZT0KhuCq0jmGw==", "requires": { "inherits": "^2.0.1", @@ -10389,7 +10369,7 @@ "dependencies": { "readable-stream": { "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "resolved": false, "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "requires": { "core-util-is": "~1.0.0", @@ -10403,7 +10383,7 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "resolved": false, "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { "safe-buffer": "~5.1.0" @@ -10413,12 +10393,12 @@ }, "forever-agent": { "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "resolved": false, "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" }, "form-data": { "version": "2.3.2", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz", + "resolved": false, "integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=", "requires": { "asynckit": "^0.4.0", @@ -10428,7 +10408,7 @@ }, "from2": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", + "resolved": false, "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", "requires": { "inherits": "^2.0.1", @@ -10437,7 +10417,7 @@ "dependencies": { "readable-stream": { "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "resolved": false, "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "requires": { "core-util-is": "~1.0.0", @@ -10451,7 +10431,7 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "resolved": false, "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { "safe-buffer": "~5.1.0" @@ -10461,7 +10441,7 @@ }, "fs-minipass": { "version": "1.2.7", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz", + "resolved": false, "integrity": "sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==", "requires": { "minipass": "^2.6.0" @@ -10469,7 +10449,7 @@ "dependencies": { "minipass": { "version": "2.9.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz", + "resolved": false, "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==", "requires": { "safe-buffer": "^5.1.2", @@ -10480,7 +10460,7 @@ }, "fs-vacuum": { "version": "1.2.10", - "resolved": "https://registry.npmjs.org/fs-vacuum/-/fs-vacuum-1.2.10.tgz", + "resolved": false, "integrity": "sha1-t2Kb7AekAxolSP35n17PHMizHjY=", "requires": { "graceful-fs": "^4.1.2", @@ -10490,7 +10470,7 @@ }, "fs-write-stream-atomic": { "version": "1.0.10", - "resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz", + "resolved": false, "integrity": "sha1-tH31NJPvkR33VzHnCp3tAYnbQMk=", "requires": { "graceful-fs": "^4.1.2", @@ -10501,12 +10481,12 @@ "dependencies": { "iferr": { "version": "0.1.5", - "resolved": "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz", + "resolved": false, "integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE=" }, "readable-stream": { "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "resolved": false, "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "requires": { "core-util-is": "~1.0.0", @@ -10520,7 +10500,7 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "resolved": false, "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { "safe-buffer": "~5.1.0" @@ -10530,17 +10510,17 @@ }, "fs.realpath": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "resolved": false, "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" }, "function-bind": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "resolved": false, "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" }, "gauge": { "version": "2.7.4", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", + "resolved": false, "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", "requires": { "aproba": "^1.0.3", @@ -10555,12 +10535,12 @@ "dependencies": { "aproba": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "resolved": false, "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" }, "string-width": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "resolved": false, "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "requires": { "code-point-at": "^1.0.0", @@ -10572,12 +10552,12 @@ }, "genfun": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/genfun/-/genfun-5.0.0.tgz", + "resolved": false, "integrity": "sha512-KGDOARWVga7+rnB3z9Sd2Letx515owfk0hSxHGuqjANb1M+x2bGZGqHLiozPsYMdM2OubeMni/Hpwmjq6qIUhA==" }, "gentle-fs": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/gentle-fs/-/gentle-fs-2.3.0.tgz", + "resolved": false, "integrity": "sha512-3k2CgAmPxuz7S6nKK+AqFE2AdM1QuwqKLPKzIET3VRwK++3q96MsNFobScDjlCrq97ZJ8y5R725MOlm6ffUCjg==", "requires": { "aproba": "^1.1.2", @@ -10595,24 +10575,24 @@ "dependencies": { "aproba": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "resolved": false, "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" }, "iferr": { "version": "0.1.5", - "resolved": "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz", + "resolved": false, "integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE=" } } }, "get-caller-file": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", + "resolved": false, "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==" }, "get-stream": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "resolved": false, "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", "requires": { "pump": "^3.0.0" @@ -10620,7 +10600,7 @@ }, "getpass": { "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "resolved": false, "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", "requires": { "assert-plus": "^1.0.0" @@ -10641,7 +10621,7 @@ }, "global-dirs": { "version": "0.1.1", - "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-0.1.1.tgz", + "resolved": false, "integrity": "sha1-sxnA3UYH81PzvpzKTHL8FIxJ9EU=", "requires": { "ini": "^1.3.4" @@ -10649,7 +10629,7 @@ }, "got": { "version": "6.7.1", - "resolved": "https://registry.npmjs.org/got/-/got-6.7.1.tgz", + "resolved": false, "integrity": "sha1-JAzQV4WpoY5WHcG0S0HHY+8ejbA=", "requires": { "create-error-class": "^3.0.0", @@ -10667,24 +10647,24 @@ "dependencies": { "get-stream": { "version": "3.0.0", - "resolved": "http://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", + "resolved": false, "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=" } } }, "graceful-fs": { "version": "4.2.3", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", + "resolved": false, "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==" }, "har-schema": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "resolved": false, "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" }, "har-validator": { "version": "5.1.0", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.0.tgz", + "resolved": false, "integrity": "sha512-+qnmNjI4OfH2ipQ9VQOw23bBd/ibtfbVdK2fYbY4acTDqKTW/YDp9McimZdDbG8iV9fZizUqQMD5xvriB146TA==", "requires": { "ajv": "^5.3.0", @@ -10693,7 +10673,7 @@ }, "has": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "resolved": false, "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", "requires": { "function-bind": "^1.1.1" @@ -10701,17 +10681,17 @@ }, "has-flag": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "resolved": false, "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" }, "has-symbols": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", + "resolved": false, "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=" }, "has-unicode": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "resolved": false, "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=" }, "hosted-git-info": { @@ -10721,12 +10701,12 @@ }, "http-cache-semantics": { "version": "3.8.1", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz", + "resolved": false, "integrity": "sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w==" }, "http-proxy-agent": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz", + "resolved": false, "integrity": "sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg==", "requires": { "agent-base": "4", @@ -10735,7 +10715,7 @@ }, "http-signature": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "resolved": false, "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", "requires": { "assert-plus": "^1.0.0", @@ -10745,7 +10725,7 @@ }, "https-proxy-agent": { "version": "2.2.4", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz", + "resolved": false, "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==", "requires": { "agent-base": "^4.3.0", @@ -10754,7 +10734,7 @@ }, "humanize-ms": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "resolved": false, "integrity": "sha1-xG4xWaKT9riW2ikxbYtv6Lt5u+0=", "requires": { "ms": "^2.0.0" @@ -10762,7 +10742,7 @@ }, "iconv-lite": { "version": "0.4.23", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", + "resolved": false, "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==", "requires": { "safer-buffer": ">= 2.1.2 < 3" @@ -10770,12 +10750,12 @@ }, "iferr": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/iferr/-/iferr-1.0.2.tgz", + "resolved": false, "integrity": "sha512-9AfeLfji44r5TKInjhz3W9DyZI1zR1JAf2hVBMGhddAKPqBsupb89jGfbCTHIGZd6fGZl9WlHdn4AObygyMKwg==" }, "ignore-walk": { "version": "3.0.3", - "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.3.tgz", + "resolved": false, "integrity": "sha512-m7o6xuOaT1aqheYHKf8W6J5pYH85ZI9w077erOzLje3JsB1gkafkAhHHY19dqjulgIZHFm32Cp5uNZgcQqdJKw==", "requires": { "minimatch": "^3.0.4" @@ -10783,22 +10763,22 @@ }, "import-lazy": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", + "resolved": false, "integrity": "sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=" }, "imurmurhash": { "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "resolved": false, "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=" }, "infer-owner": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", + "resolved": false, "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==" }, "inflight": { "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "resolved": false, "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "requires": { "once": "^1.3.0", @@ -10807,17 +10787,17 @@ }, "inherits": { "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "resolved": false, "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, "ini": { "version": "1.3.5", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", + "resolved": false, "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==" }, "init-package-json": { "version": "1.10.3", - "resolved": "https://registry.npmjs.org/init-package-json/-/init-package-json-1.10.3.tgz", + "resolved": false, "integrity": "sha512-zKSiXKhQveNteyhcj1CoOP8tqp1QuxPIPBl8Bid99DGLFqA1p87M6lNgfjJHSBoWJJlidGOv5rWjyYKEB3g2Jw==", "requires": { "glob": "^7.1.1", @@ -10832,22 +10812,22 @@ }, "invert-kv": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz", + "resolved": false, "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==" }, "ip": { "version": "1.1.5", - "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", + "resolved": false, "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=" }, "ip-regex": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz", + "resolved": false, "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=" }, "is-callable": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", + "resolved": false, "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==" }, "is-ci": { @@ -10860,14 +10840,14 @@ "dependencies": { "ci-info": { "version": "1.6.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-1.6.0.tgz", + "resolved": false, "integrity": "sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A==" } } }, "is-cidr": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-cidr/-/is-cidr-3.0.0.tgz", + "resolved": false, "integrity": "sha512-8Xnnbjsb0x462VoYiGlhEi+drY8SFwrHiSYuzc/CEwco55vkehTaxAyIjEdpi3EMvLPPJAJi9FlzP+h+03gp0Q==", "requires": { "cidr-regex": "^2.0.10" @@ -10875,12 +10855,12 @@ }, "is-date-object": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", + "resolved": false, "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=" }, "is-fullwidth-code-point": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "resolved": false, "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", "requires": { "number-is-nan": "^1.0.0" @@ -10888,7 +10868,7 @@ }, "is-installed-globally": { "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.1.0.tgz", + "resolved": false, "integrity": "sha1-Df2Y9akRFxbdU13aZJL2e/PSWoA=", "requires": { "global-dirs": "^0.1.0", @@ -10897,17 +10877,17 @@ }, "is-npm": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-1.0.0.tgz", + "resolved": false, "integrity": "sha1-8vtjpl5JBbQGyGBydloaTceTufQ=" }, "is-obj": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", + "resolved": false, "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=" }, "is-path-inside": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", + "resolved": false, "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", "requires": { "path-is-inside": "^1.0.1" @@ -10915,12 +10895,12 @@ }, "is-redirect": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-redirect/-/is-redirect-1.0.0.tgz", + "resolved": false, "integrity": "sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ=" }, "is-regex": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", + "resolved": false, "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", "requires": { "has": "^1.0.1" @@ -10933,12 +10913,12 @@ }, "is-stream": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "resolved": false, "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" }, "is-symbol": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz", + "resolved": false, "integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==", "requires": { "has-symbols": "^1.0.0" @@ -10946,58 +10926,58 @@ }, "is-typedarray": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "resolved": false, "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" }, "isarray": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "resolved": false, "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" }, "isexe": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "resolved": false, "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" }, "isstream": { "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "resolved": false, "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" }, "jsbn": { "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "resolved": false, "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", "optional": true }, "json-parse-better-errors": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "resolved": false, "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==" }, "json-schema": { "version": "0.2.3", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "resolved": false, "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" }, "json-schema-traverse": { "version": "0.3.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", + "resolved": false, "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=" }, "json-stringify-safe": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "resolved": false, "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" }, "jsonparse": { "version": "1.3.1", - "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "resolved": false, "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=" }, "jsprim": { "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "resolved": false, "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", "requires": { "assert-plus": "1.0.0", @@ -11008,7 +10988,7 @@ }, "latest-version": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-3.1.0.tgz", + "resolved": false, "integrity": "sha1-ogU4P+oyKzO1rjsYq+4NwvNW7hU=", "requires": { "package-json": "^4.0.0" @@ -11016,12 +10996,12 @@ }, "lazy-property": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/lazy-property/-/lazy-property-1.0.0.tgz", + "resolved": false, "integrity": "sha1-hN3Es3Bnm6i9TNz6TAa0PVcREUc=" }, "lcid": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz", + "resolved": false, "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==", "requires": { "invert-kv": "^2.0.0" @@ -11029,7 +11009,7 @@ }, "libcipm": { "version": "4.0.7", - "resolved": "https://registry.npmjs.org/libcipm/-/libcipm-4.0.7.tgz", + "resolved": false, "integrity": "sha512-fTq33otU3PNXxxCTCYCYe7V96o59v/o7bvtspmbORXpgFk+wcWrGf5x6tBgui5gCed/45/wtPomBsZBYm5KbIw==", "requires": { "bin-links": "^1.1.2", @@ -11051,7 +11031,7 @@ }, "libnpm": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/libnpm/-/libnpm-3.0.1.tgz", + "resolved": false, "integrity": "sha512-d7jU5ZcMiTfBqTUJVZ3xid44fE5ERBm9vBnmhp2ECD2Ls+FNXWxHSkO7gtvrnbLO78gwPdNPz1HpsF3W4rjkBQ==", "requires": { "bin-links": "^1.1.2", @@ -11078,7 +11058,7 @@ }, "libnpmaccess": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/libnpmaccess/-/libnpmaccess-3.0.2.tgz", + "resolved": false, "integrity": "sha512-01512AK7MqByrI2mfC7h5j8N9V4I7MHJuk9buo8Gv+5QgThpOgpjB7sQBDDkeZqRteFb1QM/6YNdHfG7cDvfAQ==", "requires": { "aproba": "^2.0.0", @@ -11089,7 +11069,7 @@ }, "libnpmconfig": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/libnpmconfig/-/libnpmconfig-1.2.1.tgz", + "resolved": false, "integrity": "sha512-9esX8rTQAHqarx6qeZqmGQKBNZR5OIbl/Ayr0qQDy3oXja2iFVQQI81R6GZ2a02bSNZ9p3YOGX1O6HHCb1X7kA==", "requires": { "figgy-pudding": "^3.5.1", @@ -11099,7 +11079,7 @@ "dependencies": { "find-up": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "resolved": false, "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", "requires": { "locate-path": "^3.0.0" @@ -11107,7 +11087,7 @@ }, "locate-path": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "resolved": false, "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", "requires": { "p-locate": "^3.0.0", @@ -11116,7 +11096,7 @@ }, "p-limit": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.0.tgz", + "resolved": false, "integrity": "sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ==", "requires": { "p-try": "^2.0.0" @@ -11124,7 +11104,7 @@ }, "p-locate": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "resolved": false, "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", "requires": { "p-limit": "^2.0.0" @@ -11132,14 +11112,14 @@ }, "p-try": { "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "resolved": false, "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" } } }, "libnpmhook": { "version": "5.0.3", - "resolved": "https://registry.npmjs.org/libnpmhook/-/libnpmhook-5.0.3.tgz", + "resolved": false, "integrity": "sha512-UdNLMuefVZra/wbnBXECZPefHMGsVDTq5zaM/LgKNE9Keyl5YXQTnGAzEo+nFOpdRqTWI9LYi4ApqF9uVCCtuA==", "requires": { "aproba": "^2.0.0", @@ -11150,7 +11130,7 @@ }, "libnpmorg": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/libnpmorg/-/libnpmorg-1.0.1.tgz", + "resolved": false, "integrity": "sha512-0sRUXLh+PLBgZmARvthhYXQAWn0fOsa6T5l3JSe2n9vKG/lCVK4nuG7pDsa7uMq+uTt2epdPK+a2g6btcY11Ww==", "requires": { "aproba": "^2.0.0", @@ -11161,7 +11141,7 @@ }, "libnpmpublish": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/libnpmpublish/-/libnpmpublish-1.1.2.tgz", + "resolved": false, "integrity": "sha512-2yIwaXrhTTcF7bkJKIKmaCV9wZOALf/gsTDxVSu/Gu/6wiG3fA8ce8YKstiWKTxSFNC0R7isPUb6tXTVFZHt2g==", "requires": { "aproba": "^2.0.0", @@ -11177,7 +11157,7 @@ }, "libnpmsearch": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/libnpmsearch/-/libnpmsearch-2.0.2.tgz", + "resolved": false, "integrity": "sha512-VTBbV55Q6fRzTdzziYCr64+f8AopQ1YZ+BdPOv16UegIEaE8C0Kch01wo4s3kRTFV64P121WZJwgmBwrq68zYg==", "requires": { "figgy-pudding": "^3.5.1", @@ -11187,7 +11167,7 @@ }, "libnpmteam": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/libnpmteam/-/libnpmteam-1.0.2.tgz", + "resolved": false, "integrity": "sha512-p420vM28Us04NAcg1rzgGW63LMM6rwe+6rtZpfDxCcXxM0zUTLl7nPFEnRF3JfFBF5skF/yuZDUthTsHgde8QA==", "requires": { "aproba": "^2.0.0", @@ -11198,7 +11178,7 @@ }, "libnpx": { "version": "10.2.2", - "resolved": "https://registry.npmjs.org/libnpx/-/libnpx-10.2.2.tgz", + "resolved": false, "integrity": "sha512-ujaYToga1SAX5r7FU5ShMFi88CWpY75meNZtr6RtEyv4l2ZK3+Wgvxq2IqlwWBiDZOqhumdeiocPS1aKrCMe3A==", "requires": { "dotenv": "^5.0.1", @@ -11213,7 +11193,7 @@ }, "locate-path": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "resolved": false, "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", "requires": { "p-locate": "^2.0.0", @@ -11222,7 +11202,7 @@ }, "lock-verify": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/lock-verify/-/lock-verify-2.1.0.tgz", + "resolved": false, "integrity": "sha512-vcLpxnGvrqisKvLQ2C2v0/u7LVly17ak2YSgoK4PrdsYBXQIax19vhKiLfvKNFx7FRrpTnitrpzF/uuCMuorIg==", "requires": { "npm-package-arg": "^6.1.0", @@ -11231,7 +11211,7 @@ }, "lockfile": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/lockfile/-/lockfile-1.0.4.tgz", + "resolved": false, "integrity": "sha512-cvbTwETRfsFh4nHsL1eGWapU1XFi5Ot9E85sWAwia7Y7EgB7vfqcZhTKZ+l7hCGxSPoushMv5GKhT5PdLv03WA==", "requires": { "signal-exit": "^3.0.2" @@ -11239,12 +11219,12 @@ }, "lodash._baseindexof": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/lodash._baseindexof/-/lodash._baseindexof-3.1.0.tgz", + "resolved": false, "integrity": "sha1-/lK1OhxnYeQmGNZU5KJXie1hgiw=" }, "lodash._baseuniq": { "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash._baseuniq/-/lodash._baseuniq-4.6.0.tgz", + "resolved": false, "integrity": "sha1-DrtE5FaBSveQXGIS+iybLVG4Qeg=", "requires": { "lodash._createset": "~4.0.0", @@ -11253,17 +11233,17 @@ }, "lodash._bindcallback": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz", + "resolved": false, "integrity": "sha1-5THCdkTPi1epnhftlbNcdIeJOS4=" }, "lodash._cacheindexof": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/lodash._cacheindexof/-/lodash._cacheindexof-3.0.2.tgz", + "resolved": false, "integrity": "sha1-PcaayCSY0u5ePOVgkbr9Ktx73pI=" }, "lodash._createcache": { "version": "3.1.2", - "resolved": "https://registry.npmjs.org/lodash._createcache/-/lodash._createcache-3.1.2.tgz", + "resolved": false, "integrity": "sha1-VtagZAF2JeeevKa4AY4XRAvc8JM=", "requires": { "lodash._getnative": "^3.0.0" @@ -11271,52 +11251,52 @@ }, "lodash._createset": { "version": "4.0.3", - "resolved": "https://registry.npmjs.org/lodash._createset/-/lodash._createset-4.0.3.tgz", + "resolved": false, "integrity": "sha1-D0ZZ+7CddRlPqeK4imZE02PJ/iY=" }, "lodash._getnative": { "version": "3.9.1", - "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz", + "resolved": false, "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=" }, "lodash._root": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/lodash._root/-/lodash._root-3.0.1.tgz", + "resolved": false, "integrity": "sha1-+6HEUkwZ7ppfgTa0YJ8BfPTe1pI=" }, "lodash.clonedeep": { "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "resolved": false, "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=" }, "lodash.restparam": { "version": "3.6.1", - "resolved": "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz", + "resolved": false, "integrity": "sha1-k2pOMJ7zMKdkXtQUWYbIWuWyCAU=" }, "lodash.union": { "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz", + "resolved": false, "integrity": "sha1-SLtQiECfFvGCFmZkHETdGqrjzYg=" }, "lodash.uniq": { "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "resolved": false, "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=" }, "lodash.without": { "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.without/-/lodash.without-4.4.0.tgz", + "resolved": false, "integrity": "sha1-PNRXSgC2e643OpS3SHcmQFB7eqw=" }, "lowercase-keys": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", + "resolved": false, "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==" }, "lru-cache": { "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "resolved": false, "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", "requires": { "yallist": "^3.0.2" @@ -11324,7 +11304,7 @@ }, "make-dir": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", + "resolved": false, "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", "requires": { "pify": "^3.0.0" @@ -11332,7 +11312,7 @@ }, "make-fetch-happen": { "version": "5.0.2", - "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-5.0.2.tgz", + "resolved": false, "integrity": "sha512-07JHC0r1ykIoruKO8ifMXu+xEU8qOXDFETylktdug6vJDACnP+HKevOu3PXyNPzFyTSlz8vrBYlBO1JZRe8Cag==", "requires": { "agentkeepalive": "^3.4.1", @@ -11350,7 +11330,7 @@ }, "map-age-cleaner": { "version": "0.1.3", - "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz", + "resolved": false, "integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==", "requires": { "p-defer": "^1.0.0" @@ -11358,12 +11338,12 @@ }, "meant": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/meant/-/meant-1.0.1.tgz", + "resolved": false, "integrity": "sha512-UakVLFjKkbbUwNWJ2frVLnnAtbb7D7DsloxRd3s/gDpI8rdv8W5Hp3NaDb+POBI1fQdeussER6NB8vpcRURvlg==" }, "mem": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/mem/-/mem-4.3.0.tgz", + "resolved": false, "integrity": "sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w==", "requires": { "map-age-cleaner": "^0.1.1", @@ -11373,19 +11353,19 @@ "dependencies": { "mimic-fn": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "resolved": false, "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==" } } }, "mime-db": { "version": "1.35.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.35.0.tgz", + "resolved": false, "integrity": "sha512-JWT/IcCTsB0Io3AhWUMjRqucrHSPsSf2xKLaRldJVULioggvkJvggZ3VXNNSRkCddE6D+BUI4HEIZIA2OjwIvg==" }, "mime-types": { "version": "2.1.19", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.19.tgz", + "resolved": false, "integrity": "sha512-P1tKYHVSZ6uFo26mtnve4HQFE3koh1UWVkp8YUC+ESBHe945xWSoXuHHiGarDqcEZ+whpCDnlNw5LON0kLo+sw==", "requires": { "mime-db": "~1.35.0" @@ -11393,7 +11373,7 @@ }, "minimatch": { "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "resolved": false, "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "requires": { "brace-expansion": "^1.1.7" @@ -11401,7 +11381,7 @@ }, "minizlib": { "version": "1.3.3", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.3.3.tgz", + "resolved": false, "integrity": "sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==", "requires": { "minipass": "^2.9.0" @@ -11409,7 +11389,7 @@ "dependencies": { "minipass": { "version": "2.9.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz", + "resolved": false, "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==", "requires": { "safe-buffer": "^5.1.2", @@ -11420,7 +11400,7 @@ }, "mississippi": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz", + "resolved": false, "integrity": "sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA==", "requires": { "concat-stream": "^1.5.0", @@ -11452,7 +11432,7 @@ }, "move-concurrently": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", + "resolved": false, "integrity": "sha1-viwAX9oy4LKa8fBdfEszIUxwH5I=", "requires": { "aproba": "^1.1.1", @@ -11465,29 +11445,29 @@ "dependencies": { "aproba": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "resolved": false, "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" } } }, "ms": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "resolved": false, "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" }, "mute-stream": { "version": "0.0.7", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", + "resolved": false, "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=" }, "nice-try": { "version": "1.0.5", - "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "resolved": false, "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==" }, "node-fetch-npm": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/node-fetch-npm/-/node-fetch-npm-2.0.2.tgz", + "resolved": false, "integrity": "sha512-nJIxm1QmAj4v3nfCvEeCrYSoVwXyxLnaPBK5W1W5DGEJwjlKuC2VEUycGw5oxk+4zZahRrB84PUJJgEmhFTDFw==", "requires": { "encoding": "^0.1.11", @@ -11515,7 +11495,7 @@ }, "nopt": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz", + "resolved": false, "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=", "requires": { "abbrev": "1", @@ -11524,7 +11504,7 @@ }, "normalize-package-data": { "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "resolved": false, "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", "requires": { "hosted-git-info": "^2.1.4", @@ -11535,7 +11515,7 @@ "dependencies": { "resolve": { "version": "1.10.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.10.0.tgz", + "resolved": false, "integrity": "sha512-3sUr9aq5OfSg2S9pNtPA9hL1FVEAjvfOC4leW0SNf/mpnaakz2a9femSd6LqAww2RaFctwyf1lCqnTHuF1rxDg==", "requires": { "path-parse": "^1.0.6" @@ -11545,7 +11525,7 @@ }, "npm-audit-report": { "version": "1.3.2", - "resolved": "https://registry.npmjs.org/npm-audit-report/-/npm-audit-report-1.3.2.tgz", + "resolved": false, "integrity": "sha512-abeqS5ONyXNaZJPGAf6TOUMNdSe1Y6cpc9MLBRn+CuUoYbfdca6AxOyXVlfIv9OgKX+cacblbG5w7A6ccwoTPw==", "requires": { "cli-table3": "^0.5.0", @@ -11554,7 +11534,7 @@ }, "npm-bundled": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.1.tgz", + "resolved": false, "integrity": "sha512-gqkfgGePhTpAEgUsGEgcq1rqPXA+tv/aVBlgEzfXwA1yiUJF7xtEt3CtVwOjNYQOVknDk0F20w58Fnm3EtG0fA==", "requires": { "npm-normalize-package-bin": "^1.0.1" @@ -11562,12 +11542,12 @@ }, "npm-cache-filename": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/npm-cache-filename/-/npm-cache-filename-1.0.2.tgz", + "resolved": false, "integrity": "sha1-3tMGxbC/yHCp6fr4I7xfKD4FrhE=" }, "npm-install-checks": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-3.0.2.tgz", + "resolved": false, "integrity": "sha512-E4kzkyZDIWoin6uT5howP8VDvkM+E8IQDcHAycaAxMbwkqhIg5eEYALnXOl3Hq9MrkdQB/2/g1xwBINXdKSRkg==", "requires": { "semver": "^2.3.0 || 3.x || 4 || 5" @@ -11575,7 +11555,7 @@ }, "npm-lifecycle": { "version": "3.1.4", - "resolved": "https://registry.npmjs.org/npm-lifecycle/-/npm-lifecycle-3.1.4.tgz", + "resolved": false, "integrity": "sha512-tgs1PaucZwkxECGKhC/stbEgFyc3TGh2TJcg2CDr6jbvQRdteHNhmMeljRzpe4wgFAXQADoy1cSqqi7mtiAa5A==", "requires": { "byline": "^5.0.0", @@ -11590,17 +11570,17 @@ }, "npm-logical-tree": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/npm-logical-tree/-/npm-logical-tree-1.2.1.tgz", + "resolved": false, "integrity": "sha512-AJI/qxDB2PWI4LG1CYN579AY1vCiNyWfkiquCsJWqntRu/WwimVrC8yXeILBFHDwxfOejxewlmnvW9XXjMlYIg==" }, "npm-normalize-package-bin": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz", + "resolved": false, "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==" }, "npm-package-arg": { "version": "6.1.1", - "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-6.1.1.tgz", + "resolved": false, "integrity": "sha512-qBpssaL3IOZWi5vEKUKW0cO7kzLeT+EQO9W8RsLOZf76KF9E/K9+wH0C7t06HXPpaH8WH5xF1MExLuCwbTqRUg==", "requires": { "hosted-git-info": "^2.7.1", @@ -11621,7 +11601,7 @@ }, "npm-pick-manifest": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-3.0.2.tgz", + "resolved": false, "integrity": "sha512-wNprTNg+X5nf+tDi+hbjdHhM4bX+mKqv6XmPh7B5eG+QY9VARfQPfCEH013H5GqfNj6ee8Ij2fg8yk0mzps1Vw==", "requires": { "figgy-pudding": "^3.5.1", @@ -11655,14 +11635,14 @@ "dependencies": { "safe-buffer": { "version": "5.2.0", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", + "resolved": false, "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==" } } }, "npm-run-path": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "resolved": false, "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", "requires": { "path-key": "^2.0.0" @@ -11670,12 +11650,12 @@ }, "npm-user-validate": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/npm-user-validate/-/npm-user-validate-1.0.0.tgz", + "resolved": false, "integrity": "sha1-jOyg9c6gTU6TUZ73LQVXp1Ei6VE=" }, "npmlog": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", + "resolved": false, "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", "requires": { "are-we-there-yet": "~1.1.2", @@ -11686,27 +11666,27 @@ }, "number-is-nan": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "resolved": false, "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" }, "oauth-sign": { "version": "0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "resolved": false, "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" }, "object-assign": { "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "resolved": false, "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" }, "object-keys": { "version": "1.0.12", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.12.tgz", + "resolved": false, "integrity": "sha512-FTMyFUm2wBcGHnH2eXmz7tC6IwlqQZ6mVZ+6dm6vZ4IQIHjs6FdNsQBuKGPuUUUY6NfJw2PshC08Tn6LzLDOag==" }, "object.getownpropertydescriptors": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz", + "resolved": false, "integrity": "sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY=", "requires": { "define-properties": "^1.1.2", @@ -11715,7 +11695,7 @@ }, "once": { "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "resolved": false, "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "requires": { "wrappy": "1" @@ -11723,17 +11703,17 @@ }, "opener": { "version": "1.5.1", - "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.1.tgz", + "resolved": false, "integrity": "sha512-goYSy5c2UXE4Ra1xixabeVh1guIX/ZV/YokJksb6q2lubWu6UbvPQ20p542/sFIll1nl8JnCyK9oBaOcCWXwvA==" }, "os-homedir": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "resolved": false, "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=" }, "os-locale": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz", + "resolved": false, "integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==", "requires": { "execa": "^1.0.0", @@ -11743,7 +11723,7 @@ "dependencies": { "cross-spawn": { "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "resolved": false, "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", "requires": { "nice-try": "^1.0.4", @@ -11755,7 +11735,7 @@ }, "execa": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "resolved": false, "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", "requires": { "cross-spawn": "^6.0.0", @@ -11771,12 +11751,12 @@ }, "os-tmpdir": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "resolved": false, "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" }, "osenv": { "version": "0.1.5", - "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", + "resolved": false, "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", "requires": { "os-homedir": "^1.0.0", @@ -11785,22 +11765,22 @@ }, "p-defer": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", + "resolved": false, "integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=" }, "p-finally": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "resolved": false, "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=" }, "p-is-promise": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.1.0.tgz", + "resolved": false, "integrity": "sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg==" }, "p-limit": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.2.0.tgz", + "resolved": false, "integrity": "sha512-Y/OtIaXtUPr4/YpMv1pCL5L5ed0rumAaAeBSj12F+bSlMdys7i8oQF/GUJmfpTS/QoaRrS/k6pma29haJpsMng==", "requires": { "p-try": "^1.0.0" @@ -11808,7 +11788,7 @@ }, "p-locate": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "resolved": false, "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", "requires": { "p-limit": "^1.1.0" @@ -11816,12 +11796,12 @@ }, "p-try": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "resolved": false, "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=" }, "package-json": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/package-json/-/package-json-4.0.1.tgz", + "resolved": false, "integrity": "sha1-iGmgQBJTZhxMTKPabCEh7VVfXu0=", "requires": { "got": "^6.7.1", @@ -11832,7 +11812,7 @@ }, "pacote": { "version": "9.5.12", - "resolved": "https://registry.npmjs.org/pacote/-/pacote-9.5.12.tgz", + "resolved": false, "integrity": "sha512-BUIj/4kKbwWg4RtnBncXPJd15piFSVNpTzY0rysSr3VnMowTYgkGKcaHrbReepAkjTr8lH2CVWRi58Spg2CicQ==", "requires": { "bluebird": "^3.5.3", @@ -11869,7 +11849,7 @@ "dependencies": { "minipass": { "version": "2.9.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz", + "resolved": false, "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==", "requires": { "safe-buffer": "^5.1.2", @@ -11880,7 +11860,7 @@ }, "parallel-transform": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.1.0.tgz", + "resolved": false, "integrity": "sha1-1BDwZbBdojCB/NEPKIVMKb2jOwY=", "requires": { "cyclist": "~0.2.2", @@ -11890,7 +11870,7 @@ "dependencies": { "readable-stream": { "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "resolved": false, "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "requires": { "core-util-is": "~1.0.0", @@ -11904,7 +11884,7 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "resolved": false, "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { "safe-buffer": "~5.1.0" @@ -11914,57 +11894,57 @@ }, "path-exists": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "resolved": false, "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=" }, "path-is-absolute": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "resolved": false, "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" }, "path-is-inside": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "resolved": false, "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=" }, "path-key": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "resolved": false, "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=" }, "path-parse": { "version": "1.0.6", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "resolved": false, "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==" }, "performance-now": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "resolved": false, "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" }, "pify": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "resolved": false, "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=" }, "prepend-http": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", + "resolved": false, "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=" }, "process-nextick-args": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", + "resolved": false, "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==" }, "promise-inflight": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "resolved": false, "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=" }, "promise-retry": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-1.1.1.tgz", + "resolved": false, "integrity": "sha1-ZznpaOMFHaIM5kl/srUPaRHfPW0=", "requires": { "err-code": "^1.0.0", @@ -11973,14 +11953,14 @@ "dependencies": { "retry": { "version": "0.10.1", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.10.1.tgz", + "resolved": false, "integrity": "sha1-52OI0heZLCUnUCQdPTlW/tmNj/Q=" } } }, "promzard": { "version": "0.3.0", - "resolved": "https://registry.npmjs.org/promzard/-/promzard-0.3.0.tgz", + "resolved": false, "integrity": "sha1-JqXW7ox97kyxIggwWs+5O6OCqe4=", "requires": { "read": "1" @@ -11988,12 +11968,12 @@ }, "proto-list": { "version": "1.2.4", - "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", + "resolved": false, "integrity": "sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk=" }, "protoduck": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/protoduck/-/protoduck-5.0.1.tgz", + "resolved": false, "integrity": "sha512-WxoCeDCoCBY55BMvj4cAEjdVUFGRWed9ZxPlqTKYyw1nDDTQ4pqmnIMAGfJlg7Dx35uB/M+PHJPTmGOvaCaPTg==", "requires": { "genfun": "^5.0.0" @@ -12001,22 +11981,22 @@ }, "prr": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", + "resolved": false, "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=" }, "pseudomap": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "resolved": false, "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" }, "psl": { "version": "1.1.29", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.29.tgz", + "resolved": false, "integrity": "sha512-AeUmQ0oLN02flVHXWh9sSJF7mcdFq0ppid/JkErufc3hGIV/AMa8Fo9VgDo/cT2jFdOWoFvHp90qqBH54W+gjQ==" }, "pump": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "resolved": false, "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", "requires": { "end-of-stream": "^1.1.0", @@ -12025,7 +12005,7 @@ }, "pumpify": { "version": "1.5.1", - "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", + "resolved": false, "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", "requires": { "duplexify": "^3.6.0", @@ -12035,7 +12015,7 @@ "dependencies": { "pump": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", + "resolved": false, "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", "requires": { "end-of-stream": "^1.1.0", @@ -12046,22 +12026,22 @@ }, "punycode": { "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "resolved": false, "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" }, "qrcode-terminal": { "version": "0.12.0", - "resolved": "https://registry.npmjs.org/qrcode-terminal/-/qrcode-terminal-0.12.0.tgz", + "resolved": false, "integrity": "sha512-EXtzRZmC+YGmGlDFbXKxQiMZNwCLEO6BANKXG4iCtSIM0yqc/pappSx3RIKr4r0uh5JsBckOXeKrB3Iz7mdQpQ==" }, "qs": { "version": "6.5.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "resolved": false, "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" }, "query-string": { "version": "6.8.2", - "resolved": "https://registry.npmjs.org/query-string/-/query-string-6.8.2.tgz", + "resolved": false, "integrity": "sha512-J3Qi8XZJXh93t2FiKyd/7Ec6GNifsjKXUsVFkSBj/kjLsDylWhnCz4NT1bkPcKotttPW+QbKGqqPH8OoI2pdqw==", "requires": { "decode-uri-component": "^0.2.0", @@ -12071,7 +12051,7 @@ }, "qw": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/qw/-/qw-1.0.1.tgz", + "resolved": false, "integrity": "sha1-77/cdA+a0FQwRCassYNBLMi5ltQ=" }, "rc": { @@ -12094,7 +12074,7 @@ }, "read": { "version": "1.0.7", - "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz", + "resolved": false, "integrity": "sha1-s9oZvQUkMal2cdRKQmNK33ELQMQ=", "requires": { "mute-stream": "~0.0.4" @@ -12102,7 +12082,7 @@ }, "read-cmd-shim": { "version": "1.0.5", - "resolved": "https://registry.npmjs.org/read-cmd-shim/-/read-cmd-shim-1.0.5.tgz", + "resolved": false, "integrity": "sha512-v5yCqQ/7okKoZZkBQUAfTsQ3sVJtXdNfbPnI5cceppoxEVLYA3k+VtV2omkeo8MS94JCy4fSiUwlRBAwCVRPUA==", "requires": { "graceful-fs": "^4.1.2" @@ -12110,7 +12090,7 @@ }, "read-installed": { "version": "4.0.3", - "resolved": "https://registry.npmjs.org/read-installed/-/read-installed-4.0.3.tgz", + "resolved": false, "integrity": "sha1-/5uLZ/GH0eTCm5/rMfayI6zRkGc=", "requires": { "debuglog": "^1.0.1", @@ -12124,7 +12104,7 @@ }, "read-package-json": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-2.1.1.tgz", + "resolved": false, "integrity": "sha512-dAiqGtVc/q5doFz6096CcnXhpYk0ZN8dEKVkGLU0CsASt8SrgF6SF7OTKAYubfvFhWaqofl+Y8HK19GR8jwW+A==", "requires": { "glob": "^7.1.1", @@ -12136,7 +12116,7 @@ }, "read-package-tree": { "version": "5.3.1", - "resolved": "https://registry.npmjs.org/read-package-tree/-/read-package-tree-5.3.1.tgz", + "resolved": false, "integrity": "sha512-mLUDsD5JVtlZxjSlPPx1RETkNjjvQYuweKwNVt1Sn8kP5Jh44pvYuUHCp6xSVDZWbNxVxG5lyZJ921aJH61sTw==", "requires": { "read-package-json": "^2.0.0", @@ -12156,7 +12136,7 @@ }, "readdir-scoped-modules": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/readdir-scoped-modules/-/readdir-scoped-modules-1.1.0.tgz", + "resolved": false, "integrity": "sha512-asaikDeqAQg7JifRsZn1NJZXo9E+VwlyCfbkZhwyISinqk5zNS6266HS5kah6P0SaQKGF6SkNnZVHUzHFYxYDw==", "requires": { "debuglog": "^1.0.1", @@ -12176,7 +12156,7 @@ }, "registry-url": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-3.1.0.tgz", + "resolved": false, "integrity": "sha1-PU74cPc93h138M+aOBQyRE4XSUI=", "requires": { "rc": "^1.0.1" @@ -12184,7 +12164,7 @@ }, "request": { "version": "2.88.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", + "resolved": false, "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", "requires": { "aws-sign2": "~0.7.0", @@ -12211,22 +12191,22 @@ }, "require-directory": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "resolved": false, "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" }, "require-main-filename": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", + "resolved": false, "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=" }, "resolve-from": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "resolved": false, "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==" }, "retry": { "version": "0.12.0", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "resolved": false, "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=" }, "rimraf": { @@ -12239,7 +12219,7 @@ }, "run-queue": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/run-queue/-/run-queue-1.0.3.tgz", + "resolved": false, "integrity": "sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec=", "requires": { "aproba": "^1.1.1" @@ -12247,29 +12227,29 @@ "dependencies": { "aproba": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "resolved": false, "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" } } }, "safe-buffer": { "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "resolved": false, "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, "safer-buffer": { "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "resolved": false, "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "semver": { "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "resolved": false, "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" }, "semver-diff": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-2.1.0.tgz", + "resolved": false, "integrity": "sha1-S7uEN8jTfksM8aaP1ybsbWRdbTY=", "requires": { "semver": "^5.0.3" @@ -12277,12 +12257,12 @@ }, "set-blocking": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "resolved": false, "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" }, "sha": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/sha/-/sha-3.0.0.tgz", + "resolved": false, "integrity": "sha512-DOYnM37cNsLNSGIG/zZWch5CKIRNoLdYUQTQlcgkRkoYIUwDYjqDyye16YcDZg/OPdcbUgTKMjc4SY6TB7ZAPw==", "requires": { "graceful-fs": "^4.1.2" @@ -12290,7 +12270,7 @@ }, "shebang-command": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "resolved": false, "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", "requires": { "shebang-regex": "^1.0.0" @@ -12298,27 +12278,27 @@ }, "shebang-regex": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "resolved": false, "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=" }, "signal-exit": { "version": "3.0.2", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "resolved": false, "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" }, "slide": { "version": "1.1.6", - "resolved": "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz", + "resolved": false, "integrity": "sha1-VusCfWW00tzmyy4tMsTUr8nh1wc=" }, "smart-buffer": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.1.0.tgz", + "resolved": false, "integrity": "sha512-iVICrxOzCynf/SNaBQCw34eM9jROU/s5rzIhpOvzhzuYHfJR/DhZfDkXiZSgKXfgv26HT3Yni3AV/DGw0cGnnw==" }, "socks": { "version": "2.3.3", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.3.3.tgz", + "resolved": false, "integrity": "sha512-o5t52PCNtVdiOvzMry7wU4aOqYWL0PeCXRWBEiJow4/i/wr+wpsJQ9awEu1EonLIqsfGd5qSgDdxEOvCdmBEpA==", "requires": { "ip": "1.1.5", @@ -12327,7 +12307,7 @@ }, "socks-proxy-agent": { "version": "4.0.2", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-4.0.2.tgz", + "resolved": false, "integrity": "sha512-NT6syHhI9LmuEMSK6Kd2V7gNv5KFZoLE7V5udWmn0de+3Mkj3UMA/AJPLyeNUVmElCurSHtUdM3ETpR3z770Wg==", "requires": { "agent-base": "~4.2.1", @@ -12336,7 +12316,7 @@ "dependencies": { "agent-base": { "version": "4.2.1", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.2.1.tgz", + "resolved": false, "integrity": "sha512-JVwXMr9nHYTUXsBFKUqhJwvlcYU/blreOEUkhNR2eXZIvwd+c+o5V4MgDPKWnMS/56awN3TRzIP+KoPn+roQtg==", "requires": { "es6-promisify": "^5.0.0" @@ -12346,12 +12326,12 @@ }, "sorted-object": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/sorted-object/-/sorted-object-2.0.1.tgz", + "resolved": false, "integrity": "sha1-fWMfS9OnmKJK8d/8+/6DM3pd9fw=" }, "sorted-union-stream": { "version": "2.1.3", - "resolved": "https://registry.npmjs.org/sorted-union-stream/-/sorted-union-stream-2.1.3.tgz", + "resolved": false, "integrity": "sha1-x3lMfgd4gAUv9xqNSi27Sppjisc=", "requires": { "from2": "^1.3.0", @@ -12360,7 +12340,7 @@ "dependencies": { "from2": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/from2/-/from2-1.3.0.tgz", + "resolved": false, "integrity": "sha1-iEE7qqX5pZfP3pIh2GmGzTwGHf0=", "requires": { "inherits": "~2.0.1", @@ -12369,12 +12349,12 @@ }, "isarray": { "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "resolved": false, "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" }, "readable-stream": { "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "resolved": false, "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", "requires": { "core-util-is": "~1.0.0", @@ -12385,14 +12365,14 @@ }, "string_decoder": { "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "resolved": false, "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" } } }, "spdx-correct": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.0.0.tgz", + "resolved": false, "integrity": "sha512-N19o9z5cEyc8yQQPukRCZ9EUmb4HUpnrmaL/fxS2pBo2jbfcFRVuFZ/oFC+vZz0MNNk0h80iMn5/S6qGZOL5+g==", "requires": { "spdx-expression-parse": "^3.0.0", @@ -12401,12 +12381,12 @@ }, "spdx-exceptions": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.1.0.tgz", + "resolved": false, "integrity": "sha512-4K1NsmrlCU1JJgUrtgEeTVyfx8VaYea9J9LvARxhbHtVtohPs/gFGG5yy49beySjlIMhhXZ4QqujIZEfS4l6Cg==" }, "spdx-expression-parse": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", + "resolved": false, "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", "requires": { "spdx-exceptions": "^2.1.0", @@ -12415,17 +12395,17 @@ }, "spdx-license-ids": { "version": "3.0.3", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.3.tgz", + "resolved": false, "integrity": "sha512-uBIcIl3Ih6Phe3XHK1NqboJLdGfwr1UN3k6wSD1dZpmPsIkb8AGNbZYJ1fOBk834+Gxy8rpfDxrS6XLEMZMY2g==" }, "split-on-first": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/split-on-first/-/split-on-first-1.1.0.tgz", + "resolved": false, "integrity": "sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==" }, "sshpk": { "version": "1.14.2", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.14.2.tgz", + "resolved": false, "integrity": "sha1-xvxhZIo9nE52T9P8306hBeSSupg=", "requires": { "asn1": "~0.2.3", @@ -12441,7 +12421,7 @@ }, "ssri": { "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.1.tgz", + "resolved": false, "integrity": "sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA==", "requires": { "figgy-pudding": "^3.5.1" @@ -12449,7 +12429,7 @@ }, "stream-each": { "version": "1.2.2", - "resolved": "https://registry.npmjs.org/stream-each/-/stream-each-1.2.2.tgz", + "resolved": false, "integrity": "sha512-mc1dbFhGBxvTM3bIWmAAINbqiuAk9TATcfIQC8P+/+HJefgaiTlMn2dHvkX8qlI12KeYKSQ1Ua9RrIqrn1VPoA==", "requires": { "end-of-stream": "^1.1.0", @@ -12458,7 +12438,7 @@ }, "stream-iterate": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/stream-iterate/-/stream-iterate-1.2.0.tgz", + "resolved": false, "integrity": "sha1-K9fHcpbBcCpGSIuK1B95hl7s1OE=", "requires": { "readable-stream": "^2.1.5", @@ -12467,7 +12447,7 @@ "dependencies": { "readable-stream": { "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "resolved": false, "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "requires": { "core-util-is": "~1.0.0", @@ -12481,7 +12461,7 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "resolved": false, "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { "safe-buffer": "~5.1.0" @@ -12491,17 +12471,17 @@ }, "stream-shift": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.0.tgz", + "resolved": false, "integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=" }, "strict-uri-encode": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz", + "resolved": false, "integrity": "sha1-ucczDHBChi9rFC3CdLvMWGbONUY=" }, "string-width": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "resolved": false, "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", "requires": { "is-fullwidth-code-point": "^2.0.0", @@ -12510,17 +12490,17 @@ "dependencies": { "ansi-regex": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "resolved": false, "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" }, "is-fullwidth-code-point": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "resolved": false, "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" }, "strip-ansi": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "resolved": false, "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", "requires": { "ansi-regex": "^3.0.0" @@ -12545,12 +12525,12 @@ }, "stringify-package": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/stringify-package/-/stringify-package-1.0.1.tgz", + "resolved": false, "integrity": "sha512-sa4DUQsYciMP1xhKWGuFM04fB0LG/9DlluZoSVywUMRNvzid6XucHK0/90xGxRoHrAaROrcHK1aPKaijCtSrhg==" }, "strip-ansi": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "resolved": false, "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "requires": { "ansi-regex": "^2.0.0" @@ -12558,17 +12538,17 @@ }, "strip-eof": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "resolved": false, "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=" }, "strip-json-comments": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "resolved": false, "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=" }, "supports-color": { "version": "5.4.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", + "resolved": false, "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", "requires": { "has-flag": "^3.0.0" @@ -12576,7 +12556,7 @@ }, "tar": { "version": "4.4.13", - "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.13.tgz", + "resolved": false, "integrity": "sha512-w2VwSrBoHa5BsSyH+KxEqeQBAllHhccyMFVHtGtdMpF4W7IRWfZjFiQceJPChOeTsSDVUpER2T8FA93pr0L+QA==", "requires": { "chownr": "^1.1.1", @@ -12590,7 +12570,7 @@ "dependencies": { "minipass": { "version": "2.9.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz", + "resolved": false, "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==", "requires": { "safe-buffer": "^5.1.2", @@ -12601,7 +12581,7 @@ }, "term-size": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/term-size/-/term-size-1.2.0.tgz", + "resolved": false, "integrity": "sha1-RYuDiH8oj8Vtb/+/rSYuJmOO+mk=", "requires": { "execa": "^0.7.0" @@ -12609,17 +12589,17 @@ }, "text-table": { "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "resolved": false, "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=" }, "through": { "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "resolved": false, "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" }, "through2": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz", + "resolved": false, "integrity": "sha1-AARWmzfHx0ujnEPzzteNGtlBQL4=", "requires": { "readable-stream": "^2.1.5", @@ -12628,7 +12608,7 @@ "dependencies": { "readable-stream": { "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "resolved": false, "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "requires": { "core-util-is": "~1.0.0", @@ -12642,7 +12622,7 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "resolved": false, "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { "safe-buffer": "~5.1.0" @@ -12652,17 +12632,17 @@ }, "timed-out": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz", + "resolved": false, "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=" }, "tiny-relative-date": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/tiny-relative-date/-/tiny-relative-date-1.3.0.tgz", + "resolved": false, "integrity": "sha512-MOQHpzllWxDCHHaDno30hhLfbouoYlOI8YlMNtvKe1zXbjEVhbcEovQxvZrPvtiYW630GQDoMMarCnjfyfHA+A==" }, "tough-cookie": { "version": "2.4.3", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", + "resolved": false, "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", "requires": { "psl": "^1.1.24", @@ -12671,7 +12651,7 @@ }, "tunnel-agent": { "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "resolved": false, "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", "requires": { "safe-buffer": "^5.0.1" @@ -12679,28 +12659,28 @@ }, "tweetnacl": { "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "resolved": false, "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", "optional": true }, "typedarray": { "version": "0.0.6", - "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "resolved": false, "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" }, "uid-number": { "version": "0.0.6", - "resolved": "https://registry.npmjs.org/uid-number/-/uid-number-0.0.6.tgz", + "resolved": false, "integrity": "sha1-DqEOgDXo61uOREnwbaHHMGY7qoE=" }, "umask": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/umask/-/umask-1.1.0.tgz", + "resolved": false, "integrity": "sha1-8pzr8B31F5ErtY/5xOUP3o4zMg0=" }, "unique-filename": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", + "resolved": false, "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", "requires": { "unique-slug": "^2.0.0" @@ -12708,7 +12688,7 @@ }, "unique-slug": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.0.tgz", + "resolved": false, "integrity": "sha1-22Z258fMBimHj/GWCXx4hVrp9Ks=", "requires": { "imurmurhash": "^0.1.4" @@ -12716,7 +12696,7 @@ }, "unique-string": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-1.0.0.tgz", + "resolved": false, "integrity": "sha1-nhBXzKhRq7kzmPizOuGHuZyuwRo=", "requires": { "crypto-random-string": "^1.0.0" @@ -12724,17 +12704,17 @@ }, "unpipe": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "resolved": false, "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" }, "unzip-response": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/unzip-response/-/unzip-response-2.0.1.tgz", + "resolved": false, "integrity": "sha1-0vD3N9FrBhXnKmk17QQhRXLVb5c=" }, "update-notifier": { "version": "2.5.0", - "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-2.5.0.tgz", + "resolved": false, "integrity": "sha512-gwMdhgJHGuj/+wHJJs9e6PcCszpxR1b236igrOkUofGhqJuG+amlIKwApH1IW1WWl7ovZxsX49lMBWLxSdm5Dw==", "requires": { "boxen": "^1.2.1", @@ -12751,7 +12731,7 @@ }, "url-parse-lax": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz", + "resolved": false, "integrity": "sha1-evjzA2Rem9eaJy56FKxovAYJ2nM=", "requires": { "prepend-http": "^1.0.1" @@ -12759,17 +12739,17 @@ }, "util-deprecate": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "resolved": false, "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" }, "util-extend": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/util-extend/-/util-extend-1.0.3.tgz", + "resolved": false, "integrity": "sha1-p8IW0mdUUWljeztu3GypEZ4v+T8=" }, "util-promisify": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/util-promisify/-/util-promisify-2.1.0.tgz", + "resolved": false, "integrity": "sha1-PCI2R2xNMsX/PEcAKt18E7moKlM=", "requires": { "object.getownpropertydescriptors": "^2.0.3" @@ -12777,12 +12757,12 @@ }, "uuid": { "version": "3.3.3", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.3.tgz", + "resolved": false, "integrity": "sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ==" }, "validate-npm-package-license": { "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "resolved": false, "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", "requires": { "spdx-correct": "^3.0.0", @@ -12791,7 +12771,7 @@ }, "validate-npm-package-name": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz", + "resolved": false, "integrity": "sha1-X6kS2B630MdK/BQN5zF/DKffQ34=", "requires": { "builtins": "^1.0.3" @@ -12799,7 +12779,7 @@ }, "verror": { "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "resolved": false, "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", "requires": { "assert-plus": "^1.0.0", @@ -12809,7 +12789,7 @@ }, "wcwidth": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "resolved": false, "integrity": "sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=", "requires": { "defaults": "^1.0.3" @@ -12817,7 +12797,7 @@ }, "which": { "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "resolved": false, "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", "requires": { "isexe": "^2.0.0" @@ -12825,12 +12805,12 @@ }, "which-module": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "resolved": false, "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=" }, "wide-align": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.2.tgz", + "resolved": false, "integrity": "sha512-ijDLlyQ7s6x1JgCLur53osjm/UXUYD9+0PbYKrBsYisYXzCxN+HC3mYDNy/dWdmf3AwqwU3CXwDCvsNgGK1S0w==", "requires": { "string-width": "^1.0.2" @@ -12838,7 +12818,7 @@ "dependencies": { "string-width": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "resolved": false, "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "requires": { "code-point-at": "^1.0.0", @@ -12858,7 +12838,7 @@ }, "worker-farm": { "version": "1.7.0", - "resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.7.0.tgz", + "resolved": false, "integrity": "sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw==", "requires": { "errno": "~0.1.7" @@ -12866,7 +12846,7 @@ }, "wrap-ansi": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "resolved": false, "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", "requires": { "string-width": "^1.0.1", @@ -12875,7 +12855,7 @@ "dependencies": { "string-width": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "resolved": false, "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "requires": { "code-point-at": "^1.0.0", @@ -12887,12 +12867,12 @@ }, "wrappy": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "resolved": false, "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, "write-file-atomic": { "version": "2.4.3", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.3.tgz", + "resolved": false, "integrity": "sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==", "requires": { "graceful-fs": "^4.1.11", @@ -12902,27 +12882,27 @@ }, "xdg-basedir": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-3.0.0.tgz", + "resolved": false, "integrity": "sha1-SWsswQnsqNus/i3HK2A8F8WHCtQ=" }, "xtend": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", + "resolved": false, "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=" }, "y18n": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", + "resolved": false, "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==" }, "yallist": { "version": "3.0.3", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz", + "resolved": false, "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==" }, "yargs": { "version": "11.1.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-11.1.1.tgz", + "resolved": false, "integrity": "sha512-PRU7gJrJaXv3q3yQZ/+/X6KBswZiaQ+zOmdprZcouPYtQgvNU35i+68M4b1ZHLZtYFT5QObFLV+ZkmJYcwKdiw==", "requires": { "cliui": "^4.0.0", @@ -12941,14 +12921,14 @@ "dependencies": { "y18n": { "version": "3.2.1", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", + "resolved": false, "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=" } } }, "yargs-parser": { "version": "9.0.2", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-9.0.2.tgz", + "resolved": false, "integrity": "sha1-nM9qQ0YP5O1Aqbto9I1DuKaMwHc=", "requires": { "camelcase": "^4.1.0" diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index 421bf90c1..6949670d6 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -26,6 +26,7 @@ import { CollectionStackingViewFieldColumn } from "./CollectionStackingViewField import { CollectionSubView } from "./CollectionSubView"; import { CollectionViewType } from "./CollectionView"; import { SnappingManager } from "../../util/SnappingManager"; +import { CollectionFreeFormDocumentView } from "../nodes/CollectionFreeFormDocumentView"; const _global = (window /* browser */ || global /* node */) as any; type StackingDocument = makeInterface<[typeof collectionSchema, typeof documentSchema]>; @@ -191,8 +192,8 @@ export class CollectionStackingView extends CollectionSubView(StackingDocument) } getDisplayDoc(doc: Doc, dataDoc: Doc | undefined, dxf: () => Transform, width: () => number) { - const layoutDoc = Doc.Layout(doc, this.props.ChildLayoutTemplate?.()); const height = () => this.getDocHeight(doc); + const opacity = () => this.Document.currentTimecode === undefined ? this.props.childOpacity?.() : CollectionFreeFormDocumentView.getValues(doc, this.Document.currentTimecode || 0)?.opacity; return diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index b9d33da90..d0540e00f 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -92,7 +92,7 @@ export interface DocumentViewProps { pinToPres: (document: Doc) => void; backgroundHalo?: () => boolean; backgroundColor?: (doc: Doc) => string | undefined; - opacity?: () => number; + opacity?: () => number | undefined; ChromeHeight?: () => number; dontRegisterView?: boolean; layoutKey?: string; -- cgit v1.2.3-70-g09d2 From b8d0155f92947ea5b9c762f31ca353e7279b74e3 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Tue, 19 May 2020 15:50:09 -0400 Subject: switched bing to https --- src/client/views/collections/collectionFreeForm/MarqueeView.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/client/views/collections') diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index b2e6dad6b..e2ce70c7d 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -67,7 +67,7 @@ export class MarqueeView extends React.Component { - const textDoc = Docs.Create.WebDocument(`http://bing.com/search?q=${str}`, { + const textDoc = Docs.Create.WebDocument(`https://bing.com/search?q=${str}`, { _width: 200, x, y, _nativeHeight: 962, _nativeWidth: 800, isAnnotating: false, title: "bing" }); -- cgit v1.2.3-70-g09d2 From d430c5575e2ac8d38239687c8309248e6f7f712b Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Tue, 19 May 2020 20:33:50 -0400 Subject: added nav buttons to webbox. fixed drag/drop from bing (using UseCors) --- src/client/views/MainView.tsx | 9 +++- src/client/views/collections/CollectionSubView.tsx | 20 ++++---- .../collectionFreeForm/CollectionFreeFormView.tsx | 1 + .../collections/collectionFreeForm/MarqueeView.tsx | 3 +- src/client/views/nodes/WebBox.tsx | 59 +++++++++++++++++----- 5 files changed, 67 insertions(+), 25 deletions(-) (limited to 'src/client/views/collections') diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 1d6421656..50d445473 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -139,7 +139,10 @@ export class MainView extends React.Component { initEventListeners = () => { window.addEventListener("drop", (e) => { e.preventDefault(); }, false); // drop event handler - window.addEventListener("dragover", (e) => e.preventDefault(), false); // drag event handler + window.addEventListener("dragover", (e) => { + console.log("MDRAG"); + e.preventDefault(); + }, false); // drag event handler // click interactions for the context menu document.addEventListener("pointerdown", this.globalPointerDown); document.addEventListener("pointerup", this.globalPointerUp); @@ -310,7 +313,9 @@ export class MainView extends React.Component { const width = this.flyoutWidth; return {({ measureRef }) => -
+
{ + console.log("ENTERING"); + }} onDrop={this.onDrop} style={{ width: `calc(100% - ${width}px)` }}> {!mainContainer ? (null) : this.mainDocView}
} diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 673cce14f..208925b1c 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -330,7 +330,7 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T, moreProps?: let srcWeb: Doc | undefined; if (SelectionManager.SelectedDocuments().length) { srcWeb = SelectionManager.SelectedDocuments()[0].props.Document; - srcUrl = (srcWeb.data as WebField).url.href.match(/http[s]?:\/\/[^/]*/)?.[0]; + srcUrl = (srcWeb.data as WebField).url.href?.match(/http[s]?:\/\/[^/]*/)?.[0]; } let reg = new RegExp(Utils.prepend(""), "g"); const modHtml = srcUrl ? html.replace(reg, srcUrl) : html; @@ -339,14 +339,16 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T, moreProps?: this.props.addDocument(htmlDoc); if (srcWeb) { const focusNode = (SelectionManager.SelectedDocuments()[0].ContentDiv?.getElementsByTagName("iframe")[0].contentDocument?.getSelection()?.focusNode as any); - const rect = "getBoundingClientRect" in focusNode ? focusNode.getBoundingClientRect() : focusNode?.parentElement.getBoundingClientRect(); - const x = (rect?.x || 0); - const y = NumCast(srcWeb.scrollTop) + (rect?.y || 0); - const anchor = Docs.Create.FreeformDocument([], { _LODdisable: true, _backgroundColor: "transparent", _width: 25, _height: 25, x, y, annotationOn: srcWeb }); - anchor.context = srcWeb; - const key = Doc.LayoutFieldKey(srcWeb); - Doc.AddDocToList(srcWeb, key + "-annotations", anchor); - DocUtils.MakeLink({ doc: htmlDoc }, { doc: anchor }); + if (focusNode) { + const rect = "getBoundingClientRect" in focusNode ? focusNode.getBoundingClientRect() : focusNode?.parentElement.getBoundingClientRect(); + const x = (rect?.x || 0); + const y = NumCast(srcWeb.scrollTop) + (rect?.y || 0); + const anchor = Docs.Create.FreeformDocument([], { _LODdisable: true, _backgroundColor: "transparent", _width: 25, _height: 25, x, y, annotationOn: srcWeb }); + anchor.context = srcWeb; + const key = Doc.LayoutFieldKey(srcWeb); + Doc.AddDocToList(srcWeb, key + "-annotations", anchor); + DocUtils.MakeLink({ doc: htmlDoc }, { doc: anchor }); + } } } return; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index aeb0a5813..0751d749d 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1341,6 +1341,7 @@ export class CollectionFreeFormView extends CollectionSubView e.preventDefault() } onContextMenu={this.onContextMenu} style={{ pointerEvents: this.backgroundEvents ? "all" : undefined, diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index e2ce70c7d..0244dfc56 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -69,7 +69,7 @@ export class MarqueeView extends React.Component { const textDoc = Docs.Create.WebDocument(`https://bing.com/search?q=${str}`, { _width: 200, x, y, _nativeHeight: 962, _nativeWidth: 800, isAnnotating: false, - title: "bing" + title: "bing", UseCors: true }); this.props.addDocTab(textDoc, "onRight"); }); @@ -624,6 +624,7 @@ export class MarqueeView extends React.Component e.preventDefault()} onScroll={(e) => e.currentTarget.scrollTop = e.currentTarget.scrollLeft = 0} onClick={this.onClick} onPointerDown={this.onPointerDown}> {this._visible ? this.marqueeDiv : null} {this.props.children} diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index 8844702d7..63bdbdc5c 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -1,12 +1,12 @@ import { library } from "@fortawesome/fontawesome-svg-core"; import { faStickyNote, faPen, faMousePointer } from '@fortawesome/free-solid-svg-icons'; -import { action, computed, observable, trace, IReactionDisposer, reaction } from "mobx"; +import { action, computed, observable, trace, IReactionDisposer, reaction, runInAction } from "mobx"; import { observer } from "mobx-react"; import { Doc, FieldResult } from "../../../fields/Doc"; import { documentSchema } from "../../../fields/documentSchemas"; import { HtmlField } from "../../../fields/HtmlField"; import { InkTool } from "../../../fields/InkField"; -import { makeInterface } from "../../../fields/Schema"; +import { makeInterface, listSpec } from "../../../fields/Schema"; import { Cast, NumCast, BoolCast, StrCast } from "../../../fields/Types"; import { WebField } from "../../../fields/URLField"; import { Utils, returnOne, emptyFunction, returnZero } from "../../../Utils"; @@ -25,6 +25,7 @@ import { CollectionFreeFormView } from "../collections/collectionFreeForm/Collec import { ContextMenu } from "../ContextMenu"; import { ContextMenuProps } from "../ContextMenuItem"; import { undoBatch } from "../../util/UndoManager"; +import { List } from "../../../fields/List"; const htmlToText = require("html-to-text"); library.add(faStickyNote); @@ -79,8 +80,8 @@ export class WebBox extends ViewBoxAnnotatableComponent this._url = urlField?.url.toString() || ""); document.addEventListener("pointerup", this.onLongPressUp); document.addEventListener("pointermove", this.onLongPressMove); @@ -116,18 +117,44 @@ export class WebBox extends ViewBoxAnnotatableComponent { - if (!this._url.startsWith("http")) this._url = "http://" + this._url; - this.dataDoc[this.props.fieldKey] = new WebField(new URL(this._url)); + forward = () => { + const future = Cast(this.dataDoc[this.fieldKey + "-future"], listSpec("string"), null); + const history = Cast(this.dataDoc[this.fieldKey + "-history"], listSpec("string"), null); + if (future.length) { + history.push(this._url); + this.dataDoc[this.fieldKey] = new WebField(new URL(this._url = future.pop()!)); + } } @action - setURL() { - const urlField: FieldResult = Cast(this.dataDoc[this.props.fieldKey], WebField); - if (urlField) this._url = urlField.url.toString(); - else this._url = ""; + back = () => { + const future = Cast(this.dataDoc[this.fieldKey + "-future"], listSpec("string"), null); + const history = Cast(this.dataDoc[this.fieldKey + "-history"], listSpec("string"), null); + if (history.length) { + if (future === undefined) this.dataDoc[this.fieldKey + "-future"] = new List([this._url]); + else future.push(this._url); + this.dataDoc[this.fieldKey] = new WebField(new URL(this._url = history.pop()!)); + } } + @action + submitURL = () => { + if (!this._url.startsWith("http")) this._url = "http://" + this._url; + const future = Cast(this.dataDoc[this.fieldKey + "-future"], listSpec("string"), null); + const history = Cast(this.dataDoc[this.fieldKey + "-history"], listSpec("string"), null); + const url = Cast(this.dataDoc[this.fieldKey], WebField, null)?.url.toString(); + if (url) { + if (history === undefined) { + this.dataDoc[this.fieldKey + "-history"] = new List([url]); + } else { + history.push(url); + } + future && (future.length = 0); + } + this.dataDoc[this.fieldKey] = new WebField(new URL(this._url)); + } + + onValueKeyDown = async (e: React.KeyboardEvent) => { if (e.key === "Enter") { e.stopPropagation(); @@ -178,10 +205,16 @@ export class WebBox extends ViewBoxAnnotatableComponent + +
-- cgit v1.2.3-70-g09d2 From 0b1039b75af01836082f9bb4613e66c6218a6117 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Wed, 20 May 2020 00:35:18 -0400 Subject: added link drag drop onto webBox url --- .../collectionFreeForm/CollectionFreeFormView.tsx | 4 +- src/client/views/nodes/WebBox.tsx | 54 ++++++++++++++++------ src/server/server_Initialization.ts | 28 ++++++----- 3 files changed, 59 insertions(+), 27 deletions(-) (limited to 'src/client/views/collections') diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 0751d749d..c9b3519aa 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1341,7 +1341,9 @@ export class CollectionFreeFormView extends CollectionSubView e.preventDefault() } + onDragOver={e => { + e.preventDefault(); + }} onContextMenu={this.onContextMenu} style={{ pointerEvents: this.backgroundEvents ? "all" : undefined, diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index 63bdbdc5c..c1a585bca 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -116,6 +116,21 @@ export class WebBox extends ViewBoxAnnotatableComponent { + e.preventDefault(); + } + @action + onUrlDrop = (e: React.DragEvent) => { + const { dataTransfer } = e; + const html = dataTransfer.getData("text/html"); + const uri = dataTransfer.getData("text/uri-list"); + const url = uri || html || this._url; + this._url = url.startsWith(window.location.origin) ? + url.replace(window.location.origin, this._url.match(/http[s]?:\/\/[^\/]*/)?.[0] || "") : url; + this.submitURL(); + e.stopPropagation(); + } + @action forward = () => { const future = Cast(this.dataDoc[this.fieldKey + "-future"], listSpec("string"), null); @@ -140,21 +155,25 @@ export class WebBox extends ViewBoxAnnotatableComponent { if (!this._url.startsWith("http")) this._url = "http://" + this._url; - const future = Cast(this.dataDoc[this.fieldKey + "-future"], listSpec("string"), null); - const history = Cast(this.dataDoc[this.fieldKey + "-history"], listSpec("string"), null); - const url = Cast(this.dataDoc[this.fieldKey], WebField, null)?.url.toString(); - if (url) { - if (history === undefined) { - this.dataDoc[this.fieldKey + "-history"] = new List([url]); - } else { - history.push(url); + try { + const URLy = new URL(this._url); + const future = Cast(this.dataDoc[this.fieldKey + "-future"], listSpec("string"), null); + const history = Cast(this.dataDoc[this.fieldKey + "-history"], listSpec("string"), null); + const url = Cast(this.dataDoc[this.fieldKey], WebField, null)?.url.toString(); + if (url) { + if (history === undefined) { + this.dataDoc[this.fieldKey + "-history"] = new List([url]); + } else { + history.push(url); + } + future && (future.length = 0); } - future && (future.length = 0); + this.dataDoc[this.fieldKey] = new WebField(URLy); + } catch (e) { + console.log("Error in URL :" + this._url); } - this.dataDoc[this.fieldKey] = new WebField(new URL(this._url)); } - onValueKeyDown = async (e: React.KeyboardEvent) => { if (e.key === "Enter") { e.stopPropagation(); @@ -175,7 +194,9 @@ export class WebBox extends ViewBoxAnnotatableComponent +
-
+
@@ -198,6 +221,8 @@ export class WebBox extends ViewBoxAnnotatableComponent @@ -207,7 +232,8 @@ export class WebBox extends ViewBoxAnnotatableComponent - diff --git a/src/client/views/presentationview/PresElementBox.tsx b/src/client/views/presentationview/PresElementBox.tsx index 526a3dbf4..364c1d060 100644 --- a/src/client/views/presentationview/PresElementBox.tsx +++ b/src/client/views/presentationview/PresElementBox.tsx @@ -101,12 +101,11 @@ export class PresElementBox extends ViewBoxBaseComponent i && numberRange(i).forEach(f => Cast(d["opacity-indexed"], listSpec("number"), [])[f] = 0)); } /** diff --git a/src/fields/ScriptField.ts b/src/fields/ScriptField.ts index 503c60790..5192af407 100644 --- a/src/fields/ScriptField.ts +++ b/src/fields/ScriptField.ts @@ -65,14 +65,14 @@ export class ScriptField extends ObjectField { @serializable(autoObject()) private captures?: ProxyField; - constructor(script: CompiledScript, setterscript?: CompileResult) { + constructor(script: CompiledScript, setterscript?: CompiledScript) { super(); if (script?.options.capturedVariables) { const doc = Doc.assign(new Doc, script.options.capturedVariables); this.captures = new ProxyField(doc); } - this.setterscript = setterscript?.compiled ? setterscript : undefined; + this.setterscript = setterscript; this.script = script; } @@ -98,10 +98,10 @@ export class ScriptField extends ObjectField { // } [Copy](): ObjectField { - return new ScriptField(this.script); + return new ScriptField(this.script, this.setterscript); } toString() { - return `${this.script.originalScript}`; + return `${this.script.originalScript} + ${this.setterscript?.originalScript}`; } [ToScriptString]() { @@ -141,22 +141,21 @@ export class ComputedField extends ScriptField { [Copy](): ObjectField { - return new ComputedField(this.script); + return new ComputedField(this.script, this.setterscript); } public static MakeScript(script: string, params: object = {}) { const compiled = ScriptField.CompileScript(script, params, false); return compiled.compiled ? new ComputedField(compiled) : undefined; } - public static MakeFunction(script: string, params: object = {}, capturedVariables?: { [name: string]: Field }, setterScript?: string) { + public static MakeFunction(script: string, params: object = {}, capturedVariables?: { [name: string]: Field }) { const compiled = ScriptField.CompileScript(script, params, true, capturedVariables); - const setCompiled = setterScript ? ScriptField.CompileScript(setterScript, params, true, capturedVariables) : undefined; - return compiled.compiled ? new ComputedField(compiled, setCompiled?.compiled ? setCompiled : undefined) : undefined; + return compiled.compiled ? new ComputedField(compiled) : undefined; } public static MakeInterpolated(fieldKey: string, interpolatorKey: string) { const getField = ScriptField.CompileScript(`getIndexVal(self['${fieldKey}-indexed'], self.${interpolatorKey})`, {}, true, {}); const setField = ScriptField.CompileScript(`(self['${fieldKey}-indexed'])[self.${interpolatorKey}] = value`, { value: "any" }, true, {}); - return getField.compiled ? new ComputedField(getField, setField?.compiled ? setField : undefined) : undefined; + return getField.compiled && setField.compiled ? new ComputedField(getField, setField) : undefined; } } diff --git a/src/fields/util.ts b/src/fields/util.ts index a287b0210..024c0f80e 100644 --- a/src/fields/util.ts +++ b/src/fields/util.ts @@ -116,7 +116,7 @@ export function setter(target: any, in_prop: string | symbol | number, value: an return true; } } - if (target.__fields[prop] instanceof ComputedField && target.__fields[prop].setterscript) { + if (target.__fields[prop] instanceof ComputedField && target.__fields[prop].setterscript && value !== undefined && !(value instanceof ComputedField)) { return ScriptCast(target.__fields[prop])?.setterscript?.run({ self: target[SelfProxy], this: target[SelfProxy], value }).success ? true : false; } return _setter(target, prop, value, receiver); -- cgit v1.2.3-70-g09d2 From 2ba063ff94a04e89ee1fa1fde7d71a839f5d6856 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Sat, 23 May 2020 23:25:22 -0400 Subject: switched frame animations to use currentFrame and activeFrame to fix aliasing issue of progressive slides at different frame codes --- src/client/documents/Documents.ts | 2 ++ src/client/views/MainView.tsx | 6 +--- .../collectionFreeForm/CollectionFreeFormView.tsx | 41 +++++++++++----------- .../views/nodes/CollectionFreeFormDocumentView.tsx | 25 +++++++------ src/client/views/nodes/PresBox.tsx | 6 ++-- .../views/presentationview/PresElementBox.tsx | 2 +- src/fields/documentSchemas.ts | 6 ++-- 7 files changed, 46 insertions(+), 42 deletions(-) (limited to 'src/client/views/collections') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 6b17b4303..2be961108 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -126,6 +126,8 @@ export interface DocumentOptions { curPage?: number; currentTimecode?: number; // the current timecode of a time-based document (e.g., current time of a video) value is in seconds displayTimecode?: number; // the time that a document should be displayed (e.g., time an annotation should be displayed on a video) + currentFrame?: number; // the current frame of a frame-based collection (e.g., progressive slide) + activeFrame?: number; // the active frame of a document in a frame base collection borderRounding?: string; boxShadow?: string; dontRegisterChildViews?: boolean; diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index b7a75dfb9..358de2333 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -139,10 +139,7 @@ export class MainView extends React.Component { initEventListeners = () => { window.addEventListener("drop", (e) => { e.preventDefault(); }, false); // drop event handler - window.addEventListener("dragover", (e) => { - console.log("MDRAG"); - e.preventDefault(); - }, false); // drag 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); @@ -246,7 +243,6 @@ export class MainView extends React.Component { onDrop = (e: React.DragEvent) => { e.preventDefault(); e.stopPropagation(); - console.log("Drop"); } @action diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index d0415f77d..91e257f80 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -56,6 +56,7 @@ export const panZoomSchema = createSchema({ scale: "number", currentTimecode: "number", displayTimecode: "number", + currentFrame: "number", arrangeScript: ScriptField, arrangeInit: ScriptField, useClusters: "boolean", @@ -140,7 +141,7 @@ export class CollectionFreeFormView extends CollectionSubView { - const currentTimecode = this.Document.currentTimecode; - if (currentTimecode === undefined) { - this.Document.currentTimecode = 0; + const currentFrame = this.Document.currentFrame; + if (currentFrame === undefined) { + this.Document.currentFrame = 0; CollectionFreeFormDocumentView.setupKeyframes(this.childDocs, 0); } - CollectionFreeFormDocumentView.updateKeyframe(this.childDocs, currentTimecode || 0); - this.Document.currentTimecode = Math.max(0, (currentTimecode || 0) + 1); - this.Document.lastTimecode = Math.max(NumCast(this.Document.currentTimecode), NumCast(this.Document.lastTimecode)); + CollectionFreeFormDocumentView.updateKeyframe(this.childDocs, currentFrame || 0); + this.Document.currentFrame = Math.max(0, (currentFrame || 0) + 1); + this.Document.lastTimecode = Math.max(NumCast(this.Document.currentFrame), NumCast(this.Document.lastTimecode)); } @undoBatch @action prevKeyframe = (): void => { - const currentTimecode = this.Document.currentTimecode; - if (currentTimecode === undefined) { - this.Document.currentTimecode = 0; + const currentFrame = this.Document.currentFrame; + if (currentFrame === undefined) { + this.Document.currentFrame = 0; CollectionFreeFormDocumentView.setupKeyframes(this.childDocs, 0); } CollectionFreeFormDocumentView.gotoKeyframe(this.childDocs.slice()); - this.Document.currentTimecode = Math.max(0, (currentTimecode || 0) - 1); + this.Document.currentFrame = Math.max(0, (currentFrame || 0) - 1); } private selectDocuments = (docs: Doc[]) => { @@ -232,9 +233,9 @@ export class CollectionFreeFormView extends CollectionSubView
this.Document.editing = !this.Document.editing)} > - {NumCast(this.Document.currentTimecode)} + {NumCast(this.Document.currentFrame)}
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 88fbdd589..682aed8f5 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -69,21 +69,24 @@ export class CollectionFreeFormDocumentView extends DocComponent (i <= time && x !== undefined) || p === undefined ? x : p, undefined as any as number), - y: Cast(doc["y-indexed"], listSpec("number"), []).reduce((p, y, i) => (i <= time && y !== undefined) || p === undefined ? y : p, undefined as any as number), - opacity: Cast(doc["opacity-indexed"], listSpec("number"), []).reduce((p, o, i) => i <= time || p === undefined ? o : p, undefined as any as number), + x: Cast(doc["x-indexed"], listSpec("number"), []).reduce((p, x, i) => (i <= timecode && x !== undefined) || p === undefined ? x : p, undefined as any as number), + y: Cast(doc["y-indexed"], listSpec("number"), []).reduce((p, y, i) => (i <= timecode && y !== undefined) || p === undefined ? y : p, undefined as any as number), + opacity: Cast(doc["opacity-indexed"], listSpec("number"), []).reduce((p, o, i) => i <= timecode || p === undefined ? o : p, undefined as any as number), }); } - public static setValues(timecode: number, d: Doc, x?: number, y?: number, opacity?: number) { + public static setValues(time: number, d: Doc, x?: number, y?: number, opacity?: number) { + const timecode = Math.round(time); Cast(d["x-indexed"], listSpec("number"), [])[Math.max(0, timecode - 1)] = x as any as number; - Cast(d["y-indexed"], listSpec("number"), null)[Math.max(0, timecode - 1)] = y as any as number; + Cast(d["y-indexed"], listSpec("number"), [])[Math.max(0, timecode - 1)] = y as any as number; Cast(d["x-indexed"], listSpec("number"), [])[timecode] = x as any as number; - Cast(d["y-indexed"], listSpec("number"), null)[timecode] = y as any as number; + Cast(d["y-indexed"], listSpec("number"), [])[timecode] = y as any as number; Cast(d["opacity-indexed"], listSpec("number"), null)[timecode] = opacity as any as number; } - public static updateKeyframe(docs: Doc[], timecode: number) { + public static updateKeyframe(docs: Doc[], time: number) { + const timecode = Math.round(time); docs.forEach(doc => { const xindexed = Cast(doc['x-indexed'], listSpec("number"), null); const yindexed = Cast(doc['y-indexed'], listSpec("number"), null); @@ -112,10 +115,10 @@ export class CollectionFreeFormDocumentView extends DocComponent this.updateCurrentPresentation(); const presTargetDoc = Cast(this.childDocs[this.itemIndex].presentationTargetDoc, Doc, null); const lastFrame = Cast(presTargetDoc.lastTimecode, "number", null); - const curFrame = NumCast(presTargetDoc.currentTimecode); + const curFrame = NumCast(presTargetDoc.currentFrame); if (lastFrame !== undefined && curFrame < lastFrame) { - presTargetDoc.currentTimecode = curFrame + 1; + presTargetDoc.currentFrame = curFrame + 1; } else if (this.childDocs[this.itemIndex + 1] !== undefined) { let nextSelected = this.itemIndex + 1; @@ -200,7 +200,7 @@ export class PresBox extends ViewBoxBaseComponent this.rootDoc._itemIndex = index; const presTargetDoc = Cast(this.childDocs[this.itemIndex].presentationTargetDoc, Doc, null); if (presTargetDoc.lastTimecode !== undefined) { - presTargetDoc.currentTimecode = 0; + presTargetDoc.currentFrame = 0; } if (!this.layoutDoc.presStatus) { diff --git a/src/client/views/presentationview/PresElementBox.tsx b/src/client/views/presentationview/PresElementBox.tsx index 364c1d060..31ffde8af 100644 --- a/src/client/views/presentationview/PresElementBox.tsx +++ b/src/client/views/presentationview/PresElementBox.tsx @@ -102,7 +102,7 @@ export class PresElementBox extends ViewBoxBaseComponent Date: Sat, 23 May 2020 23:59:34 -0400 Subject: renamed lastTimecode to lastFrame --- src/client/documents/Documents.ts | 1 + .../views/collections/collectionFreeForm/CollectionFreeFormView.tsx | 2 +- src/client/views/nodes/PresBox.tsx | 4 ++-- src/client/views/presentationview/PresElementBox.tsx | 2 +- src/fields/documentSchemas.ts | 1 + 5 files changed, 6 insertions(+), 4 deletions(-) (limited to 'src/client/views/collections') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 2be961108..7f5b62f22 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -127,6 +127,7 @@ export interface DocumentOptions { currentTimecode?: number; // the current timecode of a time-based document (e.g., current time of a video) value is in seconds displayTimecode?: number; // the time that a document should be displayed (e.g., time an annotation should be displayed on a video) currentFrame?: number; // the current frame of a frame-based collection (e.g., progressive slide) + lastFrame?: number; // the last frame of a frame-based collection (e.g., progressive slide) activeFrame?: number; // the active frame of a document in a frame base collection borderRounding?: string; boxShadow?: string; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 91e257f80..4840bb7e7 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -171,7 +171,7 @@ export class CollectionFreeFormView extends CollectionSubView next = () => { this.updateCurrentPresentation(); const presTargetDoc = Cast(this.childDocs[this.itemIndex].presentationTargetDoc, Doc, null); - const lastFrame = Cast(presTargetDoc.lastTimecode, "number", null); + const lastFrame = Cast(presTargetDoc.lastFrame, "number", null); const curFrame = NumCast(presTargetDoc.currentFrame); if (lastFrame !== undefined && curFrame < lastFrame) { presTargetDoc.currentFrame = curFrame + 1; @@ -199,7 +199,7 @@ export class PresBox extends ViewBoxBaseComponent if (index >= 0 && index < this.childDocs.length) { this.rootDoc._itemIndex = index; const presTargetDoc = Cast(this.childDocs[this.itemIndex].presentationTargetDoc, Doc, null); - if (presTargetDoc.lastTimecode !== undefined) { + if (presTargetDoc.lastFrame !== undefined) { presTargetDoc.currentFrame = 0; } diff --git a/src/client/views/presentationview/PresElementBox.tsx b/src/client/views/presentationview/PresElementBox.tsx index 31ffde8af..475fef5b2 100644 --- a/src/client/views/presentationview/PresElementBox.tsx +++ b/src/client/views/presentationview/PresElementBox.tsx @@ -104,7 +104,7 @@ export class PresElementBox extends ViewBoxBaseComponent Date: Tue, 26 May 2020 03:26:01 -0400 Subject: upate activeFrame from currentTimecode --- src/client/views/collections/CollectionStackingView.tsx | 2 +- src/fields/documentSchemas.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src/client/views/collections') diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index 6949670d6..7fd19a23c 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -193,7 +193,7 @@ export class CollectionStackingView extends CollectionSubView(StackingDocument) getDisplayDoc(doc: Doc, dataDoc: Doc | undefined, dxf: () => Transform, width: () => number) { const height = () => this.getDocHeight(doc); - const opacity = () => this.Document.currentTimecode === undefined ? this.props.childOpacity?.() : CollectionFreeFormDocumentView.getValues(doc, this.Document.currentTimecode || 0)?.opacity; + const opacity = () => this.Document.currentFrame === undefined ? this.props.childOpacity?.() : CollectionFreeFormDocumentView.getValues(doc, NumCast(this.Document.currentFrame))?.opacity; return Date: Tue, 26 May 2020 05:12:40 -0400 Subject: restored change that was lost in earlier merge. --- src/client/views/collections/CollectionStackingView.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/client/views/collections') diff --git a/src/client/views/collections/CollectionStackingView.scss b/src/client/views/collections/CollectionStackingView.scss index ad595ec56..af208b683 100644 --- a/src/client/views/collections/CollectionStackingView.scss +++ b/src/client/views/collections/CollectionStackingView.scss @@ -31,7 +31,7 @@ } .collectionStackingViewFieldColumn { - height: 100%; + height: max-content; } .collectionSchemaView-previewDoc { -- cgit v1.2.3-70-g09d2 From 4a3fe3e00cde9c9afe798686367468d85606b972 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Tue, 26 May 2020 14:37:43 -0400 Subject: maded stackingViewFieldColumn targets fit available space on dragging --- src/client/views/collections/CollectionStackingView.scss | 3 +++ src/client/views/collections/CollectionStackingViewFieldColumn.tsx | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'src/client/views/collections') diff --git a/src/client/views/collections/CollectionStackingView.scss b/src/client/views/collections/CollectionStackingView.scss index af208b683..203c51163 100644 --- a/src/client/views/collections/CollectionStackingView.scss +++ b/src/client/views/collections/CollectionStackingView.scss @@ -33,6 +33,9 @@ .collectionStackingViewFieldColumn { height: max-content; } + .collectionStackingViewFieldColumnDragging { + height:100%; + } .collectionSchemaView-previewDoc { height: 100%; diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx index 53435ccc9..a269b21f5 100644 --- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx +++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx @@ -352,7 +352,7 @@ export class CollectionStackingViewFieldColumn extends React.Component Date: Thu, 28 May 2020 16:53:49 -0400 Subject: fixed pdf text selection --- package-lock.json | 84 +++++++++------------- package.json | 2 +- .../views/collections/CollectionTreeView.tsx | 2 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 8 +-- src/client/views/pdf/PDFViewer.scss | 4 ++ src/client/views/pdf/PDFViewer.tsx | 4 +- 6 files changed, 45 insertions(+), 59 deletions(-) (limited to 'src/client/views/collections') diff --git a/package-lock.json b/package-lock.json index 8b10d91f3..21e4c4e27 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2800,8 +2800,7 @@ }, "ansi-regex": { "version": "2.1.1", - "bundled": true, - "optional": true + "bundled": true }, "aproba": { "version": "1.2.0", @@ -2819,13 +2818,11 @@ }, "balanced-match": { "version": "1.0.0", - "bundled": true, - "optional": true + "bundled": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, - "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -2838,18 +2835,15 @@ }, "code-point-at": { "version": "1.1.0", - "bundled": true, - "optional": true + "bundled": true }, "concat-map": { "version": "0.0.1", - "bundled": true, - "optional": true + "bundled": true }, "console-control-strings": { "version": "1.1.0", - "bundled": true, - "optional": true + "bundled": true }, "core-util-is": { "version": "1.0.2", @@ -2952,8 +2946,7 @@ }, "inherits": { "version": "2.0.4", - "bundled": true, - "optional": true + "bundled": true }, "ini": { "version": "1.3.5", @@ -2963,7 +2956,6 @@ "is-fullwidth-code-point": { "version": "1.0.0", "bundled": true, - "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -2976,20 +2968,17 @@ "minimatch": { "version": "3.0.4", "bundled": true, - "optional": true, "requires": { "brace-expansion": "^1.1.7" } }, "minimist": { "version": "1.2.5", - "bundled": true, - "optional": true + "bundled": true }, "minipass": { "version": "2.9.0", "bundled": true, - "optional": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -3006,7 +2995,6 @@ "mkdirp": { "version": "0.5.3", "bundled": true, - "optional": true, "requires": { "minimist": "^1.2.5" } @@ -3062,8 +3050,7 @@ }, "npm-normalize-package-bin": { "version": "1.0.1", - "bundled": true, - "optional": true + "bundled": true }, "npm-packlist": { "version": "1.4.8", @@ -3088,8 +3075,7 @@ }, "number-is-nan": { "version": "1.0.1", - "bundled": true, - "optional": true + "bundled": true }, "object-assign": { "version": "4.1.1", @@ -3099,7 +3085,6 @@ "once": { "version": "1.4.0", "bundled": true, - "optional": true, "requires": { "wrappy": "1" } @@ -3168,8 +3153,7 @@ }, "safe-buffer": { "version": "5.1.2", - "bundled": true, - "optional": true + "bundled": true }, "safer-buffer": { "version": "2.1.2", @@ -3199,7 +3183,6 @@ "string-width": { "version": "1.0.2", "bundled": true, - "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -3217,7 +3200,6 @@ "strip-ansi": { "version": "3.0.1", "bundled": true, - "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -3256,13 +3238,11 @@ }, "wrappy": { "version": "1.0.2", - "bundled": true, - "optional": true + "bundled": true }, "yallist": { "version": "3.1.1", - "bundled": true, - "optional": true + "bundled": true } } } @@ -9456,7 +9436,7 @@ }, "chownr": { "version": "1.1.4", - "resolved": false, + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" }, "ci-info": { @@ -9762,7 +9742,7 @@ }, "deep-extend": { "version": "0.6.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==" }, "defaults": { @@ -10261,7 +10241,7 @@ }, "glob": { "version": "7.1.6", - "resolved": false, + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", "requires": { "fs.realpath": "^1.0.0", @@ -10349,7 +10329,7 @@ }, "hosted-git-info": { "version": "2.8.8", - "resolved": false, + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz", "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==" }, "http-cache-semantics": { @@ -10485,7 +10465,7 @@ }, "is-ci": { "version": "1.2.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-1.2.1.tgz", "integrity": "sha512-s6tfsaQaQi3JNciBH6shVqEDvhGut0SUXr31ag8Pd8BBbVVlcGfWhpPmEOoM6RJ5TFhbypvf5yyRw/VXW1IiWg==", "requires": { "ci-info": "^1.5.0" @@ -10561,7 +10541,7 @@ }, "is-retry-allowed": { "version": "1.2.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz", "integrity": "sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg==" }, "is-stream": { @@ -11070,7 +11050,7 @@ }, "mkdirp": { "version": "0.5.4", - "resolved": false, + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.4.tgz", "integrity": "sha512-iG9AK/dJLtJ0XNgTuDbSyNS3zECqDlAhnQW4CsNxBG3LQJBbHmRX1egw39DmtOdCAqY+dKXV+sgPgilNWUKMVw==", "requires": { "minimist": "^1.2.5" @@ -11078,7 +11058,7 @@ "dependencies": { "minimist": { "version": "1.2.5", - "resolved": false, + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" } } @@ -11130,7 +11110,7 @@ }, "node-gyp": { "version": "5.1.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-5.1.0.tgz", "integrity": "sha512-OUTryc5bt/P8zVgNUmC6xdXiDJxLMAW8cF5tLQOT9E5sOQj+UeQxnnPy74K3CLCa/SOjjBlbuzDLR8ANwA+wmw==", "requires": { "env-paths": "^2.2.0", @@ -11244,7 +11224,7 @@ }, "npm-packlist": { "version": "1.4.8", - "resolved": false, + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.8.tgz", "integrity": "sha512-5+AZgwru5IevF5ZdnFglB5wNlHG1AOOuw28WhUq8/8emhBmLv6jX5by4WJCh7lW0uSYZYS6DXqIsyZVIXRZU9A==", "requires": { "ignore-walk": "^3.0.1", @@ -11264,7 +11244,7 @@ }, "npm-profile": { "version": "4.0.4", - "resolved": false, + "resolved": "https://registry.npmjs.org/npm-profile/-/npm-profile-4.0.4.tgz", "integrity": "sha512-Ta8xq8TLMpqssF0H60BXS1A90iMoM6GeKwsmravJ6wYjWwSzcYBTdyWa3DZCYqPutacBMEm7cxiOkiIeCUAHDQ==", "requires": { "aproba": "^1.1.2 || 2", @@ -11274,7 +11254,7 @@ }, "npm-registry-fetch": { "version": "4.0.3", - "resolved": false, + "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-4.0.3.tgz", "integrity": "sha512-WGvUx0lkKFhu9MbiGFuT9nG2NpfQ+4dCJwRwwtK2HK5izJEvwDxMeUyqbuMS7N/OkpVCqDorV6rO5E4V9F8lJw==", "requires": { "JSONStream": "^1.3.4", @@ -11709,7 +11689,7 @@ }, "rc": { "version": "1.2.8", - "resolved": false, + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", "requires": { "deep-extend": "^0.6.0", @@ -11720,7 +11700,7 @@ "dependencies": { "minimist": { "version": "1.2.5", - "resolved": false, + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" } } @@ -11779,7 +11759,7 @@ }, "readable-stream": { "version": "3.6.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", "requires": { "inherits": "^2.0.3", @@ -11800,7 +11780,7 @@ }, "registry-auth-token": { "version": "3.4.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-3.4.0.tgz", "integrity": "sha512-4LM6Fw8eBQdwMYcES4yTnn2TqIasbXuwDx3um+QRs7S55aMKCBKBxvPXl2RiUjHwuJLTyYfxSpmfSAjQpcuP+A==", "requires": { "rc": "^1.1.6", @@ -11864,7 +11844,7 @@ }, "rimraf": { "version": "2.7.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", "requires": { "glob": "^7.1.3" @@ -12163,7 +12143,7 @@ }, "string_decoder": { "version": "1.3.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", "requires": { "safe-buffer": "~5.2.0" @@ -12171,7 +12151,7 @@ "dependencies": { "safe-buffer": { "version": "5.2.0", - "resolved": false, + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==" } } @@ -12483,7 +12463,7 @@ }, "widest-line": { "version": "2.0.1", - "resolved": false, + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-2.0.1.tgz", "integrity": "sha512-Ba5m9/Fa4Xt9eb2ELXt77JxVDV8w7qQrH0zS/TWSJdLyAwQjWoOzpzj5lwVftDz6n/EOu3tNACS84v509qwnJA==", "requires": { "string-width": "^2.1.1" diff --git a/package.json b/package.json index 8bf1e6b74..ca82d523d 100644 --- a/package.json +++ b/package.json @@ -228,4 +228,4 @@ "xoauth2": "^1.2.0", "xregexp": "^4.3.0" } -} \ No newline at end of file +} diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 3e99af724..87fe79e19 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -748,7 +748,7 @@ export class CollectionTreeView extends CollectionSubView (this.Document.scrollHeight || this.Document._nativeHeight || 0); panelHeight = () => this._pageSizes.length && this._pageSizes[0] ? this._pageSizes[0].width : (this.Document._nativeWidth || 0); @computed get overlayLayer() { - return
Date: Thu, 28 May 2020 18:43:14 -0400 Subject: added aimated transitions to presentations of frame animations --- .../collectionFreeForm/CollectionFreeFormView.tsx | 14 +++++++++++--- src/client/views/nodes/CollectionFreeFormDocumentView.tsx | 5 +++-- src/client/views/nodes/PresBox.tsx | 5 +++++ 3 files changed, 19 insertions(+), 5 deletions(-) (limited to 'src/client/views/collections') diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 9d10ff158..cb1228fed 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1350,8 +1350,14 @@ export class CollectionFreeFormView extends CollectionSubView - + {this.children} {this._timelineVisible ? : (null)} @@ -1445,6 +1451,7 @@ interface CollectionFreeFormViewPannableContentsProps { viewDefDivClick?: ScriptField; children: () => JSX.Element[]; shifted: boolean; + transition?: string; } @observer @@ -1459,7 +1466,8 @@ class CollectionFreeFormViewPannableContents extends React.Component {this.props.children()}
; diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 682aed8f5..697111ac8 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -96,12 +96,12 @@ export class CollectionFreeFormDocumentView extends DocComponent docs.forEach(doc => doc.transition = undefined), 1010); + setTimeout(() => docs.forEach(doc => doc.transition = "inherit"), 1010); } public static gotoKeyframe(docs: Doc[]) { docs.forEach(doc => doc.transition = "all 1s"); - setTimeout(() => docs.forEach(doc => doc.transition = undefined), 1010); + setTimeout(() => docs.forEach(doc => doc.transition = "inherit"), 1010); } public static setupKeyframes(docs: Doc[], timecode: number, progressivize: boolean = false) { @@ -119,6 +119,7 @@ export class CollectionFreeFormDocumentView extends DocComponent const lastFrame = Cast(presTargetDoc.lastFrame, "number", null); const curFrame = NumCast(presTargetDoc.currentFrame); if (lastFrame !== undefined && curFrame < lastFrame) { + //const docs = DocListCast(presTargetDoc[Doc.LayoutFieldKey(presTargetDoc)]); + presTargetDoc.transition = "all 1s"; + setTimeout(() => presTargetDoc.transition = undefined, 1010); + // docs.forEach(doc => doc.transition = "all 1s"); + // setTimeout(() => docs.forEach(doc => doc.transition = undefined), 1010); presTargetDoc.currentFrame = curFrame + 1; } else if (this.childDocs[this.itemIndex + 1] !== undefined) { -- cgit v1.2.3-70-g09d2 From 895e84fe6999a39eb9553db68b378aee5c1864a3 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Fri, 29 May 2020 01:29:02 -0400 Subject: moved frame animation into freeform chrome. fixed marquees of docs at non-zero frame. fixed pile view to use its own _pileLayoutEngine key to avoid leaving colleciton in an animated state. added toggle for snap linew views. cached transforms in CollectionFreeformView for performance. --- src/client/views/MainView.tsx | 6 +- .../views/collections/CollectionPileView.tsx | 8 +- .../views/collections/CollectionViewChromes.scss | 60 +++++- .../views/collections/CollectionViewChromes.tsx | 201 +++++++++++++-------- .../collectionFreeForm/CollectionFreeFormView.scss | 26 --- .../collectionFreeForm/CollectionFreeFormView.tsx | 68 +++---- .../collections/collectionFreeForm/MarqueeView.tsx | 12 +- src/client/views/nodes/DocumentView.tsx | 9 +- src/client/views/nodes/PresBox.tsx | 3 - 9 files changed, 223 insertions(+), 170 deletions(-) (limited to 'src/client/views/collections') diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 958ba0ce3..a0a6adab7 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -534,10 +534,10 @@ export class MainView extends React.Component { } @computed get snapLines() { - return
+ return !Doc.UserDoc().showSnapLines ? (null) :
- {/* {SnappingManager.horizSnapLines().map(l => )} - {SnappingManager.vertSnapLines().map(l => )} */} + {SnappingManager.horizSnapLines().map(l => )} + {SnappingManager.vertSnapLines().map(l => )}
; } diff --git a/src/client/views/collections/CollectionPileView.tsx b/src/client/views/collections/CollectionPileView.tsx index 020a87b2e..fc48e0327 100644 --- a/src/client/views/collections/CollectionPileView.tsx +++ b/src/client/views/collections/CollectionPileView.tsx @@ -23,7 +23,7 @@ export class CollectionPileView extends CollectionSubView(doc => doc) { @observable _childClickedScript: Opt; componentDidMount() { if (this.layoutEngine() !== "pass" && this.layoutEngine() !== "starburst") { - this.Document._layoutEngine = "pass"; + this.Document._pileLayoutEngine = "pass"; } this._originalChrome = StrCast(this.layoutDoc._chromeStatus); this.layoutDoc._chromeStatus = "disabled"; @@ -34,7 +34,7 @@ export class CollectionPileView extends CollectionSubView(doc => doc) { this.layoutDoc._chromeStatus = this._originalChrome; } - layoutEngine = () => StrCast(this.Document._layoutEngine); + layoutEngine = () => StrCast(this.Document._pileLayoutEngine); @computed get contents() { return
@@ -53,7 +53,7 @@ export class CollectionPileView extends CollectionSubView(doc => doc) { Doc.pileup(this.childDocs); this.layoutDoc._panX = 0; this.layoutDoc._panY = -10; - this.props.Document._layoutEngine = 'pass'; + this.props.Document._pileLayoutEngine = 'pass'; } else { const defaultSize = 25; this.layoutDoc._overflow = 'visible'; @@ -67,7 +67,7 @@ export class CollectionPileView extends CollectionSubView(doc => doc) { } this.layoutDoc._panX = this.layoutDoc._panY = 0; this.layoutDoc._width = this.layoutDoc._height = defaultSize; - this.props.Document._layoutEngine = 'starburst'; + this.props.Document._pileLayoutEngine = 'starburst'; } }); diff --git a/src/client/views/collections/CollectionViewChromes.scss b/src/client/views/collections/CollectionViewChromes.scss index e4581eb46..03bd9a01a 100644 --- a/src/client/views/collections/CollectionViewChromes.scss +++ b/src/client/views/collections/CollectionViewChromes.scss @@ -8,10 +8,12 @@ z-index: 9001; transition: top .5s; background: lightgrey; + transform-origin: top left; .collectionViewChrome { display: flex; - padding-bottom: 10px; + padding-bottom: 1px; + height:32px; border-bottom: .5px solid rgb(180, 180, 180); overflow: hidden; @@ -21,12 +23,12 @@ .collectionViewBaseChrome-viewPicker { font-size: 75%; //text-transform: uppercase; - letter-spacing: 2px; + //letter-spacing: 2px; background: rgb(238, 238, 238); color: grey; outline-color: black; border: none; - padding: 12px 10px 11px 10px; + //padding: 12px 10px 11px 10px; } .collectionViewBaseChrome-viewPicker:active { @@ -47,6 +49,7 @@ .collectionViewBaseChrome-cmdPicker { margin-left: 3px; margin-right: 0px; + font-size: 75%; background: rgb(238, 238, 238); border: none; color: grey; @@ -56,6 +59,7 @@ background-color: gray; display: flex; flex-direction: row; + height:30px; .commandEntry-drop { color:white; width:25px; @@ -95,8 +99,8 @@ margin: auto; background: gray; color: white; - width: 40px; - height: 40px; + width: 30px; + height: 30px; align-items: center; justify-content: center; } @@ -195,8 +199,7 @@ .collectionTreeViewChrome-pivotField-label { vertical-align: center; padding-left: 10px; - padding-top: 10px; - padding-bottom: 10px; + margin:auto; } .collectionStackingViewChrome-pivotField, @@ -204,14 +207,15 @@ color: white; width:100%; min-width: 100px; - text-align: center; + display: flex; + align-items: center; background: rgb(238, 238, 238); .editable-view-input, input, .editableView-container-editing-oneLine, .editableView-container-editing { - padding: 12px 10px 11px 10px; + margin:auto; border: 0px; color: grey; text-align: center; @@ -235,6 +239,44 @@ } } +.collectionFreeFormViewChrome-cont { + width: 60px; + display: flex; + position: relative; + align-items: center; + .fwdKeyframe, .numKeyframe, .backKeyframe { + cursor: pointer; + position: absolute; + width: 20; + height: 30; + bottom: 0; + background: gray; + display: flex; + align-items: center; + color:white; + } + .backKeyframe { + left:0; + svg { + display:block; + margin:auto; + } + } + .numKeyframe { + left:20; + display: flex; + flex-direction: column; + padding: 5px; + } + .fwdKeyframe { + left:40; + svg { + display:block; + margin:auto; + } + } +} + .collectionSchemaViewChrome-cont { display: flex; font-size: 10.5px; diff --git a/src/client/views/collections/CollectionViewChromes.tsx b/src/client/views/collections/CollectionViewChromes.tsx index 8c4d53d63..29a3e559a 100644 --- a/src/client/views/collections/CollectionViewChromes.tsx +++ b/src/client/views/collections/CollectionViewChromes.tsx @@ -15,6 +15,7 @@ import { COLLECTION_BORDER_WIDTH } from "../globalCssVariables.scss"; import { CollectionViewType } from "./CollectionView"; import { CollectionView } from "./CollectionView"; import "./CollectionViewChromes.scss"; +import { CollectionFreeFormDocumentView } from "../nodes/CollectionFreeFormDocumentView"; const datepicker = require('js-datepicker'); interface CollectionViewChromeProps { @@ -44,7 +45,7 @@ export class CollectionViewBaseChrome extends React.Component click clicked open view", + params: ["target", "source"], title: "=> child click view", script: "this.target.childClickedOpenTemplateView = getDocTemplate(this.source?.[0])", immediate: (source: Doc[]) => this.target.childClickedOpenTemplateView = Doc.getDocTemplate(source?.[0]), initialize: emptyFunction, @@ -83,22 +84,16 @@ export class CollectionViewBaseChrome extends React.Component(); @observable private _currentKey: string = ""; - componentDidMount = () => { - runInAction(() => { - // chrome status is one of disabled, collapsed, or visible. this determines initial state from document - const chromeStatus = this.props.CollectionView.props.Document._chromeStatus; - if (chromeStatus) { - if (chromeStatus === "disabled") { - throw new Error("how did you get here, if chrome status is 'disabled' on a collection, a chrome shouldn't even be instantiated!"); - } - else if (chromeStatus === "collapsed") { - if (this.props.collapse) { - this.props.collapse(true); - } - } - } - }); - } + componentDidMount = action(() => { + // chrome status is one of disabled, collapsed, or visible. this determines initial state from document + switch (this.props.CollectionView.props.Document._chromeStatus) { + case "disabled": + throw new Error("how did you get here, if chrome status is 'disabled' on a collection, a chrome shouldn't even be instantiated!"); + case "collapsed": + this.props.collapse?.(true); + break; + } + }) @undoBatch viewChanged = (e: React.ChangeEvent) => { @@ -197,10 +192,11 @@ export class CollectionViewBaseChrome extends React.Component { + @computed get subChrome() { const collapsed = this.document._chromeStatus !== "enabled"; if (collapsed) return null; switch (this.props.type) { + case CollectionViewType.Freeform: return (); case CollectionViewType.Stacking: return (); case CollectionViewType.Schema: return (); case CollectionViewType.Tree: return (); @@ -236,7 +232,7 @@ export class CollectionViewBaseChrome extends React.Component this.props.CollectionView.props.Document._viewType = Doc.getDocTemplate(source?.[0]), initialize: emptyFunction, }; @@ -254,14 +250,61 @@ export class CollectionViewBaseChrome extends React.Component +
+
+ +
+ +
+
; + } + + @computed get viewModes() { + const collapsed = this.props.CollectionView.props.Document._chromeStatus !== "enabled"; + return
+
+
+ +
+ +
+
; + } + render() { const collapsed = this.props.CollectionView.props.Document._chromeStatus !== "enabled"; + const scale = Math.min(1, this.props.CollectionView.props.ScreenToLocalTransform().Scale); return (
@@ -276,58 +319,71 @@ export class CollectionViewBaseChrome extends React.Component -
-
-
- -
- -
-
+ {this.viewModes}
-
-
-
- -
- -
-
+ {this.templateChrome}
- {this.subChrome()} + {this.subChrome}
); } } +@observer +export class CollectionFreeFormViewChrome extends React.Component { + + get Document() { return this.props.CollectionView.props.Document; } + @computed get dataField() { + return this.props.CollectionView.props.Document[Doc.LayoutFieldKey(this.props.CollectionView.props.Document)]; + } + @computed get childDocs() { + return DocListCast(this.dataField); + } + @undoBatch + @action + nextKeyframe = (): void => { + const currentFrame = NumCast(this.Document.currentFrame); + if (currentFrame === undefined) { + this.Document.currentFrame = 0; + CollectionFreeFormDocumentView.setupKeyframes(this.childDocs, 0); + } + CollectionFreeFormDocumentView.updateKeyframe(this.childDocs, currentFrame || 0); + this.Document.currentFrame = Math.max(0, (currentFrame || 0) + 1); + this.Document.lastFrame = Math.max(NumCast(this.Document.currentFrame), NumCast(this.Document.lastFrame)); + } + @undoBatch + @action + prevKeyframe = (): void => { + const currentFrame = NumCast(this.Document.currentFrame); + if (currentFrame === undefined) { + this.Document.currentFrame = 0; + CollectionFreeFormDocumentView.setupKeyframes(this.childDocs, 0); + } + CollectionFreeFormDocumentView.gotoKeyframe(this.childDocs.slice()); + this.Document.currentFrame = Math.max(0, (currentFrame || 0) - 1); + } + render() { + return this.Document.isAnnotationOverlay ? (null) : +
+
+ +
+
this.Document.editing = !this.Document.editing)} > + {NumCast(this.Document.currentFrame)} +
+
+ +
+
; + } +} + @observer export class CollectionStackingViewChrome extends React.Component { @observable private _currentKey: string = ""; @@ -474,19 +530,20 @@ export class CollectionSchemaViewChrome extends React.Component { - get dataExtension() { - return this.props.CollectionView.props.Document[this.props.CollectionView.props.fieldKey + "_ext"] as Doc; + get sortAscending() { + return this.props.CollectionView.props.Document[this.props.CollectionView.props.fieldKey + "-sortAscending"]; } - @computed private get descending() { - return this.dataExtension && Cast(this.dataExtension.sortAscending, "boolean", null); + set sortAscending(value) { + this.props.CollectionView.props.Document[this.props.CollectionView.props.fieldKey + "-sortAscending"] = value; + } + @computed private get ascending() { + return Cast(this.sortAscending, "boolean", null); } @action toggleSort = () => { - if (this.dataExtension) { - if (this.dataExtension.sortAscending) this.dataExtension.sortAscending = undefined; - else if (this.dataExtension.sortAscending === undefined) this.dataExtension.sortAscending = false; - else this.dataExtension.sortAscending = true; - } + if (this.sortAscending) this.sortAscending = undefined; + else if (this.sortAscending === undefined) this.sortAscending = false; + else this.sortAscending = true; } render() { @@ -496,7 +553,7 @@ export class CollectionTreeViewChrome extends React.Component Sort
-
+
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss index 5478a1c4a..d9011c9d3 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss @@ -41,32 +41,6 @@ // touch action none means that the browser will handle none of the touch actions. this allows us to implement our own actions. touch-action: none; - .fwdKeyframe, .numKeyframe, .backKeyframe{ - cursor: pointer; - position: absolute; - width: 20; - height:20; - bottom:0; - background:gray; - } - .backKeyframe { - right:45; - svg { - display:block; - margin:auto; - } - } - .numKeyframe { - right:25; - text-align:center; - } - .fwdKeyframe { - right:5; - svg { - display:block; - margin:auto; - } - } .collectionfreeformview-placeholder { background: gray; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index cb1228fed..c753a703d 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1,7 +1,7 @@ import { library } from "@fortawesome/fontawesome-svg-core"; import { faEye, faEyeSlash } from "@fortawesome/free-regular-svg-icons"; import { faBraille, faChalkboard, faCompass, faCompressArrowsAlt, faExpandArrowsAlt, faFileUpload, faPaintBrush, faTable, faUpload } from "@fortawesome/free-solid-svg-icons"; -import { action, computed, IReactionDisposer, observable, ObservableMap, reaction, runInAction, _allowStateChangesInsideComputed } from "mobx"; +import { action, computed, IReactionDisposer, observable, ObservableMap, reaction, runInAction, _allowStateChangesInsideComputed, trace } from "mobx"; import { observer } from "mobx-react"; import { computedFn } from "mobx-utils"; import { Doc, HeightSym, Opt, WidthSym, DocListCast } from "../../../../fields/Doc"; @@ -118,12 +118,28 @@ export class CollectionFreeFormView extends CollectionSubView !this.isAnnotationOverlay ? this.props.PanelWidth() / 2 / this.parentScaling / this.contentScaling : 0; // shift so pan position is at center of window for non-overlay collections - private centeringShiftY = () => !this.isAnnotationOverlay ? this.props.PanelHeight() / 2 / this.parentScaling / this.contentScaling : 0;// shift so pan position is at center of window for non-overlay collections - private getTransform = (): Transform => this.props.ScreenToLocalTransform().translate(-this.borderWidth + 1, -this.borderWidth + 1).translate(-this.centeringShiftX(), -this.centeringShiftY()).transform(this.getLocalTransform()); - private getTransformOverlay = (): Transform => this.props.ScreenToLocalTransform().translate(-this.borderWidth + 1, -this.borderWidth + 1); - private getContainerTransform = (): Transform => this.props.ScreenToLocalTransform().translate(-this.borderWidth, -this.borderWidth); - private getLocalTransform = (): Transform => Transform.Identity().scale(1 / this.zoomScaling()).translate(this.panX(), this.panY()); + @computed get cachedCenteringShiftX(): number { + return !this.isAnnotationOverlay ? this.props.PanelWidth() / 2 / this.parentScaling / this.contentScaling : 0; // shift so pan position is at center of window for non-overlay collections + } + @computed get cachedCenteringShiftY(): number { + return !this.isAnnotationOverlay ? this.props.PanelHeight() / 2 / this.parentScaling / this.contentScaling : 0;// shift so pan position is at center of window for non-overlay collections + } + @computed get cachedGetLocalTransform(): Transform { + return Transform.Identity().scale(1 / this.zoomScaling()).translate(this.panX(), this.panY()); + } + @computed get cachedGetContainerTransform(): Transform { + return this.props.ScreenToLocalTransform().translate(-this.borderWidth, -this.borderWidth); + } + @computed get cachedGetTransform(): Transform { + return this.getTransformOverlay().translate(- this.cachedCenteringShiftX, - this.cachedCenteringShiftY).transform(this.cachedGetLocalTransform); + } + + private centeringShiftX = () => this.cachedCenteringShiftX; + private centeringShiftY = () => this.cachedCenteringShiftY; + private getTransform = () => this.cachedGetTransform.copy(); + private getLocalTransform = () => this.cachedGetLocalTransform.copy(); + private getContainerTransform = () => this.cachedGetContainerTransform.copy(); + private getTransformOverlay = () => this.getContainerTransform().translate(1, 1); private addLiveTextBox = (newBox: Doc) => { FormattedTextBox.SelectOnLoad = newBox[Id];// track the new text box so we can give it a prop that tells it to focus itself when it's displayed this.addDocument(newBox); @@ -162,30 +178,6 @@ export class CollectionFreeFormView extends CollectionSubView { - const currentFrame = this.Document.currentFrame; - if (currentFrame === undefined) { - this.Document.currentFrame = 0; - CollectionFreeFormDocumentView.setupKeyframes(this.childDocs, 0); - } - CollectionFreeFormDocumentView.updateKeyframe(this.childDocs, currentFrame || 0); - this.Document.currentFrame = Math.max(0, (currentFrame || 0) + 1); - this.Document.lastFrame = Math.max(NumCast(this.Document.currentFrame), NumCast(this.Document.lastFrame)); - } - @undoBatch - @action - prevKeyframe = (): void => { - const currentFrame = this.Document.currentFrame; - if (currentFrame === undefined) { - this.Document.currentFrame = 0; - CollectionFreeFormDocumentView.setupKeyframes(this.childDocs, 0); - } - CollectionFreeFormDocumentView.gotoKeyframe(this.childDocs.slice()); - this.Document.currentFrame = Math.max(0, (currentFrame || 0) - 1); - } - private selectDocuments = (docs: Doc[]) => { SelectionManager.DeselectAll(); docs.map(doc => DocumentManager.Instance.getDocumentView(doc)).map(dv => dv && SelectionManager.SelectDoc(dv, true)); @@ -1219,6 +1211,7 @@ export class CollectionFreeFormView extends CollectionSubView { this.props.Document._panX = this.props.Document._panY = 0; this.props.Document.scale = 1; }, icon: "compress-arrows-alt" }); + optionItems.push({ description: "toggle snap line display", event: () => Doc.UserDoc().showSnapLines = !Doc.UserDoc().showSnapLines, icon: "compress-arrows-alt" }); optionItems.push({ description: "Reset default note style", event: () => Doc.UserDoc().defaultTextLayout = undefined, icon: "eye" }); optionItems.push({ description: (!this.layoutDoc._nativeWidth || !this.layoutDoc._nativeHeight ? "Freeze" : "Unfreeze") + " Aspect", event: this.toggleNativeDimensions, icon: "snowflake" }); optionItems.push({ description: `${this.fitToContent ? "Unset" : "Set"} Fit To Container`, event: () => this.Document._fitToBox = !this.fitToContent, icon: !this.fitToContent ? "expand-arrows-alt" : "compress-arrows-alt" }); @@ -1397,18 +1390,7 @@ export class CollectionFreeFormView extends CollectionSubView 0 ? this.placeholder : this.marqueeView} - {this.isAnnotationOverlay || !this.props.isSelected() || this.props.Document._viewType === CollectionViewType.Pile ? (null) : - <> -
- -
-
this.Document.editing = !this.Document.editing)} > - {NumCast(this.Document.currentFrame)} -
-
- -
- } +
{ - //this.props.removeDocument(d); - d.x = NumCast(d.x) - bounds.left - bounds.width / 2; - d.y = NumCast(d.y) - bounds.top - bounds.height / 2; - d.displayTimecode = undefined; // bcz: this should be automatic somehow.. along with any other properties that were logically associated with the original collection + const dx = NumCast(d.x); + const dy = NumCast(d.y); + delete d.x; + delete d.y; + delete d.activeFrame; + delete d.displayTimecode; // bcz: this should be automatic somehow.. along with any other properties that were logically associated with the original collection + d.x = dx - bounds.left - bounds.width / 2; + d.y = dy - bounds.top - bounds.height / 2; return d; })); this.props.removeDocument(selected); diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 00d19752f..2de7b3460 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -965,9 +965,6 @@ export class DocumentView extends DocComponent(Docu return this.isSelected(outsideReaction) || (this.props.Document.rootDocument && this.props.rootSelected?.(outsideReaction)) || false; } childScaling = () => (this.layoutDoc._fitWidth ? this.props.PanelWidth() / this.nativeWidth : this.props.ContentScaling()); - panelWidth = () => this.props.PanelWidth(); - panelHeight = () => this.props.PanelHeight(); - screenToLocalTransform = () => this.props.ScreenToLocalTransform(); @computed get contents() { TraceMobx(); return (<> @@ -988,10 +985,10 @@ export class DocumentView extends DocComponent(Docu addDocument={this.props.addDocument} removeDocument={this.props.removeDocument} moveDocument={this.props.moveDocument} - ScreenToLocalTransform={this.screenToLocalTransform} + ScreenToLocalTransform={this.props.ScreenToLocalTransform} renderDepth={this.props.renderDepth} - PanelWidth={this.panelWidth} - PanelHeight={this.panelHeight} + PanelWidth={this.props.PanelWidth} + PanelHeight={this.props.PanelHeight} ignoreAutoHeight={this.props.ignoreAutoHeight} focus={this.props.focus} parentActive={this.props.parentActive} diff --git a/src/client/views/nodes/PresBox.tsx b/src/client/views/nodes/PresBox.tsx index 56a543f46..9f1e99c77 100644 --- a/src/client/views/nodes/PresBox.tsx +++ b/src/client/views/nodes/PresBox.tsx @@ -62,11 +62,8 @@ export class PresBox extends ViewBoxBaseComponent const lastFrame = Cast(presTargetDoc.lastFrame, "number", null); const curFrame = NumCast(presTargetDoc.currentFrame); if (lastFrame !== undefined && curFrame < lastFrame) { - //const docs = DocListCast(presTargetDoc[Doc.LayoutFieldKey(presTargetDoc)]); presTargetDoc.transition = "all 1s"; setTimeout(() => presTargetDoc.transition = undefined, 1010); - // docs.forEach(doc => doc.transition = "all 1s"); - // setTimeout(() => docs.forEach(doc => doc.transition = undefined), 1010); presTargetDoc.currentFrame = curFrame + 1; } else if (this.childDocs[this.itemIndex + 1] !== undefined) { -- cgit v1.2.3-70-g09d2 From 5c4a948d506de2497d685f9ccba56ef6a855af1d Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Fri, 29 May 2020 21:52:00 -0400 Subject: added a version of client-side ACL's --- src/client/views/animationtimeline/Keyframe.tsx | 8 ++--- src/client/views/collections/CollectionView.tsx | 16 ++++++---- src/client/views/nodes/DocumentContentsView.tsx | 4 +-- src/client/views/nodes/DocumentView.tsx | 6 +++- src/fields/Doc.ts | 40 ++++++++++++++++++++++--- src/fields/util.ts | 10 +++++-- 6 files changed, 66 insertions(+), 18 deletions(-) (limited to 'src/client/views/collections') diff --git a/src/client/views/animationtimeline/Keyframe.tsx b/src/client/views/animationtimeline/Keyframe.tsx index e3274fb35..b562bd957 100644 --- a/src/client/views/animationtimeline/Keyframe.tsx +++ b/src/client/views/animationtimeline/Keyframe.tsx @@ -180,10 +180,10 @@ export class Keyframe extends React.Component { const fadeIn = this.props.makeKeyData(this.regiondata, this.regiondata.position + this.regiondata.fadeIn, KeyframeFunc.KeyframeType.fade); const fadeOut = this.props.makeKeyData(this.regiondata, this.regiondata.position + this.regiondata.duration - this.regiondata.fadeOut, KeyframeFunc.KeyframeType.fade); const finish = this.props.makeKeyData(this.regiondata, this.regiondata.position + this.regiondata.duration, KeyframeFunc.KeyframeType.end); - (fadeIn.key as Doc).opacity = 1; - (fadeOut.key as Doc).opacity = 1; - (start.key as Doc).opacity = 0.1; - (finish.key as Doc).opacity = 0.1; + (fadeIn as Doc).opacity = 1; + (fadeOut as Doc).opacity = 1; + (start as Doc).opacity = 0.1; + (finish as Doc).opacity = 0.1; this.forceUpdate(); //not needed, if setTimeout is gone... }, 1000); } diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index ee4755355..fecba32c5 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -8,7 +8,7 @@ import * as React from 'react'; import Lightbox from 'react-image-lightbox-with-rotate'; import 'react-image-lightbox-with-rotate/style.css'; // This only needs to be imported once in your app import { DateField } from '../../../fields/DateField'; -import { DataSym, Doc, DocListCast, Field, Opt } from '../../../fields/Doc'; +import { DataSym, Doc, DocListCast, Field, Opt, AclSym, AclAddonly, AclReadonly } from '../../../fields/Doc'; import { List } from '../../../fields/List'; import { BoolCast, Cast, NumCast, StrCast, ScriptCast } from '../../../fields/Types'; import { ImageField } from '../../../fields/URLField'; @@ -126,10 +126,16 @@ export class CollectionView extends Touchable !docList.includes(d)); if (added.length) { - added.map(doc => doc.context = this.props.Document); - added.map(add => Doc.AddDocToList(Cast(Doc.UserDoc().myCatalog, Doc, null), "data", add)); - targetDataDoc[this.props.fieldKey] = new List([...docList, ...added]); - targetDataDoc[this.props.fieldKey + "-lastModified"] = new DateField(new Date(Date.now())); + if (this.dataDoc[AclSym] === AclReadonly) { + return false; + } else if (this.dataDoc[AclSym] === AclAddonly) { + added.map(doc => Doc.AddDocToList(targetDataDoc, this.props.fieldKey, doc)); + } else { + added.map(doc => doc.context = this.props.Document); + added.map(add => Doc.AddDocToList(Cast(Doc.UserDoc().myCatalog, Doc, null), "data", add)); + targetDataDoc[this.props.fieldKey] = new List([...docList, ...added]); + targetDataDoc[this.props.fieldKey + "-lastModified"] = new DateField(new Date(Date.now())); + } } return true; } diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx index ef56e6fcd..126e9ac14 100644 --- a/src/client/views/nodes/DocumentContentsView.tsx +++ b/src/client/views/nodes/DocumentContentsView.tsx @@ -1,6 +1,6 @@ import { computed } from "mobx"; import { observer } from "mobx-react"; -import { Doc, Opt, Field } from "../../../fields/Doc"; +import { Doc, Opt, Field, AclSym, AclPrivate } from "../../../fields/Doc"; import { Cast, StrCast, NumCast } from "../../../fields/Types"; import { OmitKeys, Without, emptyPath } from "../../../Utils"; import DirectoryImportBox from "../../util/Import & Export/DirectoryImportBox"; @@ -185,7 +185,7 @@ export class DocumentContentsView extends React.Component 1 ? splits[0] + splits[1].replace(/{([^{}]|(?R))*}/, replacer4) : ""; // might have been more elegant if javascript supported recursive patterns - return (this.props.renderDepth > 12 || !layoutFrame || !this.layoutDoc) ? (null) : + return (this.props.renderDepth > 12 || !layoutFrame || !this.layoutDoc || this.layoutDoc[AclSym] === AclPrivate) ? (null) : (Docu const more = cm.findByDescription("More..."); const moreItems: ContextMenuProps[] = more && "subitems" in more ? more.subitems : []; + moreItems.push({ description: "Make Add Only", event: () => this.layoutDoc.ACL = this.dataDoc.ACL = "addOnly", icon: "concierge-bell" }); + moreItems.push({ description: "Make Read Only", event: () => this.layoutDoc.ACL = this.dataDoc.ACL = "readOnly", icon: "concierge-bell" }); + moreItems.push({ description: "Make Private", event: () => this.layoutDoc[AclSym] = this.dataDoc[AclSym] = "noAccess", icon: "concierge-bell" }); moreItems.push({ description: "Make View of Metadata Field", event: () => Doc.MakeMetadataFieldTemplate(this.props.Document, this.props.DataDoc), icon: "concierge-bell" }); moreItems.push({ description: `${this.Document._chromeStatus !== "disabled" ? "Hide" : "Show"} Chrome`, event: () => this.Document._chromeStatus = (this.Document._chromeStatus !== "disabled" ? "disabled" : "enabled"), icon: "project-diagram" }); moreItems.push({ description: this.Document.lockedPosition ? "Unlock Position" : "Lock Position", event: this.toggleLockPosition, icon: BoolCast(this.Document.lockedPosition) ? "unlock" : "lock" }); @@ -1119,6 +1122,7 @@ export class DocumentView extends DocComponent(Docu } render() { + if (this.props.Document[AclSym] && this.props.Document[AclSym] === AclPrivate) return (null); if (!(this.props.Document instanceof Doc)) return (null); const backgroundColor = Doc.UserDoc().renderStyle === "comic" ? undefined : StrCast(this.layoutDoc._backgroundColor) || StrCast(this.layoutDoc.backgroundColor) || StrCast(this.Document.backgroundColor) || this.props.backgroundColor?.(this.Document); const opacity = Cast(this.layoutDoc._opacity, "number", Cast(this.layoutDoc.opacity, "number", Cast(this.Document.opacity, "number", null))); diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts index 1ea686cbb..6891bf652 100644 --- a/src/fields/Doc.ts +++ b/src/fields/Doc.ts @@ -93,13 +93,40 @@ export const WidthSym = Symbol("Width"); export const HeightSym = Symbol("Height"); export const DataSym = Symbol("Data"); export const LayoutSym = Symbol("Layout"); +export const AclSym = Symbol("Acl"); +export const AclPrivate = Symbol("AclNoAccess"); +export const AclReadonly = Symbol("AclReadOnly"); +export const AclAddonly = Symbol("AclAddonly"); export const UpdatingFromServer = Symbol("UpdatingFromServer"); const CachedUpdates = Symbol("Cached updates"); function fetchProto(doc: Doc) { + if (doc.author !== Doc.CurrentUserEmail) { + if (doc.ACL === "noAccess") { + doc[AclSym] = AclPrivate; + return undefined; + } else if (doc.ACL === "readOnly") { + doc[AclSym] = AclReadonly; + } else if (doc.ACL === "addOnly") { + doc[AclSym] = AclAddonly; + } + } + const proto = doc.proto; if (proto instanceof Promise) { + proto.then(proto => { + if (proto.author !== Doc.CurrentUserEmail) { + if (proto.ACL === "noAccess") { + proto[AclSym] = doc[AclSym] = AclPrivate; + return undefined; + } else if (proto.ACL === "readOnly") { + proto[AclSym] = doc[AclSym] = AclReadonly; + } else if (proto.ACL === "addOnly") { + proto[AclSym] = doc[AclSym] = AclAddonly; + } + } + }); return proto; } } @@ -113,10 +140,10 @@ export class Doc extends RefField { set: setter, get: getter, // getPrototypeOf: (target) => Cast(target[SelfProxy].proto, Doc) || null, // TODO this might be able to replace the proto logic in getter - has: (target, key) => key in target.__fields, + has: (target, key) => target[AclSym] !== AclPrivate && key in target.__fields, ownKeys: target => { const obj = {} as any; - Object.assign(obj, target.___fields); + (target[AclSym] !== AclPrivate) && Object.assign(obj, target.___fields); runInAction(() => obj.__LAYOUT__ = target.__LAYOUT__); return Object.keys(obj); }, @@ -170,8 +197,11 @@ export class Doc extends RefField { private [Self] = this; private [SelfProxy]: any; + public [AclSym]: any = undefined; public [WidthSym] = () => NumCast(this[SelfProxy]._width); public [HeightSym] = () => NumCast(this[SelfProxy]._height); + public [ToScriptString]() { return `DOC-"${this[Self][Id]}"-`; } + public [ToString]() { return `Doc(${this[AclSym] === AclPrivate ? "-inaccessible-" : this.title})`; } public get [LayoutSym]() { return this[SelfProxy].__LAYOUT__; } public get [DataSym]() { const self = this[SelfProxy]; @@ -193,8 +223,6 @@ export class Doc extends RefField { return undefined; } - [ToScriptString]() { return `DOC-"${this[Self][Id]}"-`; } - [ToString]() { return `Doc(${this.title})`; } private [CachedUpdates]: { [key: string]: () => void | Promise } = {}; public static CurrentUserEmail: string = ""; @@ -794,6 +822,7 @@ export namespace Doc { } // don't bother memoizing (caching) the result if called from a non-reactive context. (plus this avoids a warning message) export function IsBrushedDegreeUnmemoized(doc: Doc) { + if (!doc || doc[AclSym] === AclPrivate || Doc.GetProto(doc)[AclSym] === AclPrivate) return 0; return brushManager.BrushedDoc.has(doc) ? 2 : brushManager.BrushedDoc.has(Doc.GetProto(doc)) ? 1 : 0; } export function IsBrushedDegree(doc: Doc) { @@ -802,11 +831,13 @@ export namespace Doc { })(doc); } export function BrushDoc(doc: Doc) { + if (!doc || doc[AclSym] === AclPrivate || Doc.GetProto(doc)[AclSym] === AclPrivate) return doc; brushManager.BrushedDoc.set(doc, true); brushManager.BrushedDoc.set(Doc.GetProto(doc), true); return doc; } export function UnBrushDoc(doc: Doc) { + if (!doc || doc[AclSym] === AclPrivate || Doc.GetProto(doc)[AclSym] === AclPrivate) return doc; brushManager.BrushedDoc.delete(doc); brushManager.BrushedDoc.delete(Doc.GetProto(doc)); return doc; @@ -836,6 +867,7 @@ export namespace Doc { } const highlightManager = new HighlightBrush(); export function IsHighlighted(doc: Doc) { + if (!doc || doc[AclSym] === AclPrivate || Doc.GetProto(doc)[AclSym] === AclPrivate) return false; return highlightManager.HighlightedDoc.get(doc) || highlightManager.HighlightedDoc.get(Doc.GetProto(doc)); } export function HighlightDoc(doc: Doc, dataAndDisplayDocs = true) { diff --git a/src/fields/util.ts b/src/fields/util.ts index 024c0f80e..54e7eca28 100644 --- a/src/fields/util.ts +++ b/src/fields/util.ts @@ -1,5 +1,5 @@ import { UndoManager } from "../client/util/UndoManager"; -import { Doc, Field, FieldResult, UpdatingFromServer, LayoutSym } from "./Doc"; +import { Doc, Field, FieldResult, UpdatingFromServer, LayoutSym, AclSym, AclPrivate } from "./Doc"; import { SerializationHelper } from "../client/util/SerializationHelper"; import { ProxyField, PrefetchProxy } from "./Proxy"; import { RefField } from "./RefField"; @@ -106,6 +106,7 @@ const layoutProps = ["panX", "panY", "width", "height", "nativeWidth", "nativeHe "LODdisable", "chromeStatus", "viewType", "gridGap", "xMargin", "yMargin", "autoHeight"]; export function setter(target: any, in_prop: string | symbol | number, value: any, receiver: any): boolean { let prop = in_prop; + if (target[AclSym]) return true; if (typeof prop === "string" && prop !== "__id" && prop !== "__fields" && (prop.startsWith("_") || layoutProps.includes(prop))) { if (!prop.startsWith("_")) { console.log(prop + " is deprecated - switch to _" + prop); @@ -124,6 +125,8 @@ export function setter(target: any, in_prop: string | symbol | number, value: an export function getter(target: any, in_prop: string | symbol | number, receiver: any): any { let prop = in_prop; + if (in_prop === AclSym) return target[AclSym]; + if (target[AclSym] === AclPrivate) return undefined; if (prop === LayoutSym) { return target.__LAYOUT__; } @@ -148,6 +151,9 @@ export function getter(target: any, in_prop: string | symbol | number, receiver: function getFieldImpl(target: any, prop: string | number, receiver: any, ignoreProto: boolean = false): any { receiver = receiver || target[SelfProxy]; + if (target === undefined) { + console.log(""); + } let field = target.__fields[prop]; for (const plugin of getterPlugins) { const res = plugin(receiver, prop, field); @@ -160,7 +166,7 @@ function getFieldImpl(target: any, prop: string | number, receiver: any, ignoreP } if (field === undefined && !ignoreProto && prop !== "proto") { const proto = getFieldImpl(target, "proto", receiver, true);//TODO tfs: instead of receiver we could use target[SelfProxy]... I don't which semantics we want or if it really matters - if (proto instanceof Doc) { + if (proto instanceof Doc && proto[AclSym] !== AclPrivate) { return getFieldImpl(proto[Self], prop, receiver, ignoreProto); } return undefined; -- cgit v1.2.3-70-g09d2 From 1681c03a0509c2e8989fe268e7997dbe912770ec Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Sat, 30 May 2020 15:42:07 -0700 Subject: buxton pdf linking implementation --- src/client/documents/Documents.ts | 25 +++++-- .../views/collections/CollectionTreeView.tsx | 7 +- src/scraping/buxton/final/BuxtonImporter.ts | 74 +++++++++++++++++---- .../buxton/final/assets/pdfs/3DCad_Brochure.pdf | Bin 0 -> 107790 bytes 4 files changed, 82 insertions(+), 24 deletions(-) create mode 100644 src/scraping/buxton/final/assets/pdfs/3DCad_Brochure.pdf (limited to 'src/client/views/collections') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 7f5b62f22..f7e19eecd 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -432,17 +432,28 @@ export namespace Docs { parentProto.data = new List(); } if (device) { - const { __images } = device; + const { title, __images, additionalMedia } = device; delete device.__images; + delete device.additionalMedia; const { ImageDocument, StackingDocument } = Docs.Create; const constructed = __images.map(({ url, nativeWidth, nativeHeight }) => ({ url: Utils.prepend(url), nativeWidth, nativeHeight })); - const deviceImages = constructed.map(({ url, nativeWidth, nativeHeight }, i) => ImageDocument(url, { - title: `image${i}.${extname(url)}`, - _nativeWidth: nativeWidth, - _nativeHeight: nativeHeight - })); + const deviceImages = constructed.map(({ url, nativeWidth, nativeHeight }, i) => { + const imageDoc = ImageDocument(url, { + title: `image${i}.${extname(url)}`, + _nativeWidth: nativeWidth, + _nativeHeight: nativeHeight + }); + const media = additionalMedia[i]; + if (media) { + for (const key of Object.keys(media)) { + imageDoc[`additionalMedia_${key}`] = Utils.prepend(`/files/${key}/buxton/${media[key]}`); + } + } + return imageDoc; + }); // the main document we create - const doc = StackingDocument(deviceImages, { title: device.title, _LODdisable: true, hero: new ImageField(constructed[0].url) }); + const doc = StackingDocument(deviceImages, { title, _LODdisable: true, hero: new ImageField(constructed[0].url) }); + doc.nameAliases = new List([title.toLowerCase()]); // add the parsed attributes to this main document Docs.Get.FromJson({ data: device, appendToExisting: { targetDoc: Doc.GetProto(doc) } }); Doc.AddDocToList(parentProto, "data", doc); diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 87fe79e19..4d67b1e2c 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -717,7 +717,7 @@ export class CollectionTreeView extends CollectionSubView { - const { ImageDocument } = Docs.Create; + const { ImageDocument, PdfDocument } = Docs.Create; const { Document } = this.props; const fallbackImg = "http://www.cs.brown.edu/~bcz/face.gif"; const detailView = Cast(Cast(Doc.UserDoc()["template-button-detail"], Doc, null)?.dragFactory, Doc, null); @@ -726,13 +726,14 @@ export class CollectionTreeView extends CollectionSubView { DocListCast(d.data).map((img, i) => { const caption = (d.captions as any)[i]; if (caption) { Doc.GetProto(img).caption = caption; - Doc.GetProto(img).doubleClickView = doubleClickView; + Doc.GetProto(img).doubleClickView = (pdfContent = StrCast(img.additionalMedia_pdfs)) ? PdfDocument(pdfContent) : fallback; } }); Doc.GetProto(d).type = "buxton"; diff --git a/src/scraping/buxton/final/BuxtonImporter.ts b/src/scraping/buxton/final/BuxtonImporter.ts index e55850b29..684c00c0d 100644 --- a/src/scraping/buxton/final/BuxtonImporter.ts +++ b/src/scraping/buxton/final/BuxtonImporter.ts @@ -1,4 +1,4 @@ -import { readdirSync, writeFile, mkdirSync } from "fs"; +import { readdirSync, writeFile, mkdirSync, createReadStream, createWriteStream, existsSync, statSync } from "fs"; import * as path from "path"; import { red, cyan, yellow } from "colors"; import { Utils } from "../../../Utils"; @@ -9,6 +9,7 @@ const createImageSizeStream = require("image-size-stream"); import { parseXml } from "libxmljs"; import { strictEqual } from "assert"; import { Readable, PassThrough } from "stream"; +import { Directory, serverPathToFile, pathToDirectory } from "../../../server/ApiManagers/UploadManager"; /** * This is an arbitrary bundle of data that gets populated @@ -18,8 +19,7 @@ interface DocumentContents { body: string; imageData: ImageData[]; hyperlinks: string[]; - captions: string[]; - embeddedFileNames: string[]; + tableData: TableData[]; longDescription: string; } @@ -40,6 +40,7 @@ export interface DeviceDocument { secondaryKey: string; attribute: string; __images: ImageData[]; + additionalMedia: ({ [type: string]: string } | undefined)[]; hyperlinks: string[]; captions: string[]; // from the table column embeddedFileNames: string[]; // from the table column @@ -255,6 +256,8 @@ const FormatMap = new Map>([ ]); const sourceDir = path.resolve(__dirname, "source"); // where the Word documents are assumed to be stored +const assetDir = path.resolve(__dirname, "assets"); // where any additional media content like pdfs will be stored. Each subdirectory of this +// must follow the enum Directory. naming scheme const outDir = path.resolve(__dirname, "json"); // where the JSON output of these device documents will be written const imageDir = path.resolve(__dirname, "../../../server/public/files/images/buxton"); // where, in the server, these images will be written const successOut = "buxton.json"; // the JSON list representing properly formatted documents @@ -277,18 +280,45 @@ export default async function executeImport(emitter: ResultCallback, terminator: rimraf.sync(dir); mkdirSync(dir); }); + await transferAssets(); return parseFiles(wordDocuments, emitter, terminator); } catch (e) { const message = [ "Unable to find a source directory.", - "Please ensure that the following directory exists and is populated with Word documents:", - `${sourceDir}` + "Please ensure that the following directory exists:", + `${e.message}` ].join('\n'); console.log(red(message)); return { error: message }; } } +/** + * Builds a mirrored directory structure of all media / asset files + * within the server's public directory. + */ +async function transferAssets() { + for (const assetType of readdirSync(assetDir)) { + const subroot = path.resolve(assetDir, assetType); + if (!statSync(subroot).isDirectory()) { + continue; + } + const outputSubroot = serverPathToFile(assetType as Directory, "buxton"); + if (existsSync(outputSubroot)) { + continue; + } else { + mkdirSync(outputSubroot); + } + for (const fileName of readdirSync(subroot)) { + const readStream = createReadStream(path.resolve(subroot, fileName)); + const writeStream = createWriteStream(path.resolve(outputSubroot, fileName)); + await new Promise(resolve => { + readStream.pipe(writeStream).on("close", resolve); + }); + } + } +} + /** * Parse every Word document in the directory, notifying any callers as needed * at each iteration via the emitter. @@ -356,6 +386,16 @@ const xPaths = { hyperlinks: '//*[name()="Relationship" and contains(@Type, "hyperlink")]' }; +interface TableData { + fileName: string; + caption: string; + additionalMedia?: { [type: string]: string }; +} + +const SuffixDirectoryMap = new Map([ + ["p", Directory.pdfs] +]); + /** * The meat of the script, images and text content are extracted here * @param pathToDocument the path to the document relative to the root of the zip @@ -370,8 +410,7 @@ async function extractFileContents(pathToDocument: string): Promise Utilities.correctSentences(node.text()).transformed!); @@ -382,7 +421,7 @@ async function extractFileContents(pathToDocument: string): Promise node.text().trim()); const { length } = tableRowsFlattened; - const numCols = 3; + const numCols = 4; strictEqual(length > numCols, true, "No captions written."); // first row has the headers, not content strictEqual(length % numCols === 0, true, "Improper caption formatting."); @@ -392,8 +431,14 @@ async function extractFileContents(pathToDocument: string): Promise { * @param contents the data already computed / parsed by extractFileContents */ function analyze(fileName: string, contents: DocumentContents): AnalysisResult { - const { body, imageData, captions, hyperlinks, embeddedFileNames, longDescription } = contents; + const { body, imageData, hyperlinks, tableData, longDescription } = contents; const device: any = { hyperlinks, - captions, - embeddedFileNames, + captions: tableData.map(({ caption }) => caption), + embeddedFileNames: tableData.map(({ fileName }) => fileName), + additionalMedia: tableData.map(({ additionalMedia }) => additionalMedia), longDescription, __images: imageData }; diff --git a/src/scraping/buxton/final/assets/pdfs/3DCad_Brochure.pdf b/src/scraping/buxton/final/assets/pdfs/3DCad_Brochure.pdf new file mode 100644 index 000000000..4746d2f41 Binary files /dev/null and b/src/scraping/buxton/final/assets/pdfs/3DCad_Brochure.pdf differ -- cgit v1.2.3-70-g09d2 From 85721c9ed95b4c026d0a1c7891e1fee311e9f50e Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Sat, 30 May 2020 17:11:23 -0700 Subject: buxton pdf fix --- .../views/collections/CollectionTreeView.tsx | 2 +- src/client/views/pdf/PDFViewer.tsx | 14 ++++++- src/server/ApiManagers/PDFManager.ts | 43 +++++++++++----------- 3 files changed, 34 insertions(+), 25 deletions(-) (limited to 'src/client/views/collections') diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 4d67b1e2c..b2e1c0f73 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -733,7 +733,7 @@ export class CollectionTreeView extends CollectionSubView this._showWaiting = this._showCover = true); this.props.startupLive && this.setupPdfJsViewer(); this._searchReactionDisposer = reaction(() => this.Document.searchMatch, search => { diff --git a/src/server/ApiManagers/PDFManager.ts b/src/server/ApiManagers/PDFManager.ts index 0136b758e..d2a9e9cce 100644 --- a/src/server/ApiManagers/PDFManager.ts +++ b/src/server/ApiManagers/PDFManager.ts @@ -7,54 +7,54 @@ import { createCanvas } from "canvas"; const imageSize = require("probe-image-size"); import * as express from "express"; import * as path from "path"; -import { Directory, serverPathToFile, clientPathToFile } from "./UploadManager"; +import { Directory, serverPathToFile, clientPathToFile, pathToDirectory } from "./UploadManager"; import { red } from "colors"; +import { resolve } from "path"; export default class PDFManager extends ApiManager { protected initialize(register: Registration): void { register({ - method: Method.GET, - subscription: new RouteSubscriber("thumbnail").add("filename"), - secureHandler: ({ req, res }) => getOrCreateThumbnail(req.params.filename, res) + method: Method.POST, + subscription: new RouteSubscriber("thumbnail"), + secureHandler: async ({ req, res }) => { + const { coreFilename, pageNum, subtree } = req.body; + return getOrCreateThumbnail(coreFilename, pageNum, res, subtree); + } }); } } -async function getOrCreateThumbnail(thumbnailName: string, res: express.Response): Promise { - const noExtension = thumbnailName.substring(0, thumbnailName.length - ".png".length); - const pageString = noExtension.split('-')[1]; - const pageNumber = parseInt(pageString); +async function getOrCreateThumbnail(coreFilename: string, pageNum: number, res: express.Response, subtree?: string): Promise { + const resolved = `${coreFilename}-${pageNum}.png`; return new Promise(async resolve => { - const path = serverPathToFile(Directory.pdf_thumbnails, thumbnailName); + const path = serverPathToFile(Directory.pdf_thumbnails, resolved); if (existsSync(path)) { const existingThumbnail = createReadStream(path); const { err, viewport } = await new Promise(resolve => { imageSize(existingThumbnail, (err: any, viewport: any) => resolve({ err, viewport })); }); if (err) { - console.log(red(`In PDF thumbnail response, unable to determine dimensions of ${thumbnailName}:`)); + console.log(red(`In PDF thumbnail response, unable to determine dimensions of ${resolved}:`)); console.log(err); return; } - dispatchThumbnail(res, viewport, thumbnailName); + dispatchThumbnail(res, viewport, resolved); } else { - const offset = thumbnailName.length - pageString.length - 5; - const name = thumbnailName.substring(0, offset) + ".pdf"; - const path = serverPathToFile(Directory.pdfs, name); - await CreateThumbnail(path, pageNumber, res); + await CreateThumbnail(coreFilename, pageNum, res, subtree); } resolve(); }); } -async function CreateThumbnail(file: string, pageNumber: number, res: express.Response) { - const documentProxy = await Pdfjs.getDocument(file).promise; +async function CreateThumbnail(coreFilename: string, pageNum: number, res: express.Response, subtree?: string) { + const sourcePath = resolve(pathToDirectory(Directory.pdfs), `${subtree ?? ""}${coreFilename}.pdf`); + const documentProxy = await Pdfjs.getDocument(sourcePath).promise; const factory = new NodeCanvasFactory(); - const page = await documentProxy.getPage(pageNumber); + const page = await documentProxy.getPage(pageNum); const viewport = page.getViewport(1 as any); const { canvas, context } = factory.create(viewport.width, viewport.height); const renderContext = { @@ -64,14 +64,13 @@ async function CreateThumbnail(file: string, pageNumber: number, res: express.Re }; await page.render(renderContext).promise; const pngStream = canvas.createPNGStream(); - const filenames = path.basename(file).split("."); - const thumbnailName = `${filenames[0]}-${pageNumber}.png`; - const pngFile = serverPathToFile(Directory.pdf_thumbnails, thumbnailName); + const resolved = `${coreFilename}-${pageNum}.png`; + const pngFile = serverPathToFile(Directory.pdf_thumbnails, resolved); const out = createWriteStream(pngFile); pngStream.pipe(out); return new Promise((resolve, reject) => { out.on("finish", () => { - dispatchThumbnail(res, viewport, thumbnailName); + dispatchThumbnail(res, viewport, resolved); resolve(); }); out.on("error", error => { -- cgit v1.2.3-70-g09d2