From e6c1c5f08bf706023335936bebf463184650a6c2 Mon Sep 17 00:00:00 2001 From: bob Date: Tue, 4 Feb 2020 12:26:25 -0500 Subject: fixes for shift-clicking pivot view. --- src/client/views/nodes/DocumentView.tsx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 0f517197a..09bf06e1b 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -50,6 +50,7 @@ import { RadialMenuProps } from './RadialMenuItem'; import { CollectionStackingView } from '../collections/CollectionStackingView'; import { RichTextField } from '../../../new_fields/RichTextField'; +import { HistoryUtil } from '../../util/History'; library.add(fa.faEdit, fa.faTrash, fa.faShare, fa.faDownload, fa.faExpandArrowsAlt, fa.faCompressArrowsAlt, fa.faLayerGroup, fa.faExternalLinkAlt, fa.faAlignCenter, fa.faCaretSquareRight, fa.faSquare, fa.faConciergeBell, fa.faWindowRestore, fa.faFolder, fa.faMapPin, fa.faLink, fa.faFingerprint, fa.faCrosshairs, fa.faDesktop, fa.faUnlock, fa.faLock, fa.faLaptopCode, fa.faMale, @@ -253,7 +254,7 @@ export class DocumentView extends DocComponent(Docu } } - onClick = async (e: React.MouseEvent | React.PointerEvent) => { + onClick = undoBatch((e: React.MouseEvent | React.PointerEvent) => { if (!e.nativeEvent.cancelBubble && !this.Document.ignoreClick && CurrentUserUtils.MainDocId !== this.props.Document[Id] && (Math.abs(e.clientX - this._downX) < Utils.DRAG_THRESHOLD && Math.abs(e.clientY - this._downY) < Utils.DRAG_THRESHOLD)) { e.stopPropagation(); @@ -267,7 +268,7 @@ export class DocumentView extends DocComponent(Docu SelectionManager.DeselectAll(); Doc.UnBrushDoc(this.props.Document); } else if (this.onClickHandler && this.onClickHandler.script) { - this.onClickHandler.script.run({ this: this.Document.isTemplateForField && this.props.DataDoc ? this.props.DataDoc : this.props.Document, containingCollection: this.props.ContainingCollectionDoc }, console.log); + this.onClickHandler.script.run({ this: this.Document.isTemplateForField && this.props.DataDoc ? this.props.DataDoc : this.props.Document, containingCollection: this.props.ContainingCollectionDoc, shiftKey: e.shiftKey }, console.log); } else if (this.Document.type === DocumentType.BUTTON) { ScriptBox.EditButtonScript("On Button Clicked ...", this.props.Document, "onClick", e.clientX, e.clientY); } else if (this.props.Document.isButton === "Selector") { // this should be moved to an OnClick script @@ -282,7 +283,7 @@ export class DocumentView extends DocComponent(Docu } preventDefault && e.preventDefault(); } - } + }) buttonClick = async (altKey: boolean, ctrlKey: boolean) => { const maximizedDocs = await DocListCastAsync(this.Document.maximizedDocs); -- cgit v1.2.3-70-g09d2 From 6f43b2643b117748c6b9896f40b581eeec1ffe06 Mon Sep 17 00:00:00 2001 From: bob Date: Tue, 4 Feb 2020 18:30:52 -0500 Subject: small tweaks to templates... --- src/client/util/RichTextRules.ts | 20 ++++++++++++-------- src/client/views/nodes/DocumentView.tsx | 2 +- src/new_fields/Doc.ts | 4 ++-- 3 files changed, 15 insertions(+), 11 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/util/RichTextRules.ts b/src/client/util/RichTextRules.ts index 77b111412..3b30b5b3f 100644 --- a/src/client/util/RichTextRules.ts +++ b/src/client/util/RichTextRules.ts @@ -79,13 +79,16 @@ export const inpRules = { const fieldKey = match[1]; const docid = match[2]?.substring(1); if (!fieldKey) { - DocServer.GetRefField(docid).then(docx => { - const target = ((docx instanceof Doc) && docx) || Docs.Create.FreeformDocument([], { title: docid, _width: 500, _height: 500, _LODdisable: true, }, docid); - DocUtils.Publish(target, docid, returnFalse, returnFalse); - DocUtils.MakeLink({ doc: (schema as any).Document }, { doc: target }, "portal link", ""); - }); - const link = state.schema.marks.link.create({ href: Utils.prepend("/doc/" + docid), location: "onRight", title: docid, targetId: docid }); - return state.tr.deleteRange(end - 1, end).deleteRange(start, start + 2).addMark(start, end - 3, link); + if (docid) { + DocServer.GetRefField(docid).then(docx => { + const target = ((docx instanceof Doc) && docx) || Docs.Create.FreeformDocument([], { title: docid, _width: 500, _height: 500, _LODdisable: true, }, docid); + DocUtils.Publish(target, docid, returnFalse, returnFalse); + DocUtils.MakeLink({ doc: (schema as any).Document }, { doc: target }, "portal link", ""); + }); + const link = state.schema.marks.link.create({ href: Utils.prepend("/doc/" + docid), location: "onRight", title: docid, targetId: docid }); + return state.tr.deleteRange(end - 1, end).deleteRange(start, start + 2).addMark(start, end - 3, link); + } + return state.tr; } const fieldView = state.schema.nodes.dashField.create({ fieldKey, docid }); return state.tr.deleteRange(start, end).insert(start, fieldView); @@ -96,7 +99,8 @@ export const inpRules = { (state, match, start, end) => { const fieldKey = match[1]; const docid = match[2]?.substring(1); - DocServer.GetRefField(docid).then(docx => { + if (!fieldKey && !docid) return state.tr; + docid && DocServer.GetRefField(docid).then(docx => { if (!(docx instanceof Doc && docx)) { const docx = Docs.Create.FreeformDocument([], { title: docid, _width: 500, _height: 500, _LODdisable: true }, docid); DocUtils.Publish(docx, docid, returnFalse, returnFalse); diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 09bf06e1b..d768dd7cf 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -665,7 +665,7 @@ export class DocumentView extends DocComponent(Docu } }) DocumentView. - makeCustomViewClicked(this.props.Document, this.props.DataDoc, Docs.Create.StackingDocument, layout, foundLayout); + makeCustomViewClicked(this.props.Document, this.props.DataDoc, Docs.Create.StackingDocument, layout, foundLayout && Doc.MakeDelegate(foundLayout)); } else { DocumentView.makeNativeViewClicked(this.props.Document, StrCast(this.props.Document.layoutKey).split("_")[1]); } diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index 4dcdc6581..3f2335702 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -481,7 +481,7 @@ export namespace Doc { // 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) { - const resolvedDataDoc = containerDataDoc === containerDoc || !containerDataDoc ? undefined : containerDataDoc; + const resolvedDataDoc = containerDataDoc === containerDoc || !containerDataDoc || (!childDoc.isTemplateDoc && !childDoc.isTemplateForField) ? undefined : containerDataDoc; return { layout: Doc.expandTemplateLayout(childDoc, resolvedDataDoc), data: resolvedDataDoc }; } export function CreateDocumentExtensionForField(doc: Doc, fieldKey: string) { @@ -568,7 +568,7 @@ export namespace Doc { let _applyCount: number = 0; export function ApplyTemplate(templateDoc: Doc) { if (templateDoc) { - const applied = ApplyTemplateTo(templateDoc, Doc.MakeDelegate(new Doc()), "layoutCustom", templateDoc.title + "(..." + _applyCount++ + ")"); + const applied = ApplyTemplateTo(Doc.MakeDelegate(templateDoc), Doc.MakeDelegate(new Doc()), "layout", templateDoc.title + "(..." + _applyCount++ + ")"); applied && (Doc.GetProto(applied).layout = applied.layout); return applied; } -- cgit v1.2.3-70-g09d2 From da92903fb49b2c7d34bb44f11bf72a6cd49b8c0d Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Tue, 4 Feb 2020 23:52:40 -0500 Subject: lots of small fixes to templates, presentations, default templates (icon, slide) --- src/client/views/MainView.tsx | 2 +- src/client/views/OverlayView.tsx | 2 +- .../views/collections/CollectionTimeView.tsx | 10 ++++---- .../CollectionMulticolumnView.scss | 1 + .../CollectionMulticolumnView.tsx | 13 ++++++---- .../CollectionMultirowView.scss | 1 + .../CollectionMultirowView.tsx | 12 ++++++---- src/client/views/nodes/DocumentView.tsx | 28 ++++++++++------------ src/client/views/nodes/PresBox.scss | 2 +- src/client/views/nodes/PresBox.tsx | 8 +++++-- .../views/presentationview/PresElementBox.tsx | 2 +- src/new_fields/Doc.ts | 16 +++++++++---- .../authentication/models/current_user_utils.ts | 20 +++++++++++++++- 13 files changed, 78 insertions(+), 39 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 87a81504c..0cc374cee 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 { - faArrowDown, faBullseye, faFilter, faArrowUp, faBolt, faCaretUp, faCat, faCheck, faChevronRight, faClone, faCloudUploadAlt, faCommentAlt, faCut, faEllipsisV, faExclamation, faFilePdf, faFilm, faFont, faGlobeAsia, faLongArrowAltRight, + faStickyNote, faArrowDown, faBullseye, faFilter, faArrowUp, faBolt, faCaretUp, faCat, faCheck, faChevronRight, faClone, faCloudUploadAlt, faCommentAlt, faCut, faEllipsisV, faExclamation, faFilePdf, faFilm, faFont, faGlobeAsia, faLongArrowAltRight, faMusic, faObjectGroup, faPause, faMousePointer, faPenNib, faFileAudio, faPen, faEraser, faPlay, faPortrait, faRedoAlt, faThumbtack, faTree, faTv, faUndoAlt, faHighlighter, faMicrophone, faCompressArrowsAlt, faPhone, faStamp, faClipboard } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; diff --git a/src/client/views/OverlayView.tsx b/src/client/views/OverlayView.tsx index 295cd7c6e..7a99bf0ae 100644 --- a/src/client/views/OverlayView.tsx +++ b/src/client/views/OverlayView.tsx @@ -144,7 +144,7 @@ export class OverlayView extends React.Component { return (null); } return CurrentUserUtils.UserDocument.overlays instanceof Doc && DocListCast(CurrentUserUtils.UserDocument.overlays.data).map(d => { - d.inOverlay = true; + setTimeout(() => d.inOverlay = true, 0); let offsetx = 0, offsety = 0; const onPointerMove = action((e: PointerEvent) => { if (e.buttons === 1) { diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx index f999067d3..264423d72 100644 --- a/src/client/views/collections/CollectionTimeView.tsx +++ b/src/client/views/collections/CollectionTimeView.tsx @@ -46,6 +46,7 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) { @computed get _allFacets() { const facets = new Set(); this.childDocs.forEach(child => Object.keys(Doc.GetProto(child)).forEach(key => facets.add(key))); + Doc.AreProtosEqual(this.dataDoc, this.props.Document) && this.childDocs.forEach(child => Object.keys(child).forEach(key => facets.add(key))); return facets.toArray(); } @@ -108,11 +109,10 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) { const docItems: ContextMenuProps[] = []; const keySet: Set = new Set(); - this.childLayoutPairs.map(pair => - Array.from(Object.keys(Doc.GetProto(pair.layout))).filter(fieldKey => - pair.layout[fieldKey] instanceof RichTextField || - typeof (pair.layout[fieldKey]) === "number" || - typeof (pair.layout[fieldKey]) === "string").map(fieldKey => keySet.add(fieldKey))); + this.childLayoutPairs.map(pair => this._allFacets.filter(fieldKey => + pair.layout[fieldKey] instanceof RichTextField || + typeof (pair.layout[fieldKey]) === "number" || + typeof (pair.layout[fieldKey]) === "string").map(fieldKey => keySet.add(fieldKey))); keySet.toArray().map(fieldKey => docItems.push({ description: ":" + fieldKey, event: () => this.props.Document.pivotField = fieldKey, icon: "compress-arrows-alt" })); docItems.push({ description: ":(null)", event: () => this.props.Document.pivotField = undefined, icon: "compress-arrows-alt" }) diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.scss b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.scss index f57ba438a..a5d5617bc 100644 --- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.scss +++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.scss @@ -7,6 +7,7 @@ .document-wrapper { display: flex; flex-direction: column; + width: 100%; .label-wrapper { display: flex; diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx index cbe064ec0..56f777f43 100644 --- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx +++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx @@ -224,10 +224,11 @@ export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocu Document={layout} DataDocument={layout.resolvedDataDoc as Doc} CollectionDoc={this.props.Document} - PanelWidth={() => this.lookupPixels(layout)} - PanelHeight={() => PanelHeight() - (BoolCast(Document.showWidthLabels) ? 20 : 0)} - getTransform={() => this.lookupIndividualTransform(layout)} + PanelWidth={() => this.lookupPixels(layout) - 2 * NumCast(Document._xMargin)} + PanelHeight={() => PanelHeight() - 2 * NumCast(Document._yMargin) - (BoolCast(Document.showWidthLabels) ? 20 : 0)} + getTransform={() => this.lookupIndividualTransform(layout).translate(-NumCast(Document._xMargin), -NumCast(Document._yMargin))} onClick={this.onChildClickHandler} + renderDepth={this.props.renderDepth + 1} /> +
{this.contents}
); diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.scss b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.scss index ef4b4a19c..ed737ea59 100644 --- a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.scss +++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.scss @@ -8,6 +8,7 @@ .document-wrapper { display: flex; flex-direction: row; + height: 100%; .label-wrapper { display: flex; diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx index 434bf14ff..8a2498458 100644 --- a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx +++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx @@ -224,9 +224,9 @@ export class CollectionMultirowView extends CollectionSubView(MultirowDocument) Document={layout} DataDocument={layout.resolvedDataDoc as Doc} CollectionDoc={this.props.Document} - PanelHeight={() => this.lookupPixels(layout)} - PanelWidth={() => PanelWidth() - (BoolCast(Document.showHeightLabels) ? 20 : 0)} - getTransform={() => this.lookupIndividualTransform(layout)} + PanelHeight={() => this.lookupPixels(layout) - 2 * NumCast(Document._yMargin)} + PanelWidth={() => PanelWidth() - 2 * NumCast(Document._xMargin) - (BoolCast(Document.showHeightLabels) ? 20 : 0)} + getTransform={() => this.lookupIndividualTransform(layout).translate(-NumCast(Document._xMargin), -NumCast(Document._yMargin))} onClick={this.onChildClickHandler} renderDepth={this.props.renderDepth + 1} /> @@ -250,7 +250,11 @@ export class CollectionMultirowView extends CollectionSubView(MultirowDocument) render(): JSX.Element { return ( -
+
{this.contents}
); diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index d768dd7cf..c14d11cce 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -111,7 +111,7 @@ export class DocumentView extends DocComponent(Docu @computed get topMost() { return this.props.renderDepth === 0; } @computed get nativeWidth() { return this.layoutDoc._nativeWidth || 0; } @computed get nativeHeight() { return this.layoutDoc._nativeHeight || 0; } - @computed get onClickHandler() { return this.props.onClick ? this.props.onClick : this.Document.onClick; } + @computed get onClickHandler() { return this.props.onClick || this.layoutDoc.onClick || this.Document.onClick; } @computed get onPointerDownHandler() { return this.props.onPointerDown ? this.props.onPointerDown : this.Document.onPointerDown; } @computed get onPointerUpHandler() { return this.props.onPointerUp ? this.props.onPointerUp : this.Document.onPointerUp; } @@ -520,11 +520,8 @@ export class DocumentView extends DocComponent(Docu @undoBatch deleteClicked = (): void => { SelectionManager.DeselectAll(); this.props.removeDocument && this.props.removeDocument(this.props.Document); } - static makeNativeViewClicked = (doc: Doc, prevLayout: string) => { - undoBatch(() => { - if (StrCast(doc.title).endsWith("_" + prevLayout)) doc.title = StrCast(doc.title).replace("_" + prevLayout, ""); - doc.layoutKey = "layout"; - })(); + static makeNativeViewClicked = (doc: Doc) => { + undoBatch(() => Doc.setNativeView(doc))(); } static makeCustomViewClicked = (doc: Doc, dataDoc: Opt, creator: (documents: Array, options: DocumentOptions, id?: string) => Doc, name: string = "custom", docLayoutTemplate?: Doc) => { @@ -653,21 +650,22 @@ export class DocumentView extends DocComponent(Docu @action setCustomView = (custom: boolean, layout: string): void => { - if (this.props.ContainingCollectionView?.props.DataDoc || this.props.ContainingCollectionView?.props.Document.isTemplateDoc) { - Doc.MakeMetadataFieldTemplate(this.props.Document, this.props.ContainingCollectionView.props.Document); - } else if (custom) { - DocumentView.makeNativeViewClicked(this.props.Document, StrCast(this.props.Document.layoutKey).split("_")[1]); - - let foundLayout: Opt = undefined; - DocListCast(Cast(CurrentUserUtils.UserDocument.expandingButtons, Doc, null)?.data)?.map(btnDoc => { + // if (this.props.ContainingCollectionView?.props.DataDoc || this.props.ContainingCollectionView?.props.Document.isTemplateDoc) { + // Doc.MakeMetadataFieldTemplate(this.props.Document, this.props.ContainingCollectionView.props.Document); + // } else + if (custom) { + DocumentView.makeNativeViewClicked(this.props.Document); + + let foundLayout: Opt = Cast(Doc.UserDoc().iconView, Doc, null); + !foundLayout && DocListCast(Cast(CurrentUserUtils.UserDocument.expandingButtons, Doc, null)?.data)?.map(btnDoc => { if (StrCast(Cast(btnDoc?.dragFactory, Doc, null)?.title) === layout) { foundLayout = btnDoc.dragFactory as Doc; } }) DocumentView. - makeCustomViewClicked(this.props.Document, this.props.DataDoc, Docs.Create.StackingDocument, layout, foundLayout && Doc.MakeDelegate(foundLayout)); + makeCustomViewClicked(this.props.Document, this.props.DataDoc, Docs.Create.StackingDocument, layout, foundLayout); } else { - DocumentView.makeNativeViewClicked(this.props.Document, StrCast(this.props.Document.layoutKey).split("_")[1]); + DocumentView.makeNativeViewClicked(this.props.Document); } } diff --git a/src/client/views/nodes/PresBox.scss b/src/client/views/nodes/PresBox.scss index 01e7f4834..3e1967a18 100644 --- a/src/client/views/nodes/PresBox.scss +++ b/src/client/views/nodes/PresBox.scss @@ -6,7 +6,7 @@ top: 0; bottom: 0; width: 100%; - min-width: 100px; + min-width: 120px; height: 100%; min-height: 50px; letter-spacing: 2px; diff --git a/src/client/views/nodes/PresBox.tsx b/src/client/views/nodes/PresBox.tsx index 06d8e688b..44411fa30 100644 --- a/src/client/views/nodes/PresBox.tsx +++ b/src/client/views/nodes/PresBox.tsx @@ -6,7 +6,6 @@ import { action, computed, IReactionDisposer, reaction } from "mobx"; import { observer } from "mobx-react"; import { Doc, DocListCast, DocListCastAsync } from "../../../new_fields/Doc"; import { listSpec } from "../../../new_fields/Schema"; -import { ComputedField } from "../../../new_fields/ScriptField"; import { Cast, FieldValue, NumCast } from "../../../new_fields/Types"; import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils"; import { Docs } from "../../documents/Documents"; @@ -17,7 +16,6 @@ import { CollectionView, CollectionViewType } from "../collections/CollectionVie import { ContextMenu } from "../ContextMenu"; import { FieldView, FieldViewProps } from './FieldView'; import "./PresBox.scss"; -import { presSchema } from "../presentationview/PresElementBox"; library.add(faArrowLeft); library.add(faArrowRight); @@ -31,6 +29,7 @@ library.add(faEdit); @observer export class PresBox extends React.Component { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(PresBox, fieldKey); } + _childReaction: IReactionDisposer | undefined; componentDidMount() { const userDoc = CurrentUserUtils.UserDocument; let presTemp = Cast(userDoc.presentationTemplate, Doc); @@ -43,6 +42,11 @@ export class PresBox extends React.Component { else { this.props.Document.childLayout = presTemp; } + this._childReaction = reaction(() => this.childDocs.slice(), + (children) => children.forEach((child, i) => child.presentationIndex = i), { fireImmediately: true }); + } + componentWillUnmount() { + this._childReaction?.(); } @computed get childDocs() { return DocListCast(this.props.Document[this.props.fieldKey]); } diff --git a/src/client/views/presentationview/PresElementBox.tsx b/src/client/views/presentationview/PresElementBox.tsx index dcc5247d5..ea3acf75c 100644 --- a/src/client/views/presentationview/PresElementBox.tsx +++ b/src/client/views/presentationview/PresElementBox.tsx @@ -50,7 +50,7 @@ export class PresElementBox extends DocExtendableComponent d instanceof Doc && MakeMetadataFieldTemplate(d, templateDoc)); (Doc.GetProto(templateField)[metadataFieldKey] = ObjectField.MakeCopy(templateField.data)); } - if (templateField.data instanceof RichTextField && templateField.data.Text) { + if (templateField.data instanceof RichTextField && (templateField.data.Text || templateField.data.Data.toString().includes("dashField"))) { templateField._textTemplate = ComputedField.MakeFunction(`copyField(this.${metadataFieldKey})`, { this: Doc.name }); } @@ -780,6 +781,12 @@ export namespace Doc { const fieldStr = Field.toString(fieldVal as Field); return fieldStr === value; } + + export function setNativeView(doc: any) { + const prevLayout = StrCast(doc.layoutKey).split("_")[1]; + if (StrCast(doc.title).endsWith("_" + prevLayout)) doc.title = StrCast(doc.title).replace("_" + prevLayout, ""); + doc.layoutKey = "layout"; + } } Scripting.addGlobal(function renameAlias(doc: any, n: any) { return StrCast(Doc.GetProto(doc).title).replace(/\([0-9]*\)/, "") + `(${n})`; }); @@ -792,6 +799,7 @@ Scripting.addGlobal(function copyField(field: any) { return ObjectField.MakeCopy Scripting.addGlobal(function aliasDocs(field: any) { return new List(field.map((d: any) => Doc.MakeAlias(d))); }); Scripting.addGlobal(function docList(field: any) { return DocListCast(field); }); Scripting.addGlobal(function sameDocs(doc1: any, doc2: any) { return Doc.AreProtosEqual(doc1, doc2); }); +Scripting.addGlobal(function setNativeView(doc: any) { Doc.setNativeView(doc); }); Scripting.addGlobal(function undo() { return UndoManager.Undo(); }); Scripting.addGlobal(function redo() { return UndoManager.Redo(); }); Scripting.addGlobal(function selectDoc(doc: any) { Doc.UserDoc().SelectedDocs = new List([doc]); }); diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts index 6bfc729de..f2c3aab35 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -15,6 +15,8 @@ import { nullAudio } from "../../../new_fields/URLField"; import { DragManager } from "../../../client/util/DragManager"; import { InkingControl } from "../../../client/views/InkingControl"; import { CollectionViewType } from "../../../client/views/collections/CollectionView"; +import { makeTemplate } from "../../../client/util/DropConverter"; +import { RichTextField } from "../../../new_fields/RichTextField"; export class CurrentUserUtils { private static curr_id: string; @@ -227,14 +229,30 @@ export class CurrentUserUtils { /// sets up the default list of buttons to be shown in the expanding button menu at the bottom of the Dash window static setupExpandingButtons(doc: Doc) { + const slideTemplate = Docs.Create.StackingDocument( + [ + Docs.Create.MulticolumnDocument([], { title: "images", _height: 200, _xMargin: 10, _yMargin: 10 }), + Docs.Create.TextDocument("", { title: "contents", _height: 100 }) + ], + { _width: 400, _height: 300, title: "slide", _chromeStatus: "disabled", _autoHeight: true }); + slideTemplate.isTemplateDoc = makeTemplate(slideTemplate); + + const iconDoc = Docs.Create.TextDocument("", { title: "icon", _width: 150, _height: 30, onClick: ScriptField.MakeScript("setNativeView(this)") }); + Doc.GetProto(iconDoc).data = 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":[]}', ""); + doc.isTemplateDoc = makeTemplate(iconDoc); + doc.iconView = iconDoc; + doc.undoBtn = Docs.Create.FontIconDocument( { _nativeWidth: 100, _nativeHeight: 100, _width: 100, _height: 100, _dropAction: "alias", onClick: ScriptField.MakeScript("undo()"), removeDropProperties: new List(["dropAction"]), title: "undo button", icon: "undo-alt" }); doc.redoBtn = Docs.Create.FontIconDocument( { _nativeWidth: 100, _nativeHeight: 100, _width: 100, _height: 100, _dropAction: "alias", onClick: ScriptField.MakeScript("redo()"), removeDropProperties: new List(["dropAction"]), title: "redo button", icon: "redo-alt" }); + doc.slidesBtn = Docs.Create.FontIconDocument( + { _nativeWidth: 100, _nativeHeight: 100, _width: 100, _height: 100, _dropAction: "alias", onDragStart: ScriptField.MakeFunction('getCopy(this.dragFactory, true)'), dragFactory: slideTemplate, removeDropProperties: new List(["dropAction"]), title: "slide button", icon: "sticky-note" }); - doc.expandingButtons = Docs.Create.LinearDocument([doc.undoBtn as Doc, doc.redoBtn as Doc], { + doc.expandingButtons = Docs.Create.LinearDocument([doc.undoBtn as Doc, doc.redoBtn as Doc, doc.slidesBtn as Doc], { title: "expanding buttons", _gridGap: 5, _xMargin: 5, _yMargin: 5, _height: 42, _width: 100, boxShadow: "0 0", backgroundColor: "black", preventTreeViewOpen: true, forceActive: true, lockedPosition: true, + dropConverter: ScriptField.MakeScript("convertToButtons(dragData)", { dragData: DragManager.DocumentDragData.name }) }); } -- cgit v1.2.3-70-g09d2 From a0ca191b6263e3ccff8740ddf6cf9cba68b9f2f9 Mon Sep 17 00:00:00 2001 From: bob Date: Wed, 5 Feb 2020 11:26:24 -0500 Subject: fixed iconify things. fixed presentation title bar. --- src/client/documents/Documents.ts | 3 ++- src/client/views/DocumentDecorations.tsx | 3 ++- src/client/views/nodes/DocumentView.tsx | 2 +- src/new_fields/Doc.ts | 4 +++- src/server/authentication/models/current_user_utils.ts | 11 +++++++---- 5 files changed, 15 insertions(+), 8 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 5eb4dc5fb..17570fcb5 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -106,6 +106,7 @@ export interface DocumentOptions { documentText?: string; borderRounding?: string; boxShadow?: string; + showTitle?: string; sectionFilter?: string; // field key used to determine headings for sections in stacking and masonry views schemaColumns?: List; dockingConfig?: string; @@ -340,7 +341,7 @@ export namespace Docs { export namespace Create { const delegateKeys = ["x", "y", "layoutKey", "_width", "_height", "_panX", "_panY", "_viewType", "_nativeWidth", "_nativeHeight", "_dropAction", "_annotationOn", - "_chromeStatus", "_forceActive", "_autoHeight", "_fitWidth", "_LODdisable", "_itemIndex", "_showSidebar"]; + "_chromeStatus", "_forceActive", "_autoHeight", "_fitWidth", "_LODdisable", "_itemIndex", "_showSidebar", "showTitle"]; /** * This function receives the relevant document prototype and uses diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index c5034b901..a0ba16ea4 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -265,8 +265,8 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> const layoutKey = Cast(dv.props.Document.layoutKey, "string", null); const collapse = layoutKey !== "layout_icon"; if (collapse) { - if (layoutKey && layoutKey !== "layout") dv.props.Document.deiconifyLayout = layoutKey.replace("layout_", ""); dv.setCustomView(collapse, "icon"); + if (layoutKey && layoutKey !== "layout") dv.props.Document.deiconifyLayout = layoutKey.replace("layout_", ""); } else { const deiconifyLayout = Cast(dv.props.Document.deiconifyLayout, "string", null); dv.setCustomView(deiconifyLayout ? true : false, deiconifyLayout); @@ -274,6 +274,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> } }); } + SelectionManager.DeselectAll(); } @action diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index c14d11cce..1fb3dcb36 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -902,7 +902,7 @@ export class DocumentView extends DocComponent(Docu const showTitle = StrCast(this.getLayoutPropStr("showTitle")); const showTitleHover = StrCast(this.getLayoutPropStr("showTitleHover")); const showCaption = this.getLayoutPropStr("showCaption"); - const showTextTitle = showTitle && StrCast(this.layoutDoc.layout).indexOf("FormattedTextBox") !== -1 ? showTitle : undefined; + const showTextTitle = showTitle && (StrCast(this.layoutDoc.layout).indexOf("PresBox") !== -1 || StrCast(this.layoutDoc.layout).indexOf("FormattedTextBox") !== -1) ? showTitle : undefined; const searchHighlight = (!this.Document.searchFields ? (null) :
{this.Document.searchFields} diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index 9b4844b19..862557302 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -784,8 +784,10 @@ export namespace Doc { export function setNativeView(doc: any) { const prevLayout = StrCast(doc.layoutKey).split("_")[1]; + const deiconify = prevLayout === "icon" && StrCast(doc.deiconifyLayout) ? "layout_" + StrCast(doc.deiconifyLayout) : ""; + doc.deiconifyLayout = undefined; if (StrCast(doc.title).endsWith("_" + prevLayout)) doc.title = StrCast(doc.title).replace("_" + prevLayout, ""); - doc.layoutKey = "layout"; + doc.layoutKey = deiconify || "layout"; } } diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts index a6dd809f4..a4af46a63 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -17,6 +17,7 @@ import { InkingControl } from "../../../client/views/InkingControl"; 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"; export class CurrentUserUtils { private static curr_id: string; @@ -47,17 +48,19 @@ export class CurrentUserUtils { // setup the "creator" buttons for the sidebar-- eg. the default set of draggable document creation tools static setupCreatorButtons(doc: Doc, buttons?: string[]) { const notes = CurrentUserUtils.setupNoteTypes(doc); + const emptyPresentation = Docs.Create.PresDocument(new List(), { title: "Presentation", _viewType: CollectionViewType.Stacking, showTitle: "title", boxShadow: "0 0" }); + const emptyCollection = Docs.Create.FreeformDocument([], { _nativeWidth: undefined, _nativeHeight: undefined, _LODdisable: true, _width: 150, _height: 100, title: "freeform" }); doc.noteTypes = Docs.Create.TreeDocument(notes, { title: "Note Types", _height: 75 }); doc.activePen = doc; const docProtoData: { title: string, icon: string, drag?: string, ignoreClick?: boolean, click?: string, ischecked?: string, activePen?: Doc, backgroundColor?: string, dragFactory?: Doc }[] = [ - { title: "collection", icon: "folder", ignoreClick: true, drag: 'Docs.Create.FreeformDocument([], { _nativeWidth: undefined, _nativeHeight: undefined, _LODdisable: true, _width: 150, _height: 100, title: "freeform" })' }, + { title: "collection", icon: "folder", click: 'openOnRight(getCopy(this.dragFactory))', drag: 'getCopy(this.dragFactory, true)', dragFactory: emptyCollection }, { title: "preview", icon: "expand", ignoreClick: true, drag: 'Docs.Create.DocumentDocument(ComputedField.MakeFunction("selectedDocs(this,true,[_last_])?.[0]"), { _width: 250, _height: 250, title: "container" })' }, { title: "todo item", icon: "check", ignoreClick: true, drag: 'getCopy(this.dragFactory, true)', dragFactory: notes[notes.length - 1] }, { title: "web page", icon: "globe-asia", ignoreClick: true, drag: 'Docs.Create.WebDocument("https://en.wikipedia.org/wiki/Hedgehog", {_width: 300, _height: 300, title: "New Webpage" })' }, { title: "cat image", icon: "cat", ignoreClick: true, drag: 'Docs.Create.ImageDocument("https://upload.wikimedia.org/wikipedia/commons/thumb/3/3a/Cat03.jpg/1200px-Cat03.jpg", { _width: 200, title: "an image of a cat" })' }, { title: "record", icon: "microphone", ignoreClick: true, drag: `Docs.Create.AudioDocument("${nullAudio}", { _width: 200, title: "ready to record audio" })` }, { title: "clickable button", icon: "bolt", ignoreClick: true, drag: 'Docs.Create.ButtonDocument({ _width: 150, _height: 50, title: "Button" })' }, - { title: "presentation", icon: "tv", ignoreClick: true, drag: `Doc.UserDoc().curPresentation = Docs.Create.PresDocument(new List(), { _width: 200, _height: 500, _xMargin:5, _viewType: ${CollectionViewType.Stacking}, title: "a presentation trail" })` }, + { title: "presentation", icon: "tv", click: 'openOnRight(Doc.UserDoc().curPresentation = getCopy(this.dragFactory))', drag: `Doc.UserDoc().curPresentation = getCopy(this.dragFactory,true)`, dragFactory: emptyPresentation }, { title: "import folder", icon: "cloud-upload-alt", ignoreClick: true, drag: 'Docs.Create.DirectoryImportDocument({ title: "Directory Import", _width: 400, _height: 400 })' }, { title: "mobile view", icon: "phone", ignoreClick: true, drag: 'Doc.UserDoc().activeMobile' }, { title: "use pen", icon: "pen-nib", click: 'activatePen(this.activePen.pen = sameDocs(this.activePen.pen, this) ? undefined : this,2, this.backgroundColor)', backgroundColor: "blue", ischecked: `sameDocs(this.activePen.pen, this)`, activePen: doc }, @@ -240,7 +243,7 @@ export class CurrentUserUtils { const iconDoc = Docs.Create.TextDocument("", { title: "icon", _width: 150, _height: 30, onClick: ScriptField.MakeScript("setNativeView(this)") }); Doc.GetProto(iconDoc).data = 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":[]}', ""); doc.isTemplateDoc = makeTemplate(iconDoc); - doc.iconView = iconDoc; + doc.iconView = new PrefetchProxy(iconDoc); doc.undoBtn = Docs.Create.FontIconDocument( { _nativeWidth: 100, _nativeHeight: 100, _width: 100, _height: 100, _dropAction: "alias", onClick: ScriptField.MakeScript("undo()"), removeDropProperties: new List(["dropAction"]), title: "undo button", icon: "undo-alt" }); @@ -266,7 +269,7 @@ export class CurrentUserUtils { // the initial presentation Doc to use static setupDefaultPresentation(doc: Doc) { - doc.curPresentation = Docs.Create.PresDocument(new List(), { title: "Presentation", _viewType: CollectionViewType.Stacking, boxShadow: "0 0" }); + doc.curPresentation = Docs.Create.PresDocument(new List(), { title: "Presentation", _viewType: CollectionViewType.Stacking, showTitle: "title", boxShadow: "0 0" }); } static setupMobileUploads(doc: Doc) { -- cgit v1.2.3-70-g09d2 From ab95c12485c26e5e0e6dc48cef8abd63a9c1fb56 Mon Sep 17 00:00:00 2001 From: bob Date: Wed, 5 Feb 2020 15:05:32 -0500 Subject: several layout fixes for row/col stuff. fixes to icons. added buttons for buxton app. made PresBox not search for its own contents when following a link --- src/client/util/DocumentManager.ts | 4 +- src/client/views/MainView.tsx | 4 +- .../views/collections/CollectionDockingView.tsx | 4 +- src/client/views/collections/CollectionSubView.tsx | 6 ++- .../views/collections/CollectionTimeView.tsx | 2 +- .../views/collections/CollectionTreeView.tsx | 47 +++++++++++++++------- .../collectionFreeForm/CollectionFreeFormView.tsx | 2 +- .../CollectionMulticolumnView.tsx | 5 +-- .../CollectionMultirowView.tsx | 4 +- src/client/views/nodes/DocumentView.tsx | 21 +++++----- .../authentication/models/current_user_utils.ts | 9 ++--- 11 files changed, 67 insertions(+), 41 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts index 9fff8faa7..60bb25272 100644 --- a/src/client/util/DocumentManager.ts +++ b/src/client/util/DocumentManager.ts @@ -93,9 +93,9 @@ export class DocumentManager { const toReturn: DocumentView[] = []; DocumentManager.Instance.DocumentViews.map(view => - view.props.Document === toFind && toReturn.push(view)); + view.props.Document.presBox === undefined && view.props.Document === toFind && toReturn.push(view)); DocumentManager.Instance.DocumentViews.map(view => - view.props.Document !== toFind && Doc.AreProtosEqual(view.props.Document, toFind) && toReturn.push(view)); + view.props.Document.presBox === undefined && view.props.Document !== toFind && Doc.AreProtosEqual(view.props.Document, toFind) && toReturn.push(view)); return toReturn; } diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 0cc374cee..a839f9fd2 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 { - faStickyNote, faArrowDown, faBullseye, faFilter, faArrowUp, faBolt, faCaretUp, faCat, faCheck, faChevronRight, faClone, faCloudUploadAlt, faCommentAlt, faCut, faEllipsisV, faExclamation, faFilePdf, faFilm, faFont, faGlobeAsia, faLongArrowAltRight, + faFileAlt, faStickyNote, faArrowDown, faBullseye, faFilter, faArrowUp, faBolt, faCaretUp, faCat, faCheck, faChevronRight, faClone, faCloudUploadAlt, faCommentAlt, faCut, faEllipsisV, faExclamation, faFilePdf, faFilm, faFont, faGlobeAsia, faLongArrowAltRight, faMusic, faObjectGroup, faPause, faMousePointer, faPenNib, faFileAudio, faPen, faEraser, faPlay, faPortrait, faRedoAlt, faThumbtack, faTree, faTv, faUndoAlt, faHighlighter, faMicrophone, faCompressArrowsAlt, faPhone, faStamp, faClipboard } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; @@ -101,6 +101,8 @@ export class MainView extends React.Component { } } + library.add(faFileAlt); + library.add(faStickyNote); library.add(faFont); library.add(faExclamation); library.add(faPortrait); diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 861a63503..9c67d8041 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -468,7 +468,9 @@ export class CollectionDockingView extends React.Component { e.preventDefault(); e.stopPropagation(); - DragManager.StartDocumentDrag([dragSpan], new DragManager.DocumentDragData([doc]), e.clientX, e.clientY); + const dragData = new DragManager.DocumentDragData([doc]); + dragData.dropAction = doc._dropAction; + DragManager.StartDocumentDrag([dragSpan], dragData, e.clientX, e.clientY); }}> , dragSpan); diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index a2700e75a..731b5b01d 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -128,11 +128,15 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T) { const filteredDocs = docFilters.length ? viewedDocs.filter(d => { for (const key of Object.keys(clusters)) { const cluster = clusters[key]; + const satisfiesFacetx = !Object.keys(cluster).some((inner) => { + const modifier = cluster[inner]; + return ((modifier === "x") === Doc.matchFieldValue(d, key, inner)); + }); const satisfiesFacet = Object.keys(cluster).some(inner => { const modifier = cluster[inner]; return (modifier === "x") !== Doc.matchFieldValue(d, key, inner); }); - if (!satisfiesFacet) { + if (!satisfiesFacet || !satisfiesFacetx) { return false; } } diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx index 264423d72..896fb74f0 100644 --- a/src/client/views/collections/CollectionTimeView.tsx +++ b/src/client/views/collections/CollectionTimeView.tsx @@ -33,7 +33,7 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) { this.props.Document.excludeFields = new List(["_facetCollection", "_docFilter"]); const scriptText = "setDocFilter(containingTreeView.target, heading, this.title, checked)"; - const childText = "const alias = getAlias(this); Doc.ApplyTemplateTo(containingCollection.childDetailed, alias, 'layout_detailed'); useRightSplit(alias, shiftKey); "; + const childText = "const alias = getAlias(this); Doc.ApplyTemplateTo(containingCollection.childDetailed, alias, 'layout_detailView'); alias._dropAction='alias'; alias.removeDropProperties=new List(['dropAction']); useRightSplit(alias, shiftKey); "; facetCollection.onCheckedClick = ScriptField.MakeScript(scriptText, { this: Doc.name, heading: "boolean", checked: "boolean", containingTreeView: Doc.name }); this.props.Document.onChildClick = ScriptField.MakeScript(childText, { this: Doc.name, heading: "boolean", containingCollection: Doc.name, shiftKey: "boolean" }); this.props.Document._facetCollection = facetCollection; diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 9e3fb1d67..19900c48b 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -640,27 +640,46 @@ export class CollectionTreeView extends CollectionSubView(Document) { d.captions = undefined; }); }); - const { TextDocument, ImageDocument, CarouselDocument } = Docs.Create; + const { TextDocument, ImageDocument, CarouselDocument, TreeDocument } = Docs.Create; const { Document } = this.props; const fallbackImg = "http://www.cs.brown.edu/~bcz/face.gif"; - const detailedTemplate = `{ "doc": { "type": "doc", "content": [ { "type": "paragraph", "content": [ { "type": "dashField", "attrs": { "fieldKey": "short_description" } } ] }, { "type": "paragraph", "content": [ { "type": "dashField", "attrs": { "fieldKey": "year" } } ] }, { "type": "paragraph", "content": [ { "type": "dashField", "attrs": { "fieldKey": "company" } } ] } ] }, "selection":{"type":"text","anchor":1,"head":1},"storedMarks":[] }`; + const detailedTemplate = `{ "doc": { "type": "doc", "content": [ { "type": "paragraph", "content": [ { "type": "dashField", "attrs": { "fieldKey": "year" } } ] }, { "type": "paragraph", "content": [ { "type": "dashField", "attrs": { "fieldKey": "company" } } ] } ] }, "selection":{"type":"text","anchor":1,"head":1},"storedMarks":[] }`; const textDoc = TextDocument("", { title: "details", _autoHeight: true }); - const detailedLayout = Docs.Create.StackingDocument([ + const detailView = Docs.Create.StackingDocument([ CarouselDocument([], { title: "data", _height: 350, _itemIndex: 0, backgroundColor: "#9b9b9b3F" }), textDoc, - ], { _chromeStatus: "disabled", title: "detailed layout stack" }); - textDoc.data = new RichTextField(detailedTemplate, "short_description year company"); - detailedLayout.isTemplateDoc = makeTemplate(detailedLayout); - - const cardLayout = ImageDocument(fallbackImg, { title: "cardLayout", isTemplateDoc: true, isTemplateForField: "hero", }); // this acts like a template doc and a template field ... a little weird, but seems to work? - cardLayout.proto!.layout = ImageBox.LayoutString("hero"); - cardLayout.showTitle = "title"; - cardLayout.showTitleHover = "titlehover"; - - Document.childLayout = cardLayout; - Document.childDetailed = detailedLayout; + TextDocument("", { title: "short_description", _autoHeight: true }), + TreeDocument([], { title: "narratives", _height: 75, treeViewHideTitle: true }) + ], { _chromeStatus: "disabled", _width: 300, _height: 300, _autoHeight: true, title: "detailView" }); + textDoc.data = new RichTextField(detailedTemplate, "year company"); + detailView.isTemplateDoc = makeTemplate(detailView); + + + const heroView = ImageDocument(fallbackImg, { title: "heroView", isTemplateDoc: true, isTemplateForField: "hero", }); // this acts like a template doc and a template field ... a little weird, but seems to work? + heroView.proto!.layout = ImageBox.LayoutString("hero"); + heroView.showTitle = "title"; + heroView.showTitleHover = "titlehover"; + heroView._dropAction = "alias"; + heroView.removeDropProperties = new List(["dropAction"]); + + Doc.AddDocToList(CurrentUserUtils.UserDocument.expandingButtons as Doc, "data", + Docs.Create.FontIconDocument({ + _nativeWidth: 100, _nativeHeight: 100, _width: 100, _height: 100, _dropAction: "alias", onDragStart: ScriptField.MakeFunction('getCopy(this.dragFactory, true)'), + dragFactory: heroView, removeDropProperties: new List(["dropAction"]), title: "hero view", icon: "portrait" + })); + + Doc.AddDocToList(CurrentUserUtils.UserDocument.expandingButtons as Doc, "data", + Docs.Create.FontIconDocument({ + _nativeWidth: 100, _nativeHeight: 100, _width: 100, _height: 100, _dropAction: "alias", onDragStart: ScriptField.MakeFunction('getCopy(this.dragFactory, true)'), + dragFactory: detailView, removeDropProperties: new List(["dropAction"]), title: "detail view", icon: "file-alt" + })); + + + Document.childLayout = heroView; + Document.childDetailed = detailView; Document._viewType = CollectionViewType.Time; + Document._forceActive = true; Document.pivotField = "company"; } }); diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 6b81eba7d..54c45e43a 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -434,7 +434,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { let y = this.Document._panY || 0; const docs = this.childLayoutPairs.filter(pair => pair.layout instanceof Doc && !pair.layout.isMinimized).map(pair => pair.layout); const [dx, dy] = this.getTransform().transformDirection(e.clientX - this._lastX, e.clientY - this._lastY); - if (!this.isAnnotationOverlay && docs.length) { + if (!this.isAnnotationOverlay && docs.length && this.childDataProvider(docs[0])) { PDFMenu.Instance.fadeOut(true); const minx = this.childDataProvider(docs[0]).x;//docs.length ? NumCast(docs[0].x) : 0; const miny = this.childDataProvider(docs[0]).y;//docs.length ? NumCast(docs[0].y) : 0; diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx index 92b908ab6..7d8de0db4 100644 --- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx +++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx @@ -5,7 +5,6 @@ import { Doc } from '../../../../new_fields/Doc'; import { documentSchema } from '../../../../new_fields/documentSchemas'; import { makeInterface } from '../../../../new_fields/Schema'; import { BoolCast, NumCast, ScriptCast, StrCast } from '../../../../new_fields/Types'; -import { Utils } from '../../../../Utils'; import { DragManager } from '../../../util/DragManager'; import { Transform } from '../../../util/Transform'; import { undoBatch } from '../../../util/UndoManager'; @@ -119,7 +118,7 @@ export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocu private get totalRatioAllocation(): number | undefined { const layoutInfoLen = this.resolvedLayoutInformation.widthSpecifiers.length; if (layoutInfoLen > 0 && this.totalFixedAllocation !== undefined) { - return this.props.PanelWidth() - (this.totalFixedAllocation + resizerWidth * (layoutInfoLen - 1)); + return this.props.PanelWidth() - (this.totalFixedAllocation + resizerWidth * (layoutInfoLen - 1)) - 2 * NumCast(this.props.Document._xMargin); } } @@ -228,7 +227,7 @@ export class CollectionMulticolumnView extends CollectionSubView(MulticolumnDocu for (let i = 0; i < childLayoutPairs.length; i++) { const { layout } = childLayoutPairs[i]; const dxf = () => this.lookupIndividualTransform(layout).translate(-NumCast(Document._xMargin), -NumCast(Document._yMargin)); - const width = () => this.lookupPixels(layout) - 2 * NumCast(Document._xMargin); + const width = () => this.lookupPixels(layout); const height = () => PanelHeight() - 2 * NumCast(Document._yMargin) - (BoolCast(Document.showWidthLabels) ? 20 : 0); collector.push(
0 && this.totalFixedAllocation !== undefined) { - return this.props.PanelHeight() - (this.totalFixedAllocation + resizerHeight * (layoutInfoLen - 1)); + return this.props.PanelHeight() - (this.totalFixedAllocation + resizerHeight * (layoutInfoLen - 1)) - 2 * NumCast(this.props.Document._yMargin); } } @@ -228,7 +228,7 @@ export class CollectionMultirowView extends CollectionSubView(MultirowDocument) for (let i = 0; i < childLayoutPairs.length; i++) { const { layout } = childLayoutPairs[i]; const dxf = () => this.lookupIndividualTransform(layout).translate(-NumCast(Document._xMargin), -NumCast(Document._yMargin)); - const height = () => this.lookupPixels(layout) - 2 * NumCast(Document._yMargin); + const height = () => this.lookupPixels(layout); const width = () => PanelWidth() - 2 * NumCast(Document._xMargin) - (BoolCast(Document.showWidthLabels) ? 20 : 0); collector.push(
(Docu if (e.cancelBubble && this.active) { document.removeEventListener("pointermove", this.onPointerMove); // stop listening to pointerMove if something else has stopPropagated it (e.g., the MarqueeView) } - else if (!e.cancelBubble && (SelectionManager.IsSelected(this, true) || this.props.parentActive(true) || this.Document.onDragStart || this.Document.onClick) && !this.Document.lockedPosition && !this.Document.inOverlay) { + else if (!e.cancelBubble && (SelectionManager.IsSelected(this, true) || this.props.parentActive(true) || this.Document.onDragStart || this.onClickHandler) && !this.Document.lockedPosition && !this.Document.inOverlay) { if (Math.abs(this._downX - e.clientX) > 3 || Math.abs(this._downY - e.clientY) > 3) { - if (!e.altKey && (!this.topMost || this.Document.onDragStart || this.Document.onClick) && (e.buttons === 1 || InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE))) { + if (!e.altKey && (!this.topMost || this.Document.onDragStart || this.onClickHandler) && (e.buttons === 1 || InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE))) { document.removeEventListener("pointermove", this.onPointerMove); document.removeEventListener("pointerup", this.onPointerUp); this.startDragging(this._downX, this._downY, this.Document._dropAction ? this.Document._dropAction as any : e.ctrlKey || e.altKey ? "alias" : undefined, this._hitTemplateDrag); @@ -518,7 +518,7 @@ export class DocumentView extends DocComponent(Docu } @undoBatch - deleteClicked = (): void => { SelectionManager.DeselectAll(); this.props.removeDocument && this.props.removeDocument(this.props.Document); } + deleteClicked = (): void => { SelectionManager.DeselectAll(); this.props.removeDocument?.(this.props.Document); } static makeNativeViewClicked = (doc: Doc) => { undoBatch(() => Doc.setNativeView(doc))(); @@ -597,7 +597,7 @@ export class DocumentView extends DocComponent(Docu `Link from ${StrCast(de.complete.annoDragData.annotationDocument.title)}`); } if (de.complete.docDragData && de.complete.docDragData.applyAsTemplate) { - Doc.ApplyTemplateTo(de.complete.docDragData.draggedDocuments[0], this.props.Document, "layout_custom"); + Doc.ApplyTemplateTo(de.complete.docDragData.draggedDocuments[0], this.props.Document, "layout_custom", undefined); e.stopPropagation(); } if (de.complete.linkDragData) { @@ -656,12 +656,13 @@ export class DocumentView extends DocComponent(Docu if (custom) { DocumentView.makeNativeViewClicked(this.props.Document); - let foundLayout: Opt = Cast(Doc.UserDoc().iconView, Doc, null); - !foundLayout && DocListCast(Cast(CurrentUserUtils.UserDocument.expandingButtons, Doc, null)?.data)?.map(btnDoc => { - if (StrCast(Cast(btnDoc?.dragFactory, Doc, null)?.title) === layout) { - foundLayout = btnDoc.dragFactory as Doc; - } - }) + let foundLayout: Opt; + DocListCast(Cast(Doc.UserDoc().expandingButtons, Doc, null)?.data)?.concat([Cast(Doc.UserDoc().iconView, Doc, null)]). + map(btnDoc => (btnDoc.dragFactory as Doc) || btnDoc).filter(doc => doc.isTemplateDoc).forEach(tempDoc => { + if (StrCast(tempDoc.title) === layout) { + foundLayout = tempDoc; + } + }) DocumentView. makeCustomViewClicked(this.props.Document, this.props.DataDoc, Docs.Create.StackingDocument, layout, foundLayout); } else { diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts index a4af46a63..74db511df 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -53,14 +53,14 @@ export class CurrentUserUtils { doc.noteTypes = Docs.Create.TreeDocument(notes, { title: "Note Types", _height: 75 }); doc.activePen = doc; const docProtoData: { title: string, icon: string, drag?: string, ignoreClick?: boolean, click?: string, ischecked?: string, activePen?: Doc, backgroundColor?: string, dragFactory?: Doc }[] = [ - { title: "collection", icon: "folder", click: 'openOnRight(getCopy(this.dragFactory))', drag: 'getCopy(this.dragFactory, true)', dragFactory: emptyCollection }, + { title: "collection", icon: "folder", click: 'openOnRight(getCopy(this.dragFactory, true))', drag: 'getCopy(this.dragFactory, true)', dragFactory: emptyCollection }, { title: "preview", icon: "expand", ignoreClick: true, drag: 'Docs.Create.DocumentDocument(ComputedField.MakeFunction("selectedDocs(this,true,[_last_])?.[0]"), { _width: 250, _height: 250, title: "container" })' }, { title: "todo item", icon: "check", ignoreClick: true, drag: 'getCopy(this.dragFactory, true)', dragFactory: notes[notes.length - 1] }, { title: "web page", icon: "globe-asia", ignoreClick: true, drag: 'Docs.Create.WebDocument("https://en.wikipedia.org/wiki/Hedgehog", {_width: 300, _height: 300, title: "New Webpage" })' }, { title: "cat image", icon: "cat", ignoreClick: true, drag: 'Docs.Create.ImageDocument("https://upload.wikimedia.org/wikipedia/commons/thumb/3/3a/Cat03.jpg/1200px-Cat03.jpg", { _width: 200, title: "an image of a cat" })' }, { title: "record", icon: "microphone", ignoreClick: true, drag: `Docs.Create.AudioDocument("${nullAudio}", { _width: 200, title: "ready to record audio" })` }, { title: "clickable button", icon: "bolt", ignoreClick: true, drag: 'Docs.Create.ButtonDocument({ _width: 150, _height: 50, title: "Button" })' }, - { title: "presentation", icon: "tv", click: 'openOnRight(Doc.UserDoc().curPresentation = getCopy(this.dragFactory))', drag: `Doc.UserDoc().curPresentation = getCopy(this.dragFactory,true)`, dragFactory: emptyPresentation }, + { title: "presentation", icon: "tv", click: 'openOnRight(Doc.UserDoc().curPresentation = getCopy(this.dragFactory, true))', drag: `Doc.UserDoc().curPresentation = getCopy(this.dragFactory,true)`, dragFactory: emptyPresentation }, { title: "import folder", icon: "cloud-upload-alt", ignoreClick: true, drag: 'Docs.Create.DirectoryImportDocument({ title: "Directory Import", _width: 400, _height: 400 })' }, { title: "mobile view", icon: "phone", ignoreClick: true, drag: 'Doc.UserDoc().activeMobile' }, { title: "use pen", icon: "pen-nib", click: 'activatePen(this.activePen.pen = sameDocs(this.activePen.pen, this) ? undefined : this,2, this.backgroundColor)', backgroundColor: "blue", ischecked: `sameDocs(this.activePen.pen, this)`, activePen: doc }, @@ -240,7 +240,7 @@ export class CurrentUserUtils { { _width: 400, _height: 300, title: "slide", _chromeStatus: "disabled", _autoHeight: true }); slideTemplate.isTemplateDoc = makeTemplate(slideTemplate); - const iconDoc = Docs.Create.TextDocument("", { title: "icon", _width: 150, _height: 30, onClick: ScriptField.MakeScript("setNativeView(this)") }); + const iconDoc = Docs.Create.TextDocument("", { title: "icon", _width: 150, _height: 30, isTemplateDoc: true, onClick: ScriptField.MakeScript("setNativeView(this)") }); Doc.GetProto(iconDoc).data = 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":[]}', ""); doc.isTemplateDoc = makeTemplate(iconDoc); doc.iconView = new PrefetchProxy(iconDoc); @@ -250,8 +250,7 @@ export class CurrentUserUtils { doc.redoBtn = Docs.Create.FontIconDocument( { _nativeWidth: 100, _nativeHeight: 100, _width: 100, _height: 100, _dropAction: "alias", onClick: ScriptField.MakeScript("redo()"), removeDropProperties: new List(["dropAction"]), title: "redo button", icon: "redo-alt" }); doc.slidesBtn = Docs.Create.FontIconDocument( - { _nativeWidth: 100, _nativeHeight: 100, _width: 100, _height: 100, _dropAction: "alias", onDragStart: ScriptField.MakeFunction('getCopy(this.dragFactory, true)'), dragFactory: slideTemplate, removeDropProperties: new List(["dropAction"]), title: "slide button", icon: "sticky-note" }); - + { _nativeWidth: 100, _nativeHeight: 100, _width: 100, _height: 100, _dropAction: "alias", onDragStart: ScriptField.MakeFunction('getCopy(this.dragFactory, true)'), dragFactory: slideTemplate, removeDropProperties: new List(["dropAction"]), title: "presentation slide", icon: "sticky-note" }); doc.expandingButtons = Docs.Create.LinearDocument([doc.undoBtn as Doc, doc.redoBtn as Doc, doc.slidesBtn as Doc], { title: "expanding buttons", _gridGap: 5, _xMargin: 5, _yMargin: 5, _height: 42, _width: 100, boxShadow: "0 0", backgroundColor: "black", preventTreeViewOpen: true, forceActive: true, lockedPosition: true, -- cgit v1.2.3-70-g09d2 From bc2798dbab082c381f7af1aa7b5ed2b6027c45aa Mon Sep 17 00:00:00 2001 From: bob Date: Wed, 5 Feb 2020 16:04:31 -0500 Subject: added aliasOf on aliasing .. and sourceContext for presentations --- src/client/util/SelectionManager.ts | 2 -- src/client/views/DocumentButtonBar.tsx | 1 + src/client/views/nodes/DocumentView.tsx | 1 + src/client/views/nodes/PresBox.tsx | 15 +++++++++------ src/new_fields/Doc.ts | 1 + 5 files changed, 12 insertions(+), 8 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/util/SelectionManager.ts b/src/client/util/SelectionManager.ts index 86a7a620e..4612f10f4 100644 --- a/src/client/util/SelectionManager.ts +++ b/src/client/util/SelectionManager.ts @@ -3,8 +3,6 @@ import { Doc } from "../../new_fields/Doc"; import { DocumentView } from "../views/nodes/DocumentView"; import { computedFn } from "mobx-utils"; import { List } from "../../new_fields/List"; -import { DocumentDecorations } from "../views/DocumentDecorations"; -import RichTextMenu from "./RichTextMenu"; export namespace SelectionManager { diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx index 121f79840..963d97d59 100644 --- a/src/client/views/DocumentButtonBar.tsx +++ b/src/client/views/DocumentButtonBar.tsx @@ -211,6 +211,7 @@ export class DocumentButtonBar extends React.Component<{ views: (DocumentView | DockedFrameRenderer.UnpinDoc(targetDoc); } else { + targetDoc.sourceContext = this.view0?.props.ContainingCollectionDoc; // bcz: !! Shouldn't need this ... use search to lookup contexts dynamically DockedFrameRenderer.PinDoc(targetDoc); } }}> diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 776d4b8c3..c04402360 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -210,6 +210,7 @@ export class DocumentView extends DocComponent(Docu dragData.moveDocument = this.props.moveDocument;// this.Document.onDragStart ? undefined : this.props.moveDocument; dragData.applyAsTemplate = applyAsTemplate; dragData.dragDivName = this.props.dragDivName; + this.props.Document.sourceContext = this.props.ContainingCollectionDoc; // bcz: !! shouldn't need this ... use search find the document's context dynamically DragManager.StartDocumentDrag([this._mainCont.current], dragData, x, y, { hideSource: !dropAction && !this.Document.onDragStart }); } } diff --git a/src/client/views/nodes/PresBox.tsx b/src/client/views/nodes/PresBox.tsx index 44411fa30..2b195855c 100644 --- a/src/client/views/nodes/PresBox.tsx +++ b/src/client/views/nodes/PresBox.tsx @@ -181,15 +181,17 @@ export class PresBox extends React.Component { }); //docToJump stayed same meaning, it was not in the group or was the last element in the group + const aliasOf = await Cast(docToJump.aliasOf, Doc); + const srcContext = aliasOf && await Cast(aliasOf.sourceContext, Doc); if (docToJump === curDoc) { //checking if curDoc has navigation open - const target = await curDoc.presentationTargetDoc as Doc; - if (curDoc.navButton) { - DocumentManager.Instance.jumpToDocument(target, false); - } else if (curDoc.showButton) { + const target = await Cast(curDoc.presentationTargetDoc, Doc); + if (curDoc.navButton && target) { + DocumentManager.Instance.jumpToDocument(target, false, undefined, srcContext); + } else if (curDoc.showButton && target) { const curScale = DocumentManager.Instance.getScaleOfDocView(fromDoc); //awaiting jump so that new scale can be found, since jumping is async - await DocumentManager.Instance.jumpToDocument(target, true); + await DocumentManager.Instance.jumpToDocument(target, true, undefined, srcContext); curDoc.viewScale = DocumentManager.Instance.getScaleOfDocView(target); //saving the scale user was on before zooming in @@ -203,7 +205,8 @@ export class PresBox extends React.Component { const curScale = DocumentManager.Instance.getScaleOfDocView(fromDoc); //awaiting jump so that new scale can be found, since jumping is async - await DocumentManager.Instance.jumpToDocument(await docToJump.presentationTargetDoc as Doc, willZoom); + const presTargetDoc = await docToJump.presentationTargetDoc as Doc; + await DocumentManager.Instance.jumpToDocument(presTargetDoc, willZoom, undefined, srcContext); const newScale = DocumentManager.Instance.getScaleOfDocView(await curDoc.presentationTargetDoc as Doc); curDoc.viewScale = newScale; //saving the scale that user was on diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index 862557302..2f669aecc 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -427,6 +427,7 @@ export namespace Doc { 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; } -- cgit v1.2.3-70-g09d2 From 9636494fa599862607e8658ef6e6a83a5f527dd8 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Wed, 5 Feb 2020 21:23:37 -0500 Subject: fixed pivot view rendering with text. fixed dragging items with click handlers. --- .../CollectionFreeFormLayoutEngines.tsx | 29 ++++++++++++++++------ src/client/views/nodes/DocumentView.tsx | 12 ++++++--- src/client/views/nodes/FormattedTextBox.tsx | 2 +- 3 files changed, 32 insertions(+), 11 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx index f35662dab..cee8f159e 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx @@ -57,6 +57,21 @@ function toLabel(target: FieldResult) { return target[ToString](); } return String(target); +}/** + * Uses canvas.measureText to compute and return the width of the given text of given font in pixels. + * + * @param {String} text The text to be rendered. + * @param {String} font The css font descriptor that text is to be rendered with (e.g. "bold 14px verdana"). + * + * @see https://stackoverflow.com/questions/118241/calculate-text-width-with-javascript/21015393#21015393 + */ +function getTextWidth(text: string, font: string): number { + // re-use canvas object for better performance + var canvas = (getTextWidth as any).canvas || ((getTextWidth as any).canvas = document.createElement("canvas")); + var context = canvas.getContext("2d"); + context.font = font; + var metrics = context.measureText(text); + return metrics.width; } export function computePivotLayout( @@ -69,7 +84,6 @@ export function computePivotLayout( ) { const fieldKey = "data"; const pivotColumnGroups = new Map, Doc[]>(); - const fontSize = NumCast(pivotDoc[fieldKey + "-timelineFontSize"], panelDim[1] > 58 ? 20 : Math.max(7, panelDim[1] / 3)); const pivotFieldKey = toLabel(pivotDoc.pivotField); for (const doc of childDocs) { @@ -91,10 +105,14 @@ export function computePivotLayout( } } } + const fontSize = NumCast(pivotDoc[fieldKey + "-timelineFontSize"], panelDim[1] > 58 ? 20 : Math.max(7, panelDim[1] / 3)); + const desc = `${fontSize}px ${getComputedStyle(document.body).fontFamily}`; + const textlen = Array.from(pivotColumnGroups.keys()).map(c => getTextWidth(toLabel(c), desc)).reduce((p, c) => Math.max(p, c), 0 as number); + const max_text = Math.min(Math.ceil(textlen / 120) * 28, panelDim[1]/2); let maxInColumn = Array.from(pivotColumnGroups.values()).reduce((p, s) => Math.max(p, s.length), 1); const colWidth = panelDim[0] / pivotColumnGroups.size; - const colHeight = panelDim[1]; + const colHeight = panelDim[1] - max_text; let numCols = 0; let bestArea = 0; let pivotAxisWidth = 0; @@ -103,9 +121,8 @@ export function computePivotLayout( const hd = colHeight / numInCol; const wd = colWidth / i; const dim = Math.min(hd, wd); - const area = dim * dim * i * numInCol; - if (area > bestArea) { - bestArea = area; + if (dim > bestArea) { + bestArea = dim; numCols = i; pivotAxisWidth = dim; } @@ -117,13 +134,11 @@ export function computePivotLayout( const expander = 1.05; const gap = .15; let x = 0; - let max_text = 60; Array.from(pivotColumnGroups.keys()).sort().forEach(key => { const val = pivotColumnGroups.get(key)!; let y = 0; let xCount = 0; const text = toLabel(key); - max_text = Math.max(max_text, Math.min(500, text.length)); groupNames.push({ type: "text", text, diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index c04402360..189c06288 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -456,7 +456,7 @@ export class DocumentView extends DocComponent(Docu } return; } - if (!e.nativeEvent.cancelBubble || this.Document.onClick || this.Document.onDragStart) { + if (!e.nativeEvent.cancelBubble || this.onClickHandler || this.Document.onDragStart) { this._downX = e.clientX; this._downY = e.clientY; this._hitTemplateDrag = false; @@ -467,7 +467,13 @@ export class DocumentView extends DocComponent(Docu this._hitTemplateDrag = true; } } - if ((this.active || this.Document.onDragStart || this.Document.onClick) && !e.ctrlKey && (e.button === 0 || InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE)) && !this.Document.lockedPosition && !this.Document.inOverlay) e.stopPropagation(); // events stop at the lowest document that is active. if right dragging, we let it go through though to allow for context menu clicks. PointerMove callbacks should remove themselves if the move event gets stopPropagated by a lower-level handler (e.g, marquee drag); + if ((this.active || this.Document.onDragStart || this.onClickHandler) && + !e.ctrlKey && + (e.button === 0 || InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE)) && + !this.Document.lockedPosition && + !this.Document.inOverlay) { + e.stopPropagation(); // events stop at the lowest document that is active. if right dragging, we let it go through though to allow for context menu clicks. PointerMove callbacks should remove themselves if the move event gets stopPropagated by a lower-level handler (e.g, marquee drag); + } document.removeEventListener("pointermove", this.onPointerMove); document.removeEventListener("pointerup", this.onPointerUp); document.addEventListener("pointermove", this.onPointerMove); @@ -532,7 +538,7 @@ export class DocumentView extends DocComponent(Docu if (doc[customName] === undefined) { const _width = NumCast(doc._width); const _height = NumCast(doc._height); - const options = { title: "data", _width, x: -_width / 2, y: - _height / 2, }; + const options = { title: "data", _width, x: -_width / 2, y: - _height / 2, _showSidebar: false }; const field = doc.data; let fieldTemplate: Opt; diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 969df7c5d..9370d3745 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -1101,7 +1101,7 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
- {this.props.Document._showSidebar ? (null) : this.sidebarWidthPercent === "0%" ? + {!this.props.Document._showSidebar ? (null) : this.sidebarWidthPercent === "0%" ?
this.toggleSidebar()} /> :
-- cgit v1.2.3-70-g09d2 From 829872a08cd70675990b96d7388e886d57283c27 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Wed, 5 Feb 2020 23:29:46 -0500 Subject: added additional view modes for presenations --- .../views/collections/CollectionCarouselView.tsx | 3 - .../CollectionFreeFormLayoutEngines.tsx | 4 +- src/client/views/nodes/DocumentView.tsx | 22 ++---- src/client/views/nodes/PresBox.scss | 17 +++- src/client/views/nodes/PresBox.tsx | 90 +++++++++++++++------- .../views/presentationview/PresElementBox.tsx | 2 +- 6 files changed, 82 insertions(+), 56 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/views/collections/CollectionCarouselView.tsx b/src/client/views/collections/CollectionCarouselView.tsx index e30d08592..00edf71dd 100644 --- a/src/client/views/collections/CollectionCarouselView.tsx +++ b/src/client/views/collections/CollectionCarouselView.tsx @@ -13,9 +13,6 @@ import { faCaretLeft, faCaretRight } from '@fortawesome/free-solid-svg-icons'; import { Doc } from '../../../new_fields/Doc'; import { FormattedTextBox } from '../nodes/FormattedTextBox'; - - - type CarouselDocument = makeInterface<[typeof documentSchema,]>; const CarouselDocument = makeInterface(documentSchema); diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx index cee8f159e..84acbe0f0 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx @@ -108,7 +108,7 @@ export function computePivotLayout( const fontSize = NumCast(pivotDoc[fieldKey + "-timelineFontSize"], panelDim[1] > 58 ? 20 : Math.max(7, panelDim[1] / 3)); const desc = `${fontSize}px ${getComputedStyle(document.body).fontFamily}`; const textlen = Array.from(pivotColumnGroups.keys()).map(c => getTextWidth(toLabel(c), desc)).reduce((p, c) => Math.max(p, c), 0 as number); - const max_text = Math.min(Math.ceil(textlen / 120) * 28, panelDim[1]/2); + const max_text = Math.min(Math.ceil(textlen / 120) * 28, panelDim[1] / 2); let maxInColumn = Array.from(pivotColumnGroups.values()).reduce((p, s) => Math.max(p, s.length), 1); const colWidth = panelDim[0] / pivotColumnGroups.size; @@ -171,7 +171,7 @@ export function computePivotLayout( x += pivotAxisWidth * (numCols * expander + gap); }); - const maxColHeight = pivotAxisWidth * Math.ceil(maxInColumn / numCols) + pivotAxisWidth; + const maxColHeight = pivotAxisWidth * expander * Math.ceil(maxInColumn / numCols); const dividers = Array.from(pivotColumnGroups.values()).map((pg, i) => ({ type: "div", color: "lightGray", x: i * pivotAxisWidth * (numCols * expander + gap), y: -maxColHeight + pivotAxisWidth, width: pivotAxisWidth * numCols * expander, height: maxColHeight } as any)); groupNames.push(...dividers); diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 189c06288..06e9209d3 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -467,10 +467,10 @@ export class DocumentView extends DocComponent(Docu this._hitTemplateDrag = true; } } - if ((this.active || this.Document.onDragStart || this.onClickHandler) && - !e.ctrlKey && - (e.button === 0 || InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE)) && - !this.Document.lockedPosition && + if ((this.active || this.Document.onDragStart || this.onClickHandler) && + !e.ctrlKey && + (e.button === 0 || InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE)) && + !this.Document.lockedPosition && !this.Document.inOverlay) { e.stopPropagation(); // events stop at the lowest document that is active. if right dragging, we let it go through though to allow for context menu clicks. PointerMove callbacks should remove themselves if the move event gets stopPropagated by a lower-level handler (e.g, marquee drag); } @@ -616,18 +616,6 @@ export class DocumentView extends DocComponent(Docu } } - @action - onDrop = (e: React.DragEvent) => { - const text = e.dataTransfer.getData("text/plain"); - if (!e.isDefaultPrevented() && text && text.startsWith(" { @@ -981,7 +969,7 @@ export class DocumentView extends DocComponent(Docu let highlighting = fullDegree && this.layoutDoc.type !== DocumentType.FONTICON && this.layoutDoc._viewType !== CollectionViewType.Linear; highlighting = highlighting && this.props.focus !== emptyFunction; // bcz: hack to turn off highlighting onsidebar panel documents. need to flag a document as not highlightable in a more direct way return
Doc.BrushDoc(this.props.Document)} onPointerLeave={e => Doc.UnBrushDoc(this.props.Document)} style={{ transition: this.Document.isAnimating ? ".5s linear" : StrCast(this.Document.transition), diff --git a/src/client/views/nodes/PresBox.scss b/src/client/views/nodes/PresBox.scss index 3e1967a18..7618aa7e3 100644 --- a/src/client/views/nodes/PresBox.scss +++ b/src/client/views/nodes/PresBox.scss @@ -14,10 +14,6 @@ transition: 0.7s opacity ease; pointer-events: all; - .presBox-listCont { - position: relative; - } - .presBox-buttons { padding: 10px; width: 100%; @@ -28,4 +24,17 @@ border-radius: 5px; } } + .presBox-backward, .presBox-forward { + width: 25px; + border-radius: 5px; + top:50%; + position: absolute; + display: inline-block; + } + .presBox-backward { + left:5; + } + .presBox-forward { + right:5; + } } \ No newline at end of file diff --git a/src/client/views/nodes/PresBox.tsx b/src/client/views/nodes/PresBox.tsx index 2b195855c..44405c413 100644 --- a/src/client/views/nodes/PresBox.tsx +++ b/src/client/views/nodes/PresBox.tsx @@ -2,7 +2,7 @@ import React = require("react"); import { library } from '@fortawesome/fontawesome-svg-core'; import { faArrowLeft, faArrowRight, faEdit, faMinus, faPlay, faPlus, faStop, faTimes } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { action, computed, IReactionDisposer, reaction } from "mobx"; +import { action, computed, IReactionDisposer, reaction, observable } from "mobx"; import { observer } from "mobx-react"; import { Doc, DocListCast, DocListCastAsync } from "../../../new_fields/Doc"; import { listSpec } from "../../../new_fields/Schema"; @@ -16,6 +16,10 @@ import { CollectionView, CollectionViewType } from "../collections/CollectionVie import { ContextMenu } from "../ContextMenu"; import { FieldView, FieldViewProps } from './FieldView'; import "./PresBox.scss"; +import { CollectionCarouselView } from "../collections/CollectionCarouselView"; +import { returnFalse } from "../../../Utils"; +import { ContextMenuProps } from "../ContextMenuItem"; +import { CollectionTimeView } from "../collections/CollectionTimeView"; library.add(faArrowLeft); library.add(faArrowRight); @@ -30,18 +34,26 @@ library.add(faEdit); export class PresBox extends React.Component { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(PresBox, fieldKey); } _childReaction: IReactionDisposer | undefined; + _slideshowReaction: IReactionDisposer | undefined; componentDidMount() { const userDoc = CurrentUserUtils.UserDocument; - let presTemp = Cast(userDoc.presentationTemplate, Doc); - if (presTemp instanceof Promise) { - presTemp.then(presTemp => this.props.Document.childLayout = presTemp); - } - else if (presTemp === undefined) { - presTemp = userDoc.presentationTemplate = Docs.Create.PresElementBoxDocument({ backgroundColor: "transparent", _xMargin: 5, isTemplateDoc: true, isTemplateForField: "data" }); - } - else { - this.props.Document.childLayout = presTemp; - } + this._slideshowReaction = reaction(() => this.props.Document._slideshow, + (slideshow) => { + if (!slideshow) { + let presTemp = Cast(userDoc.presentationTemplate, Doc); + if (presTemp instanceof Promise) { + presTemp.then(presTemp => this.props.Document.childLayout = presTemp); + } + else if (presTemp === undefined) { + presTemp = userDoc.presentationTemplate = Docs.Create.PresElementBoxDocument({ backgroundColor: "transparent", _xMargin: 5, isTemplateDoc: true, isTemplateForField: "data" }); + } + else { + this.props.Document.childLayout = presTemp; + } + } else { + this.props.Document.childLayout = undefined; + } + }, { fireImmediately: true }); this._childReaction = reaction(() => this.childDocs.slice(), (children) => children.forEach((child, i) => child.presentationIndex = i), { fireImmediately: true }); } @@ -52,7 +64,7 @@ export class PresBox extends React.Component { @computed get childDocs() { return DocListCast(this.props.Document[this.props.fieldKey]); } next = async () => { - const current = NumCast(this.props.Document.selectedDoc); + const current = NumCast(this.props.Document._itemIndex); //asking to get document at current index const docAtCurrentNext = await this.getDocAtIndex(current + 1); if (docAtCurrentNext !== undefined) { @@ -69,7 +81,7 @@ export class PresBox extends React.Component { } } back = async () => { - const current = NumCast(this.props.Document.selectedDoc); + const current = NumCast(this.props.Document._itemIndex); //requesting for the doc at current index const docAtCurrent = await this.getDocAtIndex(current); if (docAtCurrent !== undefined) { @@ -222,7 +234,7 @@ export class PresBox extends React.Component { getDocAtIndex = async (index: number) => { const list = FieldValue(Cast(this.props.Document[this.props.fieldKey], listSpec(Doc))); if (list && index >= 0 && index < list.length) { - this.props.Document.selectedDoc = index; + this.props.Document._itemIndex = index; //awaiting async call to finish to get Doc instance return list[index]; } @@ -250,7 +262,7 @@ export class PresBox extends React.Component { Doc.UnBrushAllDocs(); const list = FieldValue(Cast(this.props.Document[this.props.fieldKey], listSpec(Doc))); if (list && index >= 0 && index < list.length) { - this.props.Document.selectedDoc = index; + this.props.Document._itemIndex = index; if (!this.props.Document.presStatus) { this.props.Document.presStatus = true; @@ -274,7 +286,7 @@ export class PresBox extends React.Component { } else { this.props.Document.presStatus = true; this.startPresentation(0); - this.gotoDocument(0, NumCast(this.props.Document.selectedDoc)); + this.gotoDocument(0, NumCast(this.props.Document._itemIndex)); } } @@ -293,7 +305,7 @@ export class PresBox extends React.Component { doc.opacity = 1; doc.viewScale = 1; }); - this.props.Document.selectedDoc = 0; + this.props.Document._itemIndex = 0; this.props.Document.presStatus = false; if (this.childDocs.length !== 0) { DocumentManager.Instance.zoomIntoScale(this.childDocs[0], 1); @@ -330,7 +342,12 @@ export class PresBox extends React.Component { })); specificContextMenu = (e: React.MouseEvent): void => { - ContextMenu.Instance.addItem({ description: "Make Current Presentation", event: action(() => Doc.UserDoc().curPresentation = this.props.Document), icon: "asterisk" }); + const funcs: ContextMenuProps[] = []; + funcs.push({ description: "Make Current Presentation", event: action(() => Doc.UserDoc().curPresentation = this.props.Document), icon: "asterisk" }); + funcs.push({ description: "Make slideshow", event: action(() => this.props.Document._slideshow = "slideshow"), icon: "asterisk" }); + funcs.push({ description: "Make timeline", event: action(() => this.props.Document._slideshow = "timeline"), icon: "asterisk" }); + funcs.push({ description: "Make list", event: action(() => this.props.Document._slideshow = "list"), icon: "asterisk" }); + ContextMenu.Instance.addItem({ description: "Presentatoin Funcs...", subitems: funcs, icon: "asterisk" }); } /** @@ -353,19 +370,37 @@ export class PresBox extends React.Component { }); } - selectElement = (doc: Doc) => { const index = DocListCast(this.props.Document[this.props.fieldKey]).indexOf(doc); - index !== -1 && this.gotoDocument(index, NumCast(this.props.Document.selectedDoc)); + index !== -1 && this.gotoDocument(index, NumCast(this.props.Document._itemIndex)); } getTransform = () => { return this.props.ScreenToLocalTransform().translate(0, -50);// listBox padding-left and pres-box-cont minHeight } + panelHeight = () => { + return this.props.PanelHeight() - 20; + } render() { this.initializeScaleViews(this.childDocs, NumCast(this.props.Document._viewType)); - return ( + return (this.props.Document._slideshow ?
+ {this.props.Document.inOverlay ? (null) : +
+ {this.props.Document._slideshow === "slideshow" ? + + : + + } +
} + + +
+ :
-
- {this.props.Document.inOverlay ? (null) : -
- -
- } -
- ); + {this.props.Document.inOverlay ? (null) : +
+ +
} +
); } } \ No newline at end of file diff --git a/src/client/views/presentationview/PresElementBox.tsx b/src/client/views/presentationview/PresElementBox.tsx index ea3acf75c..52773d466 100644 --- a/src/client/views/presentationview/PresElementBox.tsx +++ b/src/client/views/presentationview/PresElementBox.tsx @@ -54,7 +54,7 @@ export class PresElementBox extends DocExtendableComponent [this.originalLayout.embedOpen, this.originalLayout.collapsedHeight], -- cgit v1.2.3-70-g09d2 From 714e66d2916971b5b023ba33c20b8794c1d536e2 Mon Sep 17 00:00:00 2001 From: bob Date: Thu, 6 Feb 2020 09:25:50 -0500 Subject: fixed unsetting of dropAction in buxton layouts. --- src/client/documents/Documents.ts | 6 +++--- src/client/util/DragManager.ts | 7 +++++-- src/client/views/collections/CollectionDockingView.tsx | 2 +- src/client/views/collections/CollectionTimeView.tsx | 2 +- src/client/views/collections/CollectionTreeView.tsx | 9 ++++----- src/client/views/nodes/DocumentView.tsx | 4 ++-- src/new_fields/documentSchemas.ts | 2 +- src/server/authentication/models/current_user_utils.ts | 16 ++++++++-------- 8 files changed, 25 insertions(+), 23 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 17570fcb5..64dc0d8b7 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -67,7 +67,7 @@ export interface DocumentOptions { _fitWidth?: boolean; _fitToBox?: boolean; // whether a freeformview should zoom/scale to create a shrinkwrapped view of its contents _LODdisable?: boolean; - _dropAction?: dropActionType; + dropAction?: dropActionType; _chromeStatus?: string; _viewType?: number; _gridGap?: number; // gap between items in masonry view @@ -340,7 +340,7 @@ export namespace Docs { */ export namespace Create { - const delegateKeys = ["x", "y", "layoutKey", "_width", "_height", "_panX", "_panY", "_viewType", "_nativeWidth", "_nativeHeight", "_dropAction", "_annotationOn", + const delegateKeys = ["x", "y", "layoutKey", "_width", "_height", "_panX", "_panY", "_viewType", "_nativeWidth", "_nativeHeight", "dropAction", "_annotationOn", "_chromeStatus", "_forceActive", "_autoHeight", "_fitWidth", "_LODdisable", "_itemIndex", "_showSidebar", "showTitle"]; /** @@ -745,7 +745,7 @@ export namespace Docs { } if (type.indexOf("excel") !== -1) { ctor = Docs.Create.DBDocument; - options._dropAction = "copy"; + options.dropAction = "copy"; } if (type.indexOf("html") !== -1) { if (path.includes(window.location.hostname)) { diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index c05a2de96..b0dd90947 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -15,7 +15,7 @@ import { listSpec } from "../../new_fields/Schema"; import { Scripting } from "./Scripting"; import { convertDropDataToButtons } from "./DropConverter"; -export type dropActionType = "alias" | "copy" | undefined; +export type dropActionType = "alias" | "copy" | "move" | undefined; export function SetupDrag( _reference: React.RefObject, docFunc: () => Doc | Promise | undefined, @@ -197,7 +197,10 @@ export namespace DragManager { dragData.userDropAction === "copy" || (!dragData.userDropAction && dragData.dropAction === "copy") ? Doc.MakeCopy(d, true) : d) ); e.docDragData?.droppedDocuments.forEach((drop: Doc, i: number) => - Cast(dragData.draggedDocuments[i].removeDropProperties, listSpec("string"), []).map(prop => drop[prop] = undefined)); + Cast(dragData.draggedDocuments[i].removeDropProperties, listSpec("string"), []).map(prop => { + drop[prop] = "move"; + }) + ); }; dragData.draggedDocuments.map(d => d.dragFactory); // does this help? trying to make sure the dragFactory Doc is loaded StartDrag(eles, dragData, downX, downY, options, finishDrag); diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 9c67d8041..2478aaecd 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -469,7 +469,7 @@ export class CollectionDockingView extends React.Component diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx index 896fb74f0..ae5a3c7dc 100644 --- a/src/client/views/collections/CollectionTimeView.tsx +++ b/src/client/views/collections/CollectionTimeView.tsx @@ -33,7 +33,7 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) { this.props.Document.excludeFields = new List(["_facetCollection", "_docFilter"]); const scriptText = "setDocFilter(containingTreeView.target, heading, this.title, checked)"; - const childText = "const alias = getAlias(this); Doc.ApplyTemplateTo(containingCollection.childDetailed, alias, 'layout_detailView'); alias._dropAction='alias'; alias.removeDropProperties=new List(['dropAction']); useRightSplit(alias, shiftKey); "; + const childText = "const alias = getAlias(this); Doc.ApplyTemplateTo(containingCollection.childDetailed, alias, 'layout_detailView'); alias.dropAction='alias'; alias.removeDropProperties=new List(['dropAction']); useRightSplit(alias, shiftKey); "; facetCollection.onCheckedClick = ScriptField.MakeScript(scriptText, { this: Doc.name, heading: "boolean", checked: "boolean", containingTreeView: Doc.name }); this.props.Document.onChildClick = ScriptField.MakeScript(childText, { this: Doc.name, heading: "boolean", containingCollection: Doc.name, shiftKey: "boolean" }); this.props.Document._facetCollection = facetCollection; diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 19900c48b..f44c7a7b0 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -660,18 +660,16 @@ export class CollectionTreeView extends CollectionSubView(Document) { heroView.proto!.layout = ImageBox.LayoutString("hero"); heroView.showTitle = "title"; heroView.showTitleHover = "titlehover"; - heroView._dropAction = "alias"; - heroView.removeDropProperties = new List(["dropAction"]); Doc.AddDocToList(CurrentUserUtils.UserDocument.expandingButtons as Doc, "data", Docs.Create.FontIconDocument({ - _nativeWidth: 100, _nativeHeight: 100, _width: 100, _height: 100, _dropAction: "alias", onDragStart: ScriptField.MakeFunction('getCopy(this.dragFactory, true)'), + _nativeWidth: 100, _nativeHeight: 100, _width: 100, _height: 100, dropAction: "alias", onDragStart: ScriptField.MakeFunction('getCopy(this.dragFactory, true)'), dragFactory: heroView, removeDropProperties: new List(["dropAction"]), title: "hero view", icon: "portrait" })); Doc.AddDocToList(CurrentUserUtils.UserDocument.expandingButtons as Doc, "data", Docs.Create.FontIconDocument({ - _nativeWidth: 100, _nativeHeight: 100, _width: 100, _height: 100, _dropAction: "alias", onDragStart: ScriptField.MakeFunction('getCopy(this.dragFactory, true)'), + _nativeWidth: 100, _nativeHeight: 100, _width: 100, _height: 100, dropAction: "alias", onDragStart: ScriptField.MakeFunction('getCopy(this.dragFactory, true)'), dragFactory: detailView, removeDropProperties: new List(["dropAction"]), title: "detail view", icon: "file-alt" })); @@ -680,6 +678,7 @@ export class CollectionTreeView extends CollectionSubView(Document) { Document.childDetailed = detailView; Document._viewType = CollectionViewType.Time; Document._forceActive = true; + Document.childDropAction = "alias"; Document.pivotField = "company"; } }); @@ -704,7 +703,7 @@ export class CollectionTreeView extends CollectionSubView(Document) { } render() { - const dropAction = StrCast(this.props.Document._dropAction) as dropActionType; + const dropAction = StrCast(this.props.Document.dropAction) as dropActionType; const addDoc = (doc: Doc, relativeTo?: Doc, before?: boolean) => Doc.AddDocToList(this.props.Document, this.props.fieldKey, doc, relativeTo, before, false, false, false); const moveDoc = (d: Doc, target: Doc | undefined, addDoc: (doc: Doc) => boolean) => this.props.moveDocument(d, target, addDoc); return !this.childDocs ? (null) : ( diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index c04402360..f9d9e7212 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -348,7 +348,7 @@ export class DocumentView extends DocComponent(Docu if (Math.abs(this._downX - touch.clientX) > 3 || Math.abs(this._downY - touch.clientY) > 3) { if (!e.altKey && (!this.topMost || this.Document.onDragStart || this.Document.onClick)) { this.cleanUpInteractions(); - this.startDragging(this._downX, this._downY, this.Document._dropAction ? this.Document._dropAction as any : e.ctrlKey || e.altKey ? "alias" : undefined, this._hitTemplateDrag); + this.startDragging(this._downX, this._downY, this.Document.dropAction ? this.Document.dropAction as any : e.ctrlKey || e.altKey ? "alias" : undefined, this._hitTemplateDrag); } } e.stopPropagation(); // doesn't actually stop propagation since all our listeners are listening to events on 'document' however it does mark the event as cancelBubble=true which we test for in the move event handlers @@ -489,7 +489,7 @@ export class DocumentView extends DocComponent(Docu if (!e.altKey && (!this.topMost || this.Document.onDragStart || this.onClickHandler) && (e.buttons === 1 || InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE))) { document.removeEventListener("pointermove", this.onPointerMove); document.removeEventListener("pointerup", this.onPointerUp); - this.startDragging(this._downX, this._downY, this.Document._dropAction ? this.Document._dropAction as any : e.ctrlKey || e.altKey ? "alias" : undefined, this._hitTemplateDrag); + this.startDragging(this._downX, this._downY, this.props.ContainingCollectionDoc?.childDropAction ? this.props.ContainingCollectionDoc?.childDropAction : this.Document.dropAction ? this.Document.dropAction as any : e.ctrlKey || e.altKey ? "alias" : undefined, this._hitTemplateDrag); } } e.stopPropagation(); // doesn't actually stop propagation since all our listeners are listening to events on 'document' however it does mark the event as cancelBubble=true which we test for in the move event handlers diff --git a/src/new_fields/documentSchemas.ts b/src/new_fields/documentSchemas.ts index 0b3bd6338..1aed5c242 100644 --- a/src/new_fields/documentSchemas.ts +++ b/src/new_fields/documentSchemas.ts @@ -8,7 +8,7 @@ export const documentSchema = createSchema({ layoutKey: "string", // holds the field key for the field that actually holds the current lyoat layout_custom: Doc, // used to hold a custom layout (there's nothing special about this field .. any field could hold a custom layout that can be selected by setting 'layoutKey') title: "string", // document title (can be on either data document or layout) - _dropAction: "string", // override specifying what should happen when this document is dropped (can be "alias" or "copy") + dropAction: "string", // override specifying what should happen when this document is dropped (can be "alias" or "copy") _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 diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts index 74db511df..b23ab5e49 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -71,7 +71,7 @@ export class CurrentUserUtils { { title: "use drag", icon: "mouse-pointer", click: 'deactivateInk();this.activePen.pen = this;', ischecked: `sameDocs(this.activePen.pen, this)`, backgroundColor: "white", activePen: doc }, ]; 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, + _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, @@ -109,7 +109,7 @@ export class CurrentUserUtils { { title: "use drag", icon: "mouse-pointer", click: 'deactivateInk();this.activePen.pen = this;', ischecked: `sameDocs(this.activePen.pen, this)`, backgroundColor: "white", activePen: doc }, ]; 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, + _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, @@ -125,7 +125,7 @@ export class CurrentUserUtils { { title: "ignore gestures", icon: "signature", pointerUp: "setToolglass('none')", pointerDown: "setToolglass('ignoregesture')", backgroundColor: "green", ischecked: `sameDocs(this.activePen.pen, this)`, activePen: doc }, ]; return docProtoData.map(data => Docs.Create.FontIconDocument({ - _nativeWidth: 10, _nativeHeight: 10, _width: 10, _height: 10, _dropAction: data.pointerDown ? "copy" : undefined, title: data.title, icon: data.icon, ignoreClick: data.ignoreClick, + _nativeWidth: 10, _nativeHeight: 10, _width: 10, _height: 10, dropAction: data.pointerDown ? "copy" : undefined, title: data.title, icon: data.icon, 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, @@ -158,7 +158,7 @@ export class CurrentUserUtils { }); // setup a color picker const color = Docs.Create.ColorDocument({ - title: "color picker", _width: 300, _dropAction: "alias", forceActive: true, removeDropProperties: new List(["dropAction", "forceActive"]) + title: "color picker", _width: 300, dropAction: "alias", forceActive: true, removeDropProperties: new List(["dropAction", "forceActive"]) }); return Docs.Create.ButtonDocument({ @@ -191,7 +191,7 @@ export class CurrentUserUtils { _width: 50, _height: 25, backgroundColor: "lightgrey", color: "rgb(34, 34, 34)", title: "Library", fontSize: 10, letterSpacing: "0px", textTransform: "unset", borderRounding: "5px 5px 0px 0px", boxShadow: "3px 3px 0px rgb(34, 34, 34)", sourcePanel: Docs.Create.TreeDocument([doc.workspaces as Doc, doc.documents as Doc, doc.recentlyClosed as Doc], { - title: "Library", _xMargin: 5, _yMargin: 5, _gridGap: 5, forceActive: true, _dropAction: "alias", lockedPosition: true, boxShadow: "0 0", + title: "Library", _xMargin: 5, _yMargin: 5, _gridGap: 5, forceActive: true, dropAction: "alias", lockedPosition: true, boxShadow: "0 0", }), targetContainer: sidebarContainer, onClick: ScriptField.MakeScript("this.targetContainer.proto = this.sourcePanel;") @@ -246,11 +246,11 @@ export class CurrentUserUtils { doc.iconView = new PrefetchProxy(iconDoc); doc.undoBtn = Docs.Create.FontIconDocument( - { _nativeWidth: 100, _nativeHeight: 100, _width: 100, _height: 100, _dropAction: "alias", onClick: ScriptField.MakeScript("undo()"), removeDropProperties: new List(["dropAction"]), title: "undo button", icon: "undo-alt" }); + { _nativeWidth: 100, _nativeHeight: 100, _width: 100, _height: 100, dropAction: "alias", onClick: ScriptField.MakeScript("undo()"), removeDropProperties: new List(["dropAction"]), title: "undo button", icon: "undo-alt" }); doc.redoBtn = Docs.Create.FontIconDocument( - { _nativeWidth: 100, _nativeHeight: 100, _width: 100, _height: 100, _dropAction: "alias", onClick: ScriptField.MakeScript("redo()"), removeDropProperties: new List(["dropAction"]), title: "redo button", icon: "redo-alt" }); + { _nativeWidth: 100, _nativeHeight: 100, _width: 100, _height: 100, dropAction: "alias", onClick: ScriptField.MakeScript("redo()"), removeDropProperties: new List(["dropAction"]), title: "redo button", icon: "redo-alt" }); doc.slidesBtn = Docs.Create.FontIconDocument( - { _nativeWidth: 100, _nativeHeight: 100, _width: 100, _height: 100, _dropAction: "alias", onDragStart: ScriptField.MakeFunction('getCopy(this.dragFactory, true)'), dragFactory: slideTemplate, removeDropProperties: new List(["dropAction"]), title: "presentation slide", icon: "sticky-note" }); + { _nativeWidth: 100, _nativeHeight: 100, _width: 100, _height: 100, dropAction: "alias", onDragStart: ScriptField.MakeFunction('getCopy(this.dragFactory, true)'), dragFactory: slideTemplate, removeDropProperties: new List(["dropAction"]), title: "presentation slide", icon: "sticky-note" }); doc.expandingButtons = Docs.Create.LinearDocument([doc.undoBtn as Doc, doc.redoBtn as Doc, doc.slidesBtn as Doc], { title: "expanding buttons", _gridGap: 5, _xMargin: 5, _yMargin: 5, _height: 42, _width: 100, boxShadow: "0 0", backgroundColor: "black", preventTreeViewOpen: true, forceActive: true, lockedPosition: true, -- cgit v1.2.3-70-g09d2 From 0817d947b98b1b8e7f05df6b1d3db8eef4996ec9 Mon Sep 17 00:00:00 2001 From: bob Date: Thu, 6 Feb 2020 10:38:18 -0500 Subject: added synching of timelines with presentations --- .../views/collections/CollectionTimeView.tsx | 23 ++++++++++- src/client/views/nodes/PresBox.tsx | 45 ++++++++++++++-------- src/new_fields/ScriptField.ts | 4 +- 3 files changed, 52 insertions(+), 20 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx index ae5a3c7dc..1c4bfa4e8 100644 --- a/src/client/views/collections/CollectionTimeView.tsx +++ b/src/client/views/collections/CollectionTimeView.tsx @@ -19,6 +19,7 @@ import React = require("react"); import { ContextMenu } from "../ContextMenu"; import { ContextMenuProps } from "../ContextMenuItem"; import { RichTextField } from "../../../new_fields/RichTextField"; +import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils"; @observer export class CollectionTimeView extends CollectionSubView(doc => doc) { @@ -225,6 +226,21 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) {
; } + specificMenu = (e: React.MouseEvent) => { + const layoutItems: ContextMenuProps[] = []; + + layoutItems.push({ description: "Force Timeline", event: () => { this.props.Document._forceRenderEngine = "timeline" }, icon: "compress-arrows-alt" }); + layoutItems.push({ description: "Force Pivot", event: () => { this.props.Document._forceRenderEngine = "pivot" }, icon: "compress-arrows-alt" }); + layoutItems.push({ description: "Auto Time/Pivot layout", event: () => { this.props.Document._forceRenderEngine = undefined }, icon: "compress-arrows-alt" }); + layoutItems.push({ + description: "Sync with presentation", event: () => { + this.props.Document[this.props.fieldKey + "-timelineCur"] = ComputedField.MakeFunction("mainPres.curPresentation.data[mainPres.curPresentation._itemIndex].year || 0", { mainPres: Doc.name }, { mainPres: CurrentUserUtils.UserDocument }); + }, icon: "compress-arrows-alt" + }); + + ContextMenu.Instance.addItem({ description: "Pivot/Time Options ...", subitems: layoutItems, icon: "eye" }); + } + render() { const newEditableViewProps = { GetValue: () => "", @@ -248,7 +264,8 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) { nonNumbers++; } }); - const doTimeline = nonNumbers / this.childDocs.length < 0.1 && this.props.PanelWidth() / this.props.PanelHeight() > 6; + const forceLayout = StrCast(this.props.Document._forceRenderEngine); + const doTimeline = forceLayout ? (forceLayout === "timeline") : nonNumbers / this.childDocs.length < 0.1 && this.props.PanelWidth() / this.props.PanelHeight() > 6; if (doTimeline !== (this._layoutEngine === "timeline")) { if (!this._changing) { this._changing = true; @@ -259,9 +276,11 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) { } } + const facetCollection = Cast(this.props.Document?._facetCollection, Doc, null); return !facetCollection ? (null) : -
+
diff --git a/src/client/views/nodes/PresBox.tsx b/src/client/views/nodes/PresBox.tsx index 44405c413..be5d414a5 100644 --- a/src/client/views/nodes/PresBox.tsx +++ b/src/client/views/nodes/PresBox.tsx @@ -2,10 +2,10 @@ import React = require("react"); import { library } from '@fortawesome/fontawesome-svg-core'; import { faArrowLeft, faArrowRight, faEdit, faMinus, faPlay, faPlus, faStop, faTimes } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { action, computed, IReactionDisposer, reaction, observable } from "mobx"; +import { action, computed, IReactionDisposer, reaction, observable, runInAction } from "mobx"; import { observer } from "mobx-react"; import { Doc, DocListCast, DocListCastAsync } from "../../../new_fields/Doc"; -import { listSpec } from "../../../new_fields/Schema"; +import { listSpec, makeInterface } from "../../../new_fields/Schema"; import { Cast, FieldValue, NumCast } from "../../../new_fields/Types"; import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils"; import { Docs } from "../../documents/Documents"; @@ -20,6 +20,9 @@ import { CollectionCarouselView } from "../collections/CollectionCarouselView"; import { returnFalse } from "../../../Utils"; import { ContextMenuProps } from "../ContextMenuItem"; import { CollectionTimeView } from "../collections/CollectionTimeView"; +import { documentSchema } from "../../../new_fields/documentSchemas"; +import { InkingControl } from "../InkingControl"; +import { InkTool } from "../../../new_fields/InkField"; library.add(faArrowLeft); library.add(faArrowRight); @@ -35,6 +38,8 @@ export class PresBox extends React.Component { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(PresBox, fieldKey); } _childReaction: IReactionDisposer | undefined; _slideshowReaction: IReactionDisposer | undefined; + @observable _isChildActive = false; + componentDidMount() { const userDoc = CurrentUserUtils.UserDocument; this._slideshowReaction = reaction(() => this.props.Document._slideshow, @@ -54,16 +59,17 @@ export class PresBox extends React.Component { this.props.Document.childLayout = undefined; } }, { fireImmediately: true }); - this._childReaction = reaction(() => this.childDocs.slice(), - (children) => children.forEach((child, i) => child.presentationIndex = i), { fireImmediately: true }); + this._childReaction = reaction(() => this.childDocs.slice(), (children) => children.forEach((child, i) => child.presentationIndex = i), { fireImmediately: true }); } componentWillUnmount() { this._childReaction?.(); + this._slideshowReaction?.(); } @computed get childDocs() { return DocListCast(this.props.Document[this.props.fieldKey]); } next = async () => { + runInAction(() => Doc.UserDoc().curPresentation = this.props.Document); const current = NumCast(this.props.Document._itemIndex); //asking to get document at current index const docAtCurrentNext = await this.getDocAtIndex(current + 1); @@ -81,6 +87,7 @@ export class PresBox extends React.Component { } } back = async () => { + action(() => Doc.UserDoc().curPresentation = this.props.Document); const current = NumCast(this.props.Document._itemIndex); //requesting for the doc at current index const docAtCurrent = await this.getDocAtIndex(current); @@ -120,12 +127,17 @@ export class PresBox extends React.Component { } } + whenActiveChanged = action((isActive: boolean) => this.props.whenActiveChanged(this._isChildActive = isActive)); + active = (outsideReaction?: boolean) => ((InkingControl.Instance.selectedTool === InkTool.None && !this.props.Document.isBackground) && + (this.props.Document.forceActive || this.props.isSelected(outsideReaction) || this._isChildActive || this.props.renderDepth === 0) ? true : false) + /** * This is the method that checks for the actions that need to be performed * after the document has been presented, which involves 3 button options: * Hide Until Presented, Hide After Presented, Fade After Presented */ showAfterPresented = (index: number) => { + action(() => Doc.UserDoc().curPresentation = this.props.Document); this.childDocs.forEach((doc, ind) => { //the order of cases is aligned based on priority if (doc.hideTillShownButton && ind <= index) { @@ -146,6 +158,7 @@ export class PresBox extends React.Component { * Hide Until Presented, Hide After Presented, Fade After Presented */ hideIfNotPresented = (index: number) => { + action(() => Doc.UserDoc().curPresentation = this.props.Document); this.childDocs.forEach((key, ind) => { //the order of cases is aligned based on priority @@ -167,6 +180,7 @@ export class PresBox extends React.Component { * te option open, navigates to that element. */ navigateToElement = async (curDoc: Doc, fromDocIndex: number) => { + action(() => Doc.UserDoc().curPresentation = this.props.Document); const fromDoc = this.childDocs[fromDocIndex].presentationTargetDoc as Doc; let docToJump = curDoc; let willZoom = false; @@ -257,8 +271,8 @@ export class PresBox extends React.Component { //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. - @action public gotoDocument = async (index: number, fromDoc: number) => { + action(() => Doc.UserDoc().curPresentation = this.props.Document); Doc.UnBrushAllDocs(); const list = FieldValue(Cast(this.props.Document[this.props.fieldKey], listSpec(Doc))); if (list && index >= 0 && index < list.length) { @@ -279,8 +293,8 @@ export class PresBox extends React.Component { } //The function that starts or resets presentaton functionally, depending on status flag. - @action startOrResetPres = () => { + action(() => Doc.UserDoc().curPresentation = this.props.Document); if (this.props.Document.presStatus) { this.resetPresentation(); } else { @@ -299,8 +313,8 @@ export class PresBox extends React.Component { //The function that resets the presentation by removing every action done by it. It also //stops the presentaton. - @action resetPresentation = () => { + action(() => Doc.UserDoc().curPresentation = this.props.Document); this.childDocs.forEach((doc: Doc) => { doc.opacity = 1; doc.viewScale = 1; @@ -315,6 +329,7 @@ export class PresBox extends React.Component { //The function that starts the presentation, also checking if actions should be applied //directly at start. startPresentation = (startIndex: number) => { + action(() => Doc.UserDoc().curPresentation = this.props.Document); this.childDocs.map(doc => { if (doc.hideTillShownButton && this.childDocs.indexOf(doc) > startIndex) { doc.opacity = 0; @@ -343,18 +358,16 @@ export class PresBox extends React.Component { specificContextMenu = (e: React.MouseEvent): void => { const funcs: ContextMenuProps[] = []; - funcs.push({ description: "Make Current Presentation", event: action(() => Doc.UserDoc().curPresentation = this.props.Document), icon: "asterisk" }); - funcs.push({ description: "Make slideshow", event: action(() => this.props.Document._slideshow = "slideshow"), icon: "asterisk" }); - funcs.push({ description: "Make timeline", event: action(() => this.props.Document._slideshow = "timeline"), icon: "asterisk" }); - funcs.push({ description: "Make list", event: action(() => this.props.Document._slideshow = "list"), icon: "asterisk" }); - ContextMenu.Instance.addItem({ description: "Presentatoin Funcs...", subitems: funcs, icon: "asterisk" }); + funcs.push({ description: "Show as Slideshow", event: action(() => this.props.Document._slideshow = "slideshow"), icon: "asterisk" }); + funcs.push({ description: "Show as Timeline", event: action(() => this.props.Document._slideshow = "timeline"), icon: "asterisk" }); + funcs.push({ description: "Show as List", event: action(() => this.props.Document._slideshow = "list"), icon: "asterisk" }); + ContextMenu.Instance.addItem({ description: "Presentation Funcs...", subitems: funcs, icon: "asterisk" }); } /** * Initially every document starts with a viewScale 1, which means * that they will be displayed in a canvas with scale 1. */ - @action initializeScaleViews = (docList: Doc[], viewtype: number) => { this.props.Document._chromeStatus = "disabled"; const hgt = (viewtype === CollectionViewType.Tree) ? 50 : 46; @@ -384,7 +397,7 @@ export class PresBox extends React.Component { render() { this.initializeScaleViews(this.childDocs, NumCast(this.props.Document._viewType)); return (this.props.Document._slideshow ? -
+
{this.props.Document.inOverlay ? (null) :
{this.props.Document._slideshow === "slideshow" ? @@ -409,8 +422,8 @@ export class PresBox extends React.Component { {this.props.Document.inOverlay ? (null) : -
- +
+
}
); } diff --git a/src/new_fields/ScriptField.ts b/src/new_fields/ScriptField.ts index f8a8d1226..4c78ea3aa 100644 --- a/src/new_fields/ScriptField.ts +++ b/src/new_fields/ScriptField.ts @@ -114,8 +114,8 @@ export class ScriptField extends ObjectField { }); return compiled; } - public static MakeFunction(script: string, params: object = {}) { - const compiled = ScriptField.CompileScript(script, params, true); + 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; } -- cgit v1.2.3-70-g09d2 From 045233f2a8b8e79e6a3255ed594218929db1b042 Mon Sep 17 00:00:00 2001 From: bob Date: Thu, 6 Feb 2020 15:14:56 -0500 Subject: added pivoting into a pivot column --- src/client/views/collections/CollectionSubView.tsx | 6 +- .../views/collections/CollectionTimeView.tsx | 14 +++- .../CollectionFreeFormLayoutEngines.tsx | 87 ++++++++++++---------- .../collectionFreeForm/CollectionFreeFormView.tsx | 15 ++-- src/client/views/nodes/PresBox.tsx | 2 +- src/new_fields/Doc.ts | 31 ++++---- src/new_fields/util.ts | 2 +- 7 files changed, 87 insertions(+), 70 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 731b5b01d..a2700e75a 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -128,15 +128,11 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T) { const filteredDocs = docFilters.length ? viewedDocs.filter(d => { for (const key of Object.keys(clusters)) { const cluster = clusters[key]; - const satisfiesFacetx = !Object.keys(cluster).some((inner) => { - const modifier = cluster[inner]; - return ((modifier === "x") === Doc.matchFieldValue(d, key, inner)); - }); const satisfiesFacet = Object.keys(cluster).some(inner => { const modifier = cluster[inner]; return (modifier === "x") !== Doc.matchFieldValue(d, key, inner); }); - if (!satisfiesFacet || !satisfiesFacetx) { + if (!satisfiesFacet) { return false; } } diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx index a9114026f..c0e18714e 100644 --- a/src/client/views/collections/CollectionTimeView.tsx +++ b/src/client/views/collections/CollectionTimeView.tsx @@ -20,6 +20,8 @@ import { ContextMenu } from "../ContextMenu"; import { ContextMenuProps } from "../ContextMenuItem"; import { RichTextField } from "../../../new_fields/RichTextField"; import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils"; +import { Scripting } from "../../util/Scripting"; +import { ViewDefResult, ViewDefBounds } from "./collectionFreeForm/CollectionFreeFormLayoutEngines"; @observer export class CollectionTimeView extends CollectionSubView(doc => doc) { @@ -40,7 +42,11 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) { this.props.Document._facetCollection = facetCollection; this.props.Document._fitToBox = true; } + if (!this.props.Document.onViewDefClick) { + this.props.Document.onViewDefDivClick = ScriptField.MakeScript("pivotColumnClick(this,payload)", { payload: "any" }) + } } + bodyPanelWidth = () => this.props.PanelWidth() - this._facetWidth; getTransform = () => this.props.ScreenToLocalTransform().translate(-this._facetWidth, 0); @@ -299,4 +305,10 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) { }
; } -} \ No newline at end of file +} + +Scripting.addGlobal(function pivotColumnClick(pivotDoc: Doc, bounds: ViewDefBounds) { + console.log("filter down to key: " + pivotDoc._pivotField + " val:" + bounds.payload); + (bounds.payload as string[]).map(filterVal => + Doc.setDocFilter(pivotDoc, StrCast(pivotDoc._pivotField), filterVal, "check")); +}); \ No newline at end of file diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx index d58925aab..884f3b353 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx @@ -1,29 +1,18 @@ -import { Doc, Field, FieldResult, WidthSym, HeightSym } from "../../../../new_fields/Doc"; -import { NumCast, StrCast, Cast, DateCast, BoolCast } from "../../../../new_fields/Types"; +import { Doc, Field, FieldResult } from "../../../../new_fields/Doc"; +import { NumCast, StrCast, Cast } from "../../../../new_fields/Types"; import { ScriptBox } from "../../ScriptBox"; import { CompileScript } from "../../../util/Scripting"; import { ScriptField } from "../../../../new_fields/ScriptField"; import { OverlayView, OverlayElementOptions } from "../../OverlayView"; import { emptyFunction, aggregateBounds } from "../../../../Utils"; import React = require("react"); -import { ObservableMap, runInAction } from "mobx"; import { Id, ToString } from "../../../../new_fields/FieldSymbols"; import { ObjectField } from "../../../../new_fields/ObjectField"; import { RefField } from "../../../../new_fields/RefField"; -interface PivotData { - type: string; - text: string; - x: number; - y: number; - zIndex?: number; - width?: number; - height?: number; - fontSize: number; - color?: string; -} - export interface ViewDefBounds { + type: string; + text?: string; x: number; y: number; z?: number; @@ -31,7 +20,10 @@ export interface ViewDefBounds { width?: number; height?: number; transition?: string; + fontSize?: number; highlight?: boolean; + color?: string; + payload: any; } export interface PoolData { @@ -83,14 +75,14 @@ export function computePivotLayout( viewDefsToJSX: (views: any) => ViewDefResult[] ) { const fieldKey = "data"; - const pivotColumnGroups = new Map, Doc[]>(); + const pivotColumnGroups = new Map, { docs: Doc[], filters: string[] }>(); const pivotFieldKey = toLabel(pivotDoc._pivotField); for (const doc of childDocs) { const val = Field.toString(doc[pivotFieldKey] as Field); if (val) { - !pivotColumnGroups.get(val) && pivotColumnGroups.set(val, []); - pivotColumnGroups.get(val)!.push(doc); + !pivotColumnGroups.get(val) && pivotColumnGroups.set(val, { docs: [], filters: [val] }); + pivotColumnGroups.get(val)!.docs.push(doc); } } if (pivotColumnGroups.size > 10) { @@ -100,7 +92,10 @@ export function computePivotLayout( const numClusters = Math.ceil(sortedKeys.length / clusterSize); for (let i = 0; i < numClusters; i++) { for (let j = i * clusterSize + 1; j < Math.min(sortedKeys.length, (i + 1) * clusterSize); j++) { - pivotColumnGroups.get(sortedKeys[i * clusterSize])!.push(...pivotColumnGroups.get(sortedKeys[j])!); + const curgrp = pivotColumnGroups.get(sortedKeys[i * clusterSize])!; + const newgrp = pivotColumnGroups.get(sortedKeys[j])!; + curgrp.docs.push(...newgrp.docs); + curgrp.filters.push(...newgrp.filters); pivotColumnGroups.delete(sortedKeys[j]); } } @@ -109,7 +104,7 @@ export function computePivotLayout( const desc = `${fontSize}px ${getComputedStyle(document.body).fontFamily}`; const textlen = Array.from(pivotColumnGroups.keys()).map(c => getTextWidth(toLabel(c), desc)).reduce((p, c) => Math.max(p, c), 0 as number); const max_text = Math.min(Math.ceil(textlen / 120) * 28, panelDim[1] / 2); - let maxInColumn = Array.from(pivotColumnGroups.values()).reduce((p, s) => Math.max(p, s.length), 1); + let maxInColumn = Array.from(pivotColumnGroups.values()).reduce((p, s) => Math.max(p, s.docs.length), 1); const colWidth = panelDim[0] / pivotColumnGroups.size; const colHeight = panelDim[1] - max_text; @@ -129,7 +124,7 @@ export function computePivotLayout( } const docMap = new Map(); - const groupNames: PivotData[] = []; + const groupNames: ViewDefBounds[] = []; const expander = 1.05; const gap = .15; @@ -146,9 +141,10 @@ export function computePivotLayout( y: pivotAxisWidth, width: pivotAxisWidth * expander * numCols, height: max_text, - fontSize + fontSize, + payload: val }); - for (const doc of val) { + for (const doc of val.docs) { const layoutDoc = Doc.Layout(doc); let wid = pivotAxisWidth; let hgt = layoutDoc._nativeWidth ? (NumCast(layoutDoc._nativeHeight) / NumCast(layoutDoc._nativeWidth)) * pivotAxisWidth : pivotAxisWidth; @@ -157,10 +153,12 @@ export function computePivotLayout( wid = layoutDoc._nativeHeight ? (NumCast(layoutDoc._nativeWidth) / NumCast(layoutDoc._nativeHeight)) * pivotAxisWidth : pivotAxisWidth; } docMap.set(doc, { - x: x + xCount * pivotAxisWidth * expander + (pivotAxisWidth - wid) / 2 + (val.length < numCols ? (numCols - val.length) * pivotAxisWidth / 2 : 0), + type: "doc", + x: x + xCount * pivotAxisWidth * expander + (pivotAxisWidth - wid) / 2 + (val.docs.length < numCols ? (numCols - val.docs.length) * pivotAxisWidth / 2 : 0), y: -y + (pivotAxisWidth - hgt) / 2, width: wid, - height: hgt + height: hgt, + payload: undefined }); xCount++; if (xCount >= numCols) { @@ -172,12 +170,15 @@ export function computePivotLayout( }); const maxColHeight = pivotAxisWidth * expander * Math.ceil(maxInColumn / numCols); - const dividers = Array.from(pivotColumnGroups.values()).map((pg, i) => - ({ type: "div", color: "lightGray", x: i * pivotAxisWidth * (numCols * expander + gap), y: -maxColHeight + pivotAxisWidth, width: pivotAxisWidth * numCols * expander, height: maxColHeight } as any)); + const dividers = Array.from(pivotColumnGroups.values()).map((pkey, i) => + ({ type: "div", color: "lightGray", x: i * pivotAxisWidth * (numCols * expander + gap), y: -maxColHeight + pivotAxisWidth, width: pivotAxisWidth * numCols * expander, height: maxColHeight, payload: pkey.filters })); groupNames.push(...dividers); return normalizeResults(panelDim, max_text, childPairs, docMap, poolData, viewDefsToJSX, groupNames, 0, []); } +function toNumber(val: FieldResult) { + return val === undefined ? undefined : NumCast(val, Number(StrCast(val))); +} export function computeTimelineLayout( poolData: Map, @@ -190,9 +191,9 @@ export function computeTimelineLayout( const fieldKey = "data"; const pivotDateGroups = new Map(); const docMap = new Map(); - const groupNames: PivotData[] = []; + const groupNames: ViewDefBounds[] = []; const timelineFieldKey = Field.toString(pivotDoc._pivotField as Field); - const curTime = Cast(pivotDoc[fieldKey + "-timelineCur"], "number", null); + const curTime = toNumber(pivotDoc[fieldKey + "-timelineCur"]); const curTimeSpan = Cast(pivotDoc[fieldKey + "-timelineSpan"], "number", null); const minTimeReq = curTime === undefined ? Cast(pivotDoc[fieldKey + "-timelineMinReq"], "number", null) : curTimeSpan && (curTime - curTimeSpan); const maxTimeReq = curTime === undefined ? Cast(pivotDoc[fieldKey + "-timelineMaxReq"], "number", null) : curTimeSpan && (curTime + curTimeSpan); @@ -237,10 +238,10 @@ export function computeTimelineLayout( let prevKey = Math.floor(minTime); if (sortedKeys.length && scaling * (sortedKeys[0] - prevKey) > 25) { - groupNames.push({ type: "text", text: prevKey.toString(), x: x, y: 0, height: fontHeight, fontSize }); + groupNames.push({ type: "text", text: prevKey.toString(), x: x, y: 0, height: fontHeight, fontSize, payload: undefined }); } if (!sortedKeys.length && curTime !== undefined) { - groupNames.push({ type: "text", text: curTime.toString(), x: (curTime - minTime) * scaling, zIndex: 1000, color: "orange", y: 0, height: fontHeight, fontSize }); + groupNames.push({ type: "text", text: curTime.toString(), x: (curTime - minTime) * scaling, zIndex: 1000, color: "orange", y: 0, height: fontHeight, fontSize, payload: undefined }); } const pivotAxisWidth = NumCast(pivotDoc.pivotTimeWidth, panelDim[1] / 2.5); @@ -248,21 +249,23 @@ export function computeTimelineLayout( let zind = 0; sortedKeys.forEach(key => { if (curTime !== undefined && curTime > prevKey && curTime <= key) { - groupNames.push({ type: "text", text: curTime.toString(), x: (curTime - minTime) * scaling, y: 0, zIndex: 1000, color: "orange", height: fontHeight, fontSize }); + groupNames.push({ type: "text", text: curTime.toString(), x: (curTime - minTime) * scaling, y: 0, zIndex: 1000, color: "orange", height: fontHeight, fontSize, payload: key }); } const keyDocs = pivotDateGroups.get(key)!; x += scaling * (key - prevKey); const stack = findStack(x, stacking); prevKey = key; - !stack && (curTime === undefined || Math.abs(x - (curTime - minTime) * scaling) > pivotAxisWidth) && groupNames.push({ type: "text", text: key.toString(), x: x, y: stack * 25, height: fontHeight, fontSize }); + if (!stack && (curTime === undefined || Math.abs(x - (curTime - minTime) * scaling) > pivotAxisWidth)) { + groupNames.push({ type: "text", text: key.toString(), x: x, y: stack * 25, height: fontHeight, fontSize, payload: undefined }); + } layoutDocsAtTime(keyDocs, key); }); - if (sortedKeys.length && curTime > sortedKeys[sortedKeys.length - 1]) { + if (sortedKeys.length && curTime !== undefined && curTime > sortedKeys[sortedKeys.length - 1]) { x = (curTime - minTime) * scaling; - groupNames.push({ type: "text", text: curTime.toString(), x: x, y: 0, zIndex: 1000, color: "orange", height: fontHeight, fontSize }); + groupNames.push({ type: "text", text: curTime.toString(), x: x, y: 0, zIndex: 1000, color: "orange", height: fontHeight, fontSize, payload: undefined }); } if (Math.ceil(maxTime - minTime) * scaling > x + 25) { - groupNames.push({ type: "text", text: Math.ceil(maxTime).toString(), x: Math.ceil(maxTime - minTime) * scaling, y: 0, height: fontHeight, fontSize }); + groupNames.push({ type: "text", text: Math.ceil(maxTime).toString(), x: Math.ceil(maxTime - minTime) * scaling, y: 0, height: fontHeight, fontSize, payload: undefined }); } const divider = { type: "div", color: "black", x: 0, y: 0, width: panelDim[0], height: 1 } as any; @@ -279,8 +282,9 @@ export function computeTimelineLayout( wid = layoutDoc._nativeHeight ? (NumCast(layoutDoc._nativeWidth) / NumCast(layoutDoc._nativeHeight)) * pivotAxisWidth : pivotAxisWidth; } docMap.set(doc, { + type: "doc", x: x, y: -Math.sqrt(stack) * pivotAxisWidth / 2 - pivotAxisWidth + (pivotAxisWidth - hgt) / 2, - zIndex: (curTime === key ? 1000 : zind++), highlight: curTime === key, width: wid / (Math.max(stack, 1)), height: hgt + zIndex: (curTime === key ? 1000 : zind++), highlight: curTime === key, width: wid / (Math.max(stack, 1)), height: hgt, payload: undefined }); stacking[stack] = x + pivotAxisWidth; }); @@ -288,10 +292,10 @@ export function computeTimelineLayout( } function normalizeResults(panelDim: number[], fontHeight: number, childPairs: { data?: Doc, layout: Doc }[], docMap: Map, - poolData: Map, viewDefsToJSX: (views: any) => ViewDefResult[], groupNames: PivotData[], minWidth: number, extras: PivotData[]) { + poolData: Map, viewDefsToJSX: (views: any) => ViewDefResult[], groupNames: ViewDefBounds[], minWidth: number, extras: ViewDefBounds[]) { - const grpEles = groupNames.map(gn => ({ x: gn.x, y: gn.y, width: gn.width, height: gn.height }) as PivotData); - const docEles = childPairs.filter(d => docMap.get(d.layout)).map(pair => docMap.get(pair.layout) as PivotData); + const grpEles = groupNames.map(gn => ({ x: gn.x, y: gn.y, width: gn.width, height: gn.height }) as ViewDefBounds); + const docEles = childPairs.filter(d => docMap.get(d.layout)).map(pair => docMap.get(pair.layout) as ViewDefBounds); const aggBounds = aggregateBounds(docEles.concat(grpEles), 0, 0); aggBounds.r = Math.max(minWidth, aggBounds.r - aggBounds.x); const wscale = panelDim[0] / (aggBounds.r - aggBounds.x); @@ -323,7 +327,8 @@ function normalizeResults(panelDim: number[], fontHeight: number, childPairs: { color: gname.color, width: gname.width === undefined ? undefined : gname.width * scale, height: Math.max(fontHeight, (gname.height || 0) * scale), - fontSize: gname.fontSize + fontSize: gname.fontSize, + payload: gname.payload })))) }; } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 54c45e43a..a34779046 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -32,7 +32,7 @@ import { FormattedTextBox } from "../../nodes/FormattedTextBox"; import { pageSchema } from "../../nodes/ImageBox"; import PDFMenu from "../../pdf/PDFMenu"; import { CollectionSubView } from "../CollectionSubView"; -import { computePivotLayout, ViewDefResult, computeTimelineLayout, PoolData } from "./CollectionFreeFormLayoutEngines"; +import { computePivotLayout, ViewDefResult, computeTimelineLayout, PoolData, ViewDefBounds } from "./CollectionFreeFormLayoutEngines"; import { CollectionFreeFormRemoteCursors } from "./CollectionFreeFormRemoteCursors"; import "./CollectionFreeFormView.scss"; import MarqueeOptionsMenu from "./MarqueeOptionsMenu"; @@ -747,11 +747,14 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { }; } - viewDefsToJSX = (views: any[]) => { + viewDefsToJSX = (views: ViewDefBounds[]) => { return !Array.isArray(views) ? [] : views.filter(ele => this.viewDefToJSX(ele)).map(ele => this.viewDefToJSX(ele)!); } - private viewDefToJSX(viewDef: any): Opt { + onViewDefDivClick = (e: React.MouseEvent, payload: any) => { + (this.props.Document.onViewDefDivClick as ScriptField)?.script.run({ this: this.props.Document, payload }); + } + private viewDefToJSX(viewDef: ViewDefBounds): Opt { const x = Cast(viewDef.x, "number"); const y = Cast(viewDef.y, "number"); const z = Cast(viewDef.z, "number"); @@ -769,15 +772,15 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { style={{ width, height, color, fontSize, transform: `translate(${x}px, ${y}px)` }}> {text}
, - bounds: { x: x!, y: y!, z, zIndex, width, height } + bounds: viewDef }; } else if (viewDef.type === "div") { const backgroundColor = Cast(viewDef.color, "string"); return [x, y].some(val => val === undefined) ? undefined : { - ele:
this.onViewDefDivClick(e, viewDef)} style={{ width, height, backgroundColor, transform: `translate(${x}px, ${y}px)` }} />, - bounds: { x: x!, y: y!, z, zIndex, width, height } + bounds: viewDef }; } } diff --git a/src/client/views/nodes/PresBox.tsx b/src/client/views/nodes/PresBox.tsx index be5d414a5..6c4cbba12 100644 --- a/src/client/views/nodes/PresBox.tsx +++ b/src/client/views/nodes/PresBox.tsx @@ -360,7 +360,7 @@ export class PresBox extends React.Component { const funcs: ContextMenuProps[] = []; funcs.push({ description: "Show as Slideshow", event: action(() => this.props.Document._slideshow = "slideshow"), icon: "asterisk" }); funcs.push({ description: "Show as Timeline", event: action(() => this.props.Document._slideshow = "timeline"), icon: "asterisk" }); - funcs.push({ description: "Show as List", event: action(() => this.props.Document._slideshow = "list"), icon: "asterisk" }); + funcs.push({ description: "Show as List", event: action(() => this.props.Document._slideshow = undefined), icon: "asterisk" }); ContextMenu.Instance.addItem({ description: "Presentation Funcs...", subitems: funcs, icon: "asterisk" }); } diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index 6ae02720c..92b1fb090 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -791,6 +791,21 @@ export namespace Doc { if (StrCast(doc.title).endsWith("_" + prevLayout)) doc.title = StrCast(doc.title).replace("_" + prevLayout, ""); doc.layoutKey = deiconify || "layout"; } + export function setDocFilter(container: Doc, key: string, value: any, modifiers?: string) { + const docFilters = Cast(container._docFilter, 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 (modifiers !== undefined) { + docFilters.push(key); + docFilters.push(value); + docFilters.push(modifiers); + container._docFilter = new List(docFilters); + } + } } Scripting.addGlobal(function renameAlias(doc: any, n: any) { return StrCast(Doc.GetProto(doc).title).replace(/\([0-9]*\)/, "") + `(${n})`; }); @@ -815,18 +830,4 @@ Scripting.addGlobal(function selectedDocs(container: Doc, excludeCollections: bo const docs = DocListCast(Doc.UserDoc().SelectedDocs).filter(d => !Doc.AreProtosEqual(d, container) && !d.annotationOn && d.type !== DocumentType.DOCUMENT && d.type !== DocumentType.KVP && (!excludeCollections || !Cast(d.data, listSpec(Doc), null))); return docs.length ? new List(docs) : prevValue; }); -Scripting.addGlobal(function setDocFilter(container: Doc, key: string, value: any, modifiers?: string) { - const docFilters = Cast(container._docFilter, 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 (modifiers !== undefined) { - docFilters.push(key); - docFilters.push(value); - docFilters.push(modifiers); - container._docFilter = new List(docFilters); - } -}); \ No newline at end of file +Scripting.addGlobal(function setDocFilter(container: Doc, key: string, value: any, modifiers?: string) { Doc.setDocFilter(container, key, value, modifiers); }); \ No newline at end of file diff --git a/src/new_fields/util.ts b/src/new_fields/util.ts index 3495a934d..45ec676b2 100644 --- a/src/new_fields/util.ts +++ b/src/new_fields/util.ts @@ -101,7 +101,7 @@ export function makeEditable() { } let layoutProps = ["panX", "panY", "width", "height", "nativeWidth", "nativeHeight", "fitWidth", "fitToBox", - "LODdisable", "dropAction", "chromeStatus", "viewType", "gridGap", "xMargin", "yMargin", "autoHeight"]; + "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" && -- cgit v1.2.3-70-g09d2 From 8597134b6ada1e57ae08d49e24c00d11f728ba90 Mon Sep 17 00:00:00 2001 From: bob Date: Thu, 6 Feb 2020 16:04:04 -0500 Subject: restored isBackground for documents that don't want to respond to anything. --- src/client/util/DragManager.ts | 4 ++-- .../views/collections/collectionFreeForm/CollectionFreeFormView.tsx | 1 + src/client/views/nodes/CollectionFreeFormDocumentView.tsx | 1 + src/client/views/nodes/ImageBox.scss | 5 ++--- src/client/views/nodes/ImageBox.tsx | 3 ++- 5 files changed, 8 insertions(+), 6 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index b0dd90947..e572f0fcb 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -15,7 +15,7 @@ import { listSpec } from "../../new_fields/Schema"; import { Scripting } from "./Scripting"; import { convertDropDataToButtons } from "./DropConverter"; -export type dropActionType = "alias" | "copy" | "move" | undefined; +export type dropActionType = "alias" | "copy" | undefined; export function SetupDrag( _reference: React.RefObject, docFunc: () => Doc | Promise | undefined, @@ -198,7 +198,7 @@ export namespace DragManager { ); e.docDragData?.droppedDocuments.forEach((drop: Doc, i: number) => Cast(dragData.draggedDocuments[i].removeDropProperties, listSpec("string"), []).map(prop => { - drop[prop] = "move"; + drop[prop] = undefined; }) ); }; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 1ac0d28f5..f2c4cda34 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -126,6 +126,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { @undoBatch @action drop = (e: Event, de: DragManager.DropEvent) => { + if (this.props.Document.isBackground) return false; const xf = this.getTransform(); const xfo = this.getTransformOverlay(); const [xp, yp] = xf.transformPoint(de.x, de.y); diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 2a11267d4..f484b6115 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -88,6 +88,7 @@ export class CollectionFreeFormDocumentView extends DocComponent {!this.props.fitToBox ? Date: Fri, 7 Feb 2020 01:22:48 -0500 Subject: sped up pivot viewer by not recreating docs when pivot changes. --- .../views/collections/CollectionStackingView.tsx | 6 ++-- .../CollectionStackingViewFieldColumn.tsx | 2 +- src/client/views/collections/CollectionSubView.tsx | 29 +--------------- .../views/collections/CollectionTimeView.scss | 5 +++ .../views/collections/CollectionTimeView.tsx | 39 +++++++++++++++------- .../CollectionFreeFormLayoutEngines.tsx | 20 ++++++----- .../collectionFreeForm/CollectionFreeFormView.tsx | 37 +++++++++++++++++--- .../views/nodes/CollectionFreeFormDocumentView.tsx | 1 + 8 files changed, 83 insertions(+), 56 deletions(-) (limited to 'src/client/views/nodes') diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index 01a2f1042..e04f4e8a6 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -52,11 +52,11 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { } @computed get NodeWidth() { return this.props.PanelWidth() - this.gridGap; } - children(docs: Doc[]) { + children(docs: Doc[], columns?: number) { this._docXfs.length = 0; return docs.map((d, i) => { const height = () => this.getDocHeight(d); - const width = () => (this.widthScale ? this.widthScale : 1) * Math.min(d._nativeWidth && !d.ignoreAspect && !this.props.Document.fillColumn ? d[WidthSym]() : Number.MAX_VALUE, this.columnWidth / this.numGroupColumns); + const width = () => (this.widthScale && !columns ? this.widthScale : 1) * Math.min(d._nativeWidth && !d.ignoreAspect && !this.props.Document.fillColumn ? d[WidthSym]() : Number.MAX_VALUE, this.columnWidth / this.numGroupColumns); const dref = React.createRef(); const dxf = () => this.getDocTransform(d, dref.current!); this._docXfs.push({ dxf: dxf, width: width, height: height }); @@ -381,7 +381,7 @@ export class CollectionStackingView extends CollectionSubView(doc => doc) { return Math.min(this.props.Document[WidthSym]() / this.props.PanelWidth(), this.props.Document[HeightSym]() / this.props.PanelHeight()); } @computed get widthScale() { - return StrCast(this.props.Document.title).includes("slide") ? this.heightScale : undefined; + return StrCast(this.props.Document.title).includes("slide") || true ? this.heightScale : undefined; } render() { TraceMobx(); diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx index b81b1f31d..21982f1ca 100644 --- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx +++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx @@ -407,7 +407,7 @@ export class CollectionStackingViewFieldColumn extends React.Component - {this.props.parent.children(this.props.docList)} + {this.props.parent.children(this.props.docList, uniqueHeadings.length)} {singleColumn ? (null) : this.props.parent.columnDragger}
{(chromeStatus !== 'view-mode' && chromeStatus !== 'disabled') ? diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index a2700e75a..e0e99d635 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -111,34 +111,7 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T) { get childDocs() { const docs = DocListCast(this.dataField); const viewSpecScript = Cast(this.props.Document.viewSpecScript, ScriptField); - const viewedDocs = viewSpecScript ? docs.filter(d => viewSpecScript.script.run({ doc: d }, console.log).result) : docs; - const docFilters = Cast(this.props.Document._docFilter, listSpec("string"), []); - const clusters: { [key: string]: { [value: string]: string } } = {}; - for (let i = 0; i < docFilters.length; i += 3) { - const [key, value, modifiers] = docFilters.slice(i, i + 3); - const cluster = clusters[key]; - if (!cluster) { - const child: { [value: string]: string } = {}; - child[value] = modifiers; - clusters[key] = child; - } else { - cluster[value] = modifiers; - } - } - const filteredDocs = docFilters.length ? viewedDocs.filter(d => { - for (const key of Object.keys(clusters)) { - const cluster = clusters[key]; - const satisfiesFacet = Object.keys(cluster).some(inner => { - const modifier = cluster[inner]; - return (modifier === "x") !== Doc.matchFieldValue(d, key, inner); - }); - if (!satisfiesFacet) { - return false; - } - } - return true; - }) : viewedDocs; - return filteredDocs; + return viewSpecScript ? docs.filter(d => viewSpecScript.script.run({ doc: d }, console.log).result) : docs; } @action diff --git a/src/client/views/collections/CollectionTimeView.scss b/src/client/views/collections/CollectionTimeView.scss index df5057b5b..a5ce73a92 100644 --- a/src/client/views/collections/CollectionTimeView.scss +++ b/src/client/views/collections/CollectionTimeView.scss @@ -5,6 +5,11 @@ height: 100%; width: 100%; overflow: hidden; + .collectionTimeView-backBtn { + background: green; + display: inline; + margin-right: 20px; + } .collectionFreeform-customText { text-align: left; } diff --git a/src/client/views/collections/CollectionTimeView.tsx b/src/client/views/collections/CollectionTimeView.tsx index fb36a1b0c..0c1f93829 100644 --- a/src/client/views/collections/CollectionTimeView.tsx +++ b/src/client/views/collections/CollectionTimeView.tsx @@ -1,27 +1,27 @@ import { faEdit } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { action, computed, IReactionDisposer, observable, trace } from "mobx"; +import { action, computed, observable, trace } from "mobx"; import { observer } from "mobx-react"; import { Set } from "typescript-collections"; -import { Doc, DocListCast } from "../../../new_fields/Doc"; +import { Doc, DocListCast, Field } 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, StrCast, NumCast } from "../../../new_fields/Types"; +import { Cast, NumCast, StrCast } from "../../../new_fields/Types"; import { Docs } from "../../documents/Documents"; +import { Scripting } from "../../util/Scripting"; +import { ContextMenu } from "../ContextMenu"; +import { ContextMenuProps } from "../ContextMenuItem"; import { EditableView } from "../EditableView"; import { anchorPoints, Flyout } from "../TemplateMenu"; +import { ViewDefBounds } from "./collectionFreeForm/CollectionFreeFormLayoutEngines"; import { CollectionFreeFormView } from "./collectionFreeForm/CollectionFreeFormView"; -import "./CollectionTimeView.scss"; import { CollectionSubView } from "./CollectionSubView"; -import { CollectionTreeView } from "./CollectionTreeView"; +import "./CollectionTimeView.scss"; import React = require("react"); -import { ContextMenu } from "../ContextMenu"; -import { ContextMenuProps } from "../ContextMenuItem"; -import { RichTextField } from "../../../new_fields/RichTextField"; -import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils"; -import { Scripting } from "../../util/Scripting"; -import { ViewDefResult, ViewDefBounds } from "./collectionFreeForm/CollectionFreeFormLayoutEngines"; +import { CollectionTreeView } from "./CollectionTreeView"; +import { ObjectField } from "../../../new_fields/ObjectField"; @observer export class CollectionTimeView extends CollectionSubView(doc => doc) { @@ -289,7 +289,19 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) {
- + +
{!this.props.isSelected() || this.props.PanelHeight() < 100 ? (null) :
@@ -308,6 +320,9 @@ export class CollectionTimeView extends CollectionSubView(doc => doc) { } Scripting.addGlobal(function pivotColumnClick(pivotDoc: Doc, bounds: ViewDefBounds) { + let pfilterIndex = NumCast(pivotDoc._pfilterIndex); + pivotDoc["_pfilter" + pfilterIndex] = ObjectField.MakeCopy(pivotDoc._docFilter as ObjectField); + pivotDoc._pfilterIndex = ++pfilterIndex; pivotDoc._docFilter = new List(); (bounds.payload as string[]).map(filterVal => Doc.setDocFilter(pivotDoc, StrCast(pivotDoc._pivotField), filterVal, "check")); diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx index e354ad0af..95f7794bb 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx @@ -36,7 +36,6 @@ export interface PoolData { color?: string, transition?: string, highlight?: boolean, - state?: any } export interface ViewDefResult { @@ -71,19 +70,21 @@ interface pivotColumn { filters: string[] } + export function computePivotLayout( poolData: Map, pivotDoc: Doc, childDocs: Doc[], + filterDocs: Doc[], childPairs: { layout: Doc, data?: Doc }[], panelDim: number[], - viewDefsToJSX: (views: any) => ViewDefResult[] + viewDefsToJSX: (views: ViewDefBounds[]) => ViewDefResult[] ) { const fieldKey = "data"; const pivotColumnGroups = new Map, pivotColumn>(); const pivotFieldKey = toLabel(pivotDoc._pivotField); - for (const doc of childDocs) { + for (const doc of filterDocs) { const val = Field.toString(doc[pivotFieldKey] as Field); if (val) { !pivotColumnGroups.get(val) && pivotColumnGroups.set(val, { docs: [], filters: [val] }); @@ -179,7 +180,7 @@ export function computePivotLayout( const dividers = sortedPivotKeys.map((key, i) => ({ type: "div", color: "lightGray", x: i * pivotAxisWidth * (numCols * expander + gap), y: -maxColHeight + pivotAxisWidth, width: pivotAxisWidth * numCols * expander, height: maxColHeight, payload: pivotColumnGroups.get(key)!.filters })); groupNames.push(...dividers); - return normalizeResults(panelDim, max_text, childPairs, docMap, poolData, viewDefsToJSX, groupNames, 0, []); + return normalizeResults(panelDim, max_text, childPairs, docMap, poolData, viewDefsToJSX, groupNames, 0, [], childDocs.filter(c => !filterDocs.includes(c))); } function toNumber(val: FieldResult) { @@ -190,9 +191,10 @@ export function computeTimelineLayout( poolData: Map, pivotDoc: Doc, childDocs: Doc[], + filterDocs: Doc[], childPairs: { layout: Doc, data?: Doc }[], panelDim: number[], - viewDefsToJSX: (views: ViewDefBounds) => ViewDefResult[] + viewDefsToJSX: (views: ViewDefBounds[]) => ViewDefResult[] ) { const fieldKey = "data"; const pivotDateGroups = new Map(); @@ -212,7 +214,7 @@ export function computeTimelineLayout( let minTime = Number.MAX_VALUE; let maxTime = -Number.MAX_VALUE; - childDocs.map(doc => { + filterDocs.map(doc => { const num = NumCast(doc[timelineFieldKey], Number(StrCast(doc[timelineFieldKey]))); if (!(Number.isNaN(num) || (minTimeReq && num < minTimeReq) || (maxTimeReq && num > maxTimeReq))) { !pivotDateGroups.get(num) && pivotDateGroups.set(num, []); @@ -275,7 +277,7 @@ export function computeTimelineLayout( } const divider = { type: "div", color: "black", x: 0, y: 0, width: panelDim[0], height: 1, payload: undefined }; - return normalizeResults(panelDim, fontHeight, childPairs, docMap, poolData, viewDefsToJSX, groupNames, (maxTime - minTime) * scaling, [divider]); + return normalizeResults(panelDim, fontHeight, childPairs, docMap, poolData, viewDefsToJSX, groupNames, (maxTime - minTime) * scaling, [divider], childDocs.filter(c => !filterDocs.includes(c))); function layoutDocsAtTime(keyDocs: Doc[], key: number) { keyDocs.forEach(doc => { @@ -298,7 +300,8 @@ export function computeTimelineLayout( } function normalizeResults(panelDim: number[], fontHeight: number, childPairs: { data?: Doc, layout: Doc }[], docMap: Map, - poolData: Map, viewDefsToJSX: (views: ViewDefBounds) => ViewDefResult[], groupNames: ViewDefBounds[], minWidth: number, extras: ViewDefBounds[]) { + poolData: Map, viewDefsToJSX: (views: ViewDefBounds[]) => ViewDefResult[], groupNames: ViewDefBounds[], minWidth: number, extras: ViewDefBounds[], + extraDocs: Doc[]) { const grpEles = groupNames.map(gn => ({ x: gn.x, y: gn.y, width: gn.width, height: gn.height }) as ViewDefBounds); const docEles = childPairs.filter(d => docMap.get(d.layout)).map(pair => docMap.get(pair.layout) as ViewDefBounds); @@ -323,6 +326,7 @@ function normalizeResults(panelDim: number[], fontHeight: number, childPairs: { poolData.set(pair.layout[Id], { transition: "transform 1s", ...newPos }); } }); + extraDocs.map(ed => poolData.set(ed[Id], { x: 0, y: 0, zIndex: -99 })); return { elements: viewDefsToJSX(extras.concat(groupNames.map(gname => ({ diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index ea3805b65..2518a4a55 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -7,7 +7,7 @@ import { Doc, DocListCast, HeightSym, Opt, WidthSym, DocListCastAsync, Field } f import { documentSchema, positionSchema } from "../../../../new_fields/documentSchemas"; import { Id } from "../../../../new_fields/FieldSymbols"; import { InkTool, InkField, InkData } from "../../../../new_fields/InkField"; -import { createSchema, makeInterface } from "../../../../new_fields/Schema"; +import { createSchema, makeInterface, listSpec } from "../../../../new_fields/Schema"; import { ScriptField } from "../../../../new_fields/ScriptField"; import { BoolCast, Cast, DateCast, NumCast, StrCast, ScriptCast } from "../../../../new_fields/Types"; import { CurrentUserUtils } from "../../../../server/authentication/models/current_user_utils"; @@ -794,12 +794,12 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { }.bind(this)); doTimelineLayout(poolData: Map) { - return computeTimelineLayout(poolData, this.props.Document, this.childDocs, + return computeTimelineLayout(poolData, this.props.Document, this.childDocs, this.filterDocs, this.childLayoutPairs, [this.props.PanelWidth(), this.props.PanelHeight()], this.viewDefsToJSX); } doPivotLayout(poolData: Map) { - return computePivotLayout(poolData, this.props.Document, this.childDocs, + return computePivotLayout(poolData, this.props.Document, this.childDocs, this.filterDocs, this.childLayoutPairs, [this.props.PanelWidth(), this.props.PanelHeight()], this.viewDefsToJSX); } @@ -812,7 +812,6 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { this.childLayoutPairs.filter(pair => this.isCurrent(pair.layout)).map((pair, i) => { const pos = this.getCalculatedPositions({ doc: pair.layout, index: i, collection: this.Document, docs: layoutDocs, state }); - state = pos.state === undefined ? state : pos.state; poolData.set(pair.layout[Id], pos); }); return { elements: elements }; @@ -826,6 +825,36 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { } return { newPool, computedElementData: this.doFreeformLayout(newPool) }; } + + @computed get filterDocs() { + const docFilters = Cast(this.props.Document._docFilter, listSpec("string"), []); + const clusters: { [key: string]: { [value: string]: string } } = {}; + for (let i = 0; i < docFilters.length; i += 3) { + const [key, value, modifiers] = docFilters.slice(i, i + 3); + const cluster = clusters[key]; + if (!cluster) { + const child: { [value: string]: string } = {}; + child[value] = modifiers; + clusters[key] = child; + } else { + cluster[value] = modifiers; + } + } + const filteredDocs = docFilters.length ? this.childDocs.filter(d => { + for (const key of Object.keys(clusters)) { + const cluster = clusters[key]; + const satisfiesFacet = Object.keys(cluster).some(inner => { + const modifier = cluster[inner]; + return (modifier === "x") !== Doc.matchFieldValue(d, key, inner); + }); + if (!satisfiesFacet) { + return false; + } + } + return true; + }) : this.childDocs; + return filteredDocs; + } get doLayoutComputation() { const { newPool, computedElementData } = this.doInternalLayoutComputation; runInAction(() => diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index f484b6115..3bceec45f 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -88,6 +88,7 @@ export class CollectionFreeFormDocumentView extends DocComponent -- cgit v1.2.3-70-g09d2