From 0d263dba422a96c5d22f29a9b6411ff074c92645 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Sat, 25 Jan 2020 17:28:57 -0500 Subject: added carousel view --- .../views/collections/CollectionCarouselView.tsx | 62 ++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 src/client/views/collections/CollectionCarouselView.tsx (limited to 'src/client/views/collections/CollectionCarouselView.tsx') diff --git a/src/client/views/collections/CollectionCarouselView.tsx b/src/client/views/collections/CollectionCarouselView.tsx new file mode 100644 index 000000000..f2cc2479f --- /dev/null +++ b/src/client/views/collections/CollectionCarouselView.tsx @@ -0,0 +1,62 @@ +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { observable } from 'mobx'; +import { observer } from 'mobx-react'; +import * as React from 'react'; +import { documentSchema } from '../../../new_fields/documentSchemas'; +import { makeInterface } from '../../../new_fields/Schema'; +import { NumCast } from '../../../new_fields/Types'; +import { DragManager } from '../../util/DragManager'; +import { ContentFittingDocumentView } from '../nodes/ContentFittingDocumentView'; +import "./CollectionCarouselView.scss"; +import { CollectionSubView } from './CollectionSubView'; +import { faCaretLeft, faCaretRight } from '@fortawesome/free-solid-svg-icons'; +import { Doc } from '../../../new_fields/Doc'; + + + + +type CarouselDocument = makeInterface<[typeof documentSchema,]>; +const CarouselDocument = makeInterface(documentSchema); + +@observer +export class CollectionCarouselView extends CollectionSubView(CarouselDocument) { + @observable public addMenuToggle = React.createRef(); + private _dropDisposer?: DragManager.DragDropDisposer; + + componentWillUnmount() { + this._dropDisposer && this._dropDisposer(); + } + + componentDidMount() { + } + protected createDashEventsTarget = (ele: HTMLDivElement) => { //used for stacking and masonry view + this._dropDisposer && this._dropDisposer(); + if (ele) { + this._dropDisposer = DragManager.MakeDropTarget(ele, this.drop.bind(this)); + } + } + + render() { + const index = NumCast(this.layoutDoc._itemIndex); + return !(this.childLayoutPairs?.[index]?.layout instanceof Doc) ? (null) : +
+ +
this.layoutDoc._itemIndex = (index - 1 + this.childLayoutPairs.length) % this.childLayoutPairs.length}> + +
+
this.layoutDoc._itemIndex = (index + 1) % this.childLayoutPairs.length}> + +
+
; + } +} \ No newline at end of file -- cgit v1.2.3-70-g09d2 From 5e67aa8ab95e40730acb584cb5ff812fe470608f Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Mon, 27 Jan 2020 17:32:47 -0500 Subject: template fixes --- src/client/util/DropConverter.ts | 8 +- src/client/util/RichTextRules.ts | 62 +++++++------- src/client/util/RichTextSchema.tsx | 97 +++++++++++++--------- src/client/views/DocComponent.tsx | 4 +- .../views/collections/CollectionCarouselView.tsx | 4 +- src/client/views/nodes/FieldView.tsx | 6 +- src/client/views/nodes/FormattedTextBox.tsx | 2 +- 7 files changed, 104 insertions(+), 79 deletions(-) (limited to 'src/client/views/collections/CollectionCarouselView.tsx') diff --git a/src/client/util/DropConverter.ts b/src/client/util/DropConverter.ts index 9c068d2d7..8d92de28f 100644 --- a/src/client/util/DropConverter.ts +++ b/src/client/util/DropConverter.ts @@ -4,7 +4,9 @@ import { DocumentType } from "../documents/DocumentTypes"; import { ObjectField } from "../../new_fields/ObjectField"; import { StrCast } from "../../new_fields/Types"; import { Docs } from "../documents/Documents"; -import { ScriptField } from "../../new_fields/ScriptField"; +import { ScriptField, ComputedField } from "../../new_fields/ScriptField"; +import { RichTextField } from "../../new_fields/RichTextField"; +import { Compute } from "google-auth-library"; export function makeTemplate(doc: Doc): boolean { const layoutDoc = doc.layout instanceof Doc && doc.layout.isTemplateForField ? doc.layout : doc; @@ -18,6 +20,10 @@ export function makeTemplate(doc: Doc): boolean { Doc.MakeMetadataFieldTemplate(d, Doc.GetProto(layoutDoc)); } else if (d.type === DocumentType.COL) { any = makeTemplate(d) || any; + } else if (d.data instanceof RichTextField) { + d._textTemplate = ComputedField.MakeFunction("copyField(this.data)", { this: Doc.name }); + d.isTemplateForField = "data"; + any = true; } }); return any; diff --git a/src/client/util/RichTextRules.ts b/src/client/util/RichTextRules.ts index bc8a0abb1..0de0e21fd 100644 --- a/src/client/util/RichTextRules.ts +++ b/src/client/util/RichTextRules.ts @@ -2,14 +2,15 @@ import { textblockTypeInputRule, smartQuotes, emDash, ellipsis, InputRule } from import { schema } from "./RichTextSchema"; import { wrappingInputRule } from "./prosemirrorPatches"; import { NodeSelection, TextSelection } from "prosemirror-state"; -import { StrCast, Cast } from "../../new_fields/Types"; -import { Doc } from "../../new_fields/Doc"; +import { StrCast, Cast, NumCast } from "../../new_fields/Types"; +import { Doc, DataSym } from "../../new_fields/Doc"; import { FormattedTextBox } from "../views/nodes/FormattedTextBox"; import { Docs, DocUtils } from "../documents/Documents"; import { Id } from "../../new_fields/FieldSymbols"; import { DocServer } from "../DocServer"; import { returnFalse, Utils } from "../../Utils"; import RichTextMenu from "./RichTextMenu"; +import { RichTextField } from "../../new_fields/RichTextField"; export const inpRules = { rules: [ @@ -70,36 +71,26 @@ export const inpRules = { return state.tr.deleteRange(start, end).addStoredMark(schema.marks.pFontSize.create({ fontSize: size })); }), - // make current selection a hyperlink portal (assumes % was used to initiate an EnteringStyle mode) + // create a text display of a metadata field new InputRule( - new RegExp(/!$/), + new RegExp(/\[\[([a-zA-Z_ \-0-9]+)\]\]$/), (state, match, start, end) => { - if (state.selection.to === state.selection.from || !(schema as any).EnteringStyle) return null; - const value = state.doc.textBetween(start, end); - - const node = (state.doc.resolve(start) as any).nodeAfter; - const sm = state.storedMarks || undefined; - const fieldView = state.schema.nodes.dashField.create({ fieldKey: StrCast(value) }); - const replaced = node ? state.tr.replaceRangeWith(start, end, fieldView).setStoredMarks([...node.marks, ...(sm ? sm : [])]) : state.tr; - return replaced.doc.nodeSize > end - 2 ? replaced.setSelection(new TextSelection(replaced.doc.resolve(end - 2))) : replaced; + const fieldKey = match[1]; + const fieldView = state.schema.nodes.dashField.create({ fieldKey: StrCast(fieldKey) }); + return state.tr.deleteRange(start, end).insert(start, fieldView); }), - // make current selection a hyperlink portal (assumes % was used to initiate an EnteringStyle mode) + // create a hyperlink portal new InputRule( - new RegExp(/@$/), + new RegExp(/\[\[:([a-zA-Z_ \-0-9]+)\]\]$/), (state, match, start, end) => { - if (state.selection.to === state.selection.from || !(schema as any).EnteringStyle) return null; - - const value = state.doc.textBetween(start, end); - if (value) { - DocServer.GetRefField(value).then(docx => { - const target = ((docx instanceof Doc) && docx) || Docs.Create.FreeformDocument([], { title: value, _width: 500, _height: 500, }, value); - DocUtils.Publish(target, value, returnFalse, returnFalse); - DocUtils.MakeLink({ doc: (schema as any).Document }, { doc: target }, "portal link", ""); - }); - const link = state.schema.marks.link.create({ href: Utils.prepend("/doc/" + value), location: "onRight", title: value, targetId: value }); - return state.tr.addMark(start, end, link); - } - return state.tr; + const docId = match[1].substring(1); + DocServer.GetRefField(docId).then(docx => { + const target = ((docx instanceof Doc) && docx) || Docs.Create.FreeformDocument([], { title: docId, _width: 500, _height: 500, }, 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.addMark(start, end, link); }), // stop using active style new InputRule( @@ -209,10 +200,21 @@ export const inpRules = { new InputRule( new RegExp(/%#$/), (state, match, start, end) => { - const target = Docs.Create.TextDocument("", { _width: 75, _height: 35, backgroundColor: "yellow", annotationOn: FormattedTextBox.FocusedBox!.dataDoc, _autoHeight: true, fontSize: 9, title: "inline comment" }); + const textDoc = Doc.GetProto(Cast((schema as any).Document[DataSym], Doc, null)!); + const numInlines = NumCast(textDoc.inlineTextCount); + textDoc.inlineTextCount = numInlines + 1; + const inlineFieldKey = "inline" + numInlines; + const textDocInline = Docs.Create.TextDocument("", { _width: 75, _height: 35, backgroundColor: "yellow", annotationOn: textDoc, _autoHeight: true, fontSize: 9, title: "inline comment" }); + textDocInline.layoutKey = "layout_" + inlineFieldKey; + textDocInline.customTitle = true; + textDocInline.title = "inline"; + textDocInline.isTemplateForField = inlineFieldKey; + textDocInline.proto = textDoc; + textDoc[textDocInline.layoutKey] = FormattedTextBox.LayoutString(inlineFieldKey); + textDoc[inlineFieldKey] = "-inline-"; const node = (state.doc.resolve(start) as any).nodeAfter; - const newNode = schema.nodes.dashComment.create({ docid: target[Id] }); - const dashDoc = schema.nodes.dashDoc.create({ width: 75, height: 35, title: "dashDoc", docid: target[Id], float: "right" }); + const newNode = schema.nodes.dashComment.create({ docid: textDocInline[Id] }); + const dashDoc = schema.nodes.dashDoc.create({ width: 75, height: 35, title: "dashDoc", docid: textDocInline[Id], float: "right" }); const sm = state.storedMarks || undefined; const replaced = node ? state.tr.insert(start, newNode).replaceRangeWith(start + 1, end + 1, dashDoc).insertText(" ", start + 2).setStoredMarks([...node.marks, ...(sm ? sm : [])]) : state.tr; diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx index 21916e3d6..0deedbe39 100644 --- a/src/client/util/RichTextSchema.tsx +++ b/src/client/util/RichTextSchema.tsx @@ -18,6 +18,7 @@ import { Transform } from "./Transform"; import React = require("react"); import { BoolCast, NumCast, StrCast } from "../../new_fields/Types"; import { FormattedTextBox } from "../views/nodes/FormattedTextBox"; +import { ObjectField } from "../../new_fields/ObjectField"; const blockquoteDOM: DOMOutputSpecArray = ["blockquote", 0], hrDOM: DOMOutputSpecArray = ["hr"], preDOM: DOMOutputSpecArray = ["pre", ["code", 0]], brDOM: DOMOutputSpecArray = ["br"], ulDOM: DOMOutputSpecArray = ["ul", 0]; @@ -682,7 +683,7 @@ export class DashDocCommentView { if (target) { const expand = target.hidden; const tr = view.state.tr.setNodeMarkup(target.pos, undefined, { ...target.node.attrs, hidden: target.node.attrs.hidden ? false : true }); - view.dispatch(tr.setSelection(TextSelection.create(tr.doc, getPos() + (expand ? 2 : 1)))); // update the attrs + view.dispatch(tr.setSelection(TextSelection.create(tr.doc, getPos() + (expand ? 2 : 1)))); // update the attrs setTimeout(() => { expand && DocServer.GetRefField(node.attrs.docid).then(async dashDoc => dashDoc instanceof Doc && Doc.linkFollowHighlight(dashDoc)); try { view.dispatch(view.state.tr.setSelection(TextSelection.create(view.state.tr.doc, getPos() + (expand ? 2 : 1)))); } catch (e) { } @@ -734,12 +735,6 @@ export class DashDocView { this._dashSpan.style.height = node.attrs.height; this._dashSpan.style.position = "absolute"; this._dashSpan.style.display = "inline-block"; - const removeDoc = () => { - const pos = getPos(); - const ns = new NodeSelection(view.state.doc.resolve(pos)); - view.dispatch(view.state.tr.setSelection(ns).deleteSelection()); - return true; - }; this._dashSpan.onpointerleave = () => { const ele = document.getElementById("DashDocCommentView-" + node.attrs.docid); if (ele) { @@ -752,46 +747,24 @@ export class DashDocView { (ele as HTMLDivElement).style.backgroundColor = "orange"; } }; + const removeDoc = () => { + const pos = getPos(); + const ns = new NodeSelection(view.state.doc.resolve(pos)); + view.dispatch(view.state.tr.setSelection(ns).deleteSelection()); + return true; + }; DocServer.GetRefField(node.attrs.docid).then(async dashDoc => { if (dashDoc instanceof Doc) { self._dashDoc = dashDoc; dashDoc.hideSidebar = true; - if (node.attrs.width !== dashDoc.width + "px" || node.attrs.height !== dashDoc.height + "px") { + if (node.attrs.width !== dashDoc._width + "px" || node.attrs.height !== dashDoc._height + "px") { try { // bcz: an exception will be thrown if two aliases are open at the same time when a doc view comment is made - view.dispatch(view.state.tr.setNodeMarkup(getPos(), null, { ...node.attrs, width: dashDoc.width + "px", height: dashDoc.height + "px" })); + view.dispatch(view.state.tr.setNodeMarkup(getPos(), null, { ...node.attrs, width: dashDoc._width + "px", height: dashDoc._height + "px" })); } catch (e) { console.log(e); } } - this._reactionDisposer && this._reactionDisposer(); - this._reactionDisposer = reaction(() => dashDoc[HeightSym]() + dashDoc[WidthSym](), () => { - this._dashSpan.style.height = this._outer.style.height = dashDoc[HeightSym]() + "px"; - this._dashSpan.style.width = this._outer.style.width = dashDoc[WidthSym]() + "px"; - }); - ReactDOM.render(, this._dashSpan); + self.doRender(dashDoc, removeDoc); } }); const self = this; @@ -807,6 +780,49 @@ export class DashDocView { this._outer.appendChild(this._dashSpan); (this as any).dom = this._outer; } + doRender(dashDoc: Doc, removeDoc: any) { + const self = this; + const finalLayout = Doc.expandTemplateLayout(dashDoc, this._textBox.dataDoc); + if (!finalLayout) setTimeout(() => self.doRender(dashDoc, removeDoc), 0); + else { + const layoutKey = StrCast(finalLayout.layoutKey); + const finalKey = layoutKey && StrCast(finalLayout[layoutKey]).split("'")?.[1]; + if (finalLayout !== dashDoc && finalKey) { + const finalLayoutField = finalLayout[finalKey] + finalLayoutField instanceof ObjectField && (finalLayout._textTemplate = ObjectField.MakeCopy(finalLayoutField)); + } + this._reactionDisposer && this._reactionDisposer(); + this._reactionDisposer = reaction(() => [finalLayout[WidthSym](), finalLayout[HeightSym]()], (dim) => { + this._dashSpan.style.width = this._outer.style.width = dim[0] + "px"; + this._dashSpan.style.height = this._outer.style.height = dim[1] + "px"; + }, { fireImmediately: true }); + ReactDOM.render(, this._dashSpan); + } + } destroy() { this._reactionDisposer && this._reactionDisposer(); } @@ -837,8 +853,9 @@ export class DashFieldView { this._labelSpan.style.fontWeight = "bold"; this._labelSpan.style.fontSize = "larger"; this._labelSpan.innerHTML = `${node.attrs.fieldKey}: `; + const ddoc = tbox.props.DataDoc || tbox.dataDoc; this._reactionDisposer && this._reactionDisposer(); - this._reactionDisposer = reaction(() => this._textBoxDoc[DataSym][node.attrs.fieldKey], fval => this._fieldSpan.innerHTML = Field.toString(fval as Field), { fireImmediately: true }); + this._reactionDisposer = reaction(() => ddoc[node.attrs.fieldKey], fval => this._fieldSpan.innerHTML = Field.toString(fval as Field), { fireImmediately: true }); this._fieldWrapper.appendChild(this._labelSpan); this._fieldWrapper.appendChild(this._fieldSpan); (this as any).dom = this._fieldWrapper; @@ -1012,7 +1029,7 @@ export class SummaryView { view.dispatch(view.state.tr. setSelection(textSelection). // select the current summarized text (or where it will be if its collapsed) replaceSelection(!visible ? new Slice(Fragment.fromArray([]), 0, 0) : node.attrs.text). // collapse/expand it - setNodeMarkup(getPos(), undefined, attrs)); // update the attrs + setNodeMarkup(getPos(), undefined, attrs)); // update the attrs e.preventDefault(); e.stopPropagation(); this._collapsed.className = this.className(visible); diff --git a/src/client/views/DocComponent.tsx b/src/client/views/DocComponent.tsx index d98301cf6..a31997a10 100644 --- a/src/client/views/DocComponent.tsx +++ b/src/client/views/DocComponent.tsx @@ -34,7 +34,7 @@ export function DocExtendableComponent

(schemaCt //TODO This might be pretty inefficient if doc isn't observed, because computed doesn't cache then @computed get Document(): T { return schemaCtor(this.props.Document); } @computed get layoutDoc() { return Doc.Layout(this.props.Document); } - @computed get dataDoc() { return (this.props.DataDoc && (this.props.Document.isTemplateForField || this.props.Document.isTemplateDoc) ? this.props.DataDoc : Doc.GetProto(this.props.Document)) as Doc; } + @computed get dataDoc() { return (this.props.DataDoc && (this.props.Document.isTemplateForField || this.props.Document.isTemplateDoc) ? this.props.DataDoc : Cast(this.props.Document.resolvedDataDoc, Doc, null) || Doc.GetProto(this.props.Document)) as Doc; } active = (outsideReaction?: boolean) => !this.props.Document.isBackground && (this.props.Document.forceActive || this.props.isSelected(outsideReaction) || this.props.renderDepth === 0);// && !InkingControl.Instance.selectedTool; // bcz: inking state shouldn't affect static tools } return Component; @@ -57,7 +57,7 @@ export function DocAnnotatableComponent

(schema //TODO This might be pretty inefficient if doc isn't observed, because computed doesn't cache then @computed get Document(): T { return schemaCtor(this.props.Document); } @computed get layoutDoc() { return Doc.Layout(this.props.Document); } - @computed get dataDoc() { return (this.props.DataDoc && (this.props.Document.isTemplateForField || this.props.Document.isTemplateDoc) ? this.props.DataDoc : Doc.GetProto(this.props.Document)) as Doc; } + @computed get dataDoc() { return (this.props.DataDoc && (this.props.Document.isTemplateForField || this.props.Document.isTemplateDoc) ? this.props.DataDoc : Cast(this.props.Document.resolvedDataDoc, Doc, null) || Doc.GetProto(this.props.Document)) as Doc; } _annotationKey: string = "annotations"; public set annotationKey(val: string) { this._annotationKey = val; } diff --git a/src/client/views/collections/CollectionCarouselView.tsx b/src/client/views/collections/CollectionCarouselView.tsx index f2cc2479f..9f32bb0c9 100644 --- a/src/client/views/collections/CollectionCarouselView.tsx +++ b/src/client/views/collections/CollectionCarouselView.tsx @@ -45,13 +45,13 @@ export class CollectionCarouselView extends CollectionSubView(CarouselDocument) Document={this.childLayoutPairs[index].layout} DataDocument={this.childLayoutPairs[index].data} getTransform={this.props.ScreenToLocalTransform} /> -

this.layoutDoc._itemIndex = (index - 1 + this.childLayoutPairs.length) % this.childLayoutPairs.length}> +
{ e.stopPropagation(); this.layoutDoc._itemIndex = (index - 1 + this.childLayoutPairs.length) % this.childLayoutPairs.length }}>
-
this.layoutDoc._itemIndex = (index + 1) % this.childLayoutPairs.length}> +
{ e.stopPropagation(); this.layoutDoc._itemIndex = (index + 1) % this.childLayoutPairs.length }}> { // if (typeof field === "string") { // return

{field}

; // } - else if (field instanceof RichTextField) { - return ; - } + // else if (field instanceof RichTextField) { + // return ; + // } else if (field instanceof ImageField) { return ; } diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index fab267358..5c9f1a754 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -496,7 +496,7 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps & this._reactionDisposer = reaction( () => { - const field = this.dataDoc ? Cast(this.dataDoc[this.props.fieldKey], RichTextField) : undefined; + const field = Cast(this.props.Document._textTemplate || this.dataDoc[this.props.fieldKey], RichTextField); return field ? field.Data : RichTextUtils.Initialize(); }, incomingValue => { -- cgit v1.2.3-70-g09d2 From d1ed73e0a0fa3f3da9811edfe3233c663d34cffa Mon Sep 17 00:00:00 2001 From: bob Date: Tue, 28 Jan 2020 15:15:47 -0500 Subject: functional child templates for Buxton view --- .../views/collections/CollectionCarouselView.tsx | 52 ++++++++++------- .../views/collections/CollectionPivotView.tsx | 66 +++++++--------------- .../CollectionStackingViewFieldColumn.tsx | 1 + .../views/nodes/CollectionFreeFormDocumentView.tsx | 1 + src/new_fields/Doc.ts | 4 ++ 5 files changed, 58 insertions(+), 66 deletions(-) (limited to 'src/client/views/collections/CollectionCarouselView.tsx') diff --git a/src/client/views/collections/CollectionCarouselView.tsx b/src/client/views/collections/CollectionCarouselView.tsx index 9f32bb0c9..815dfb35a 100644 --- a/src/client/views/collections/CollectionCarouselView.tsx +++ b/src/client/views/collections/CollectionCarouselView.tsx @@ -1,5 +1,5 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { observable } from 'mobx'; +import { observable, computed } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; import { documentSchema } from '../../../new_fields/documentSchemas'; @@ -36,27 +36,37 @@ export class CollectionCarouselView extends CollectionSubView(CarouselDocument) } } - render() { + advance = (e: React.MouseEvent) => { + e.stopPropagation(); + this.layoutDoc._itemIndex = (NumCast(this.layoutDoc._itemIndex) + 1) % this.childLayoutPairs.length; + } + goback = (e: React.MouseEvent) => { + e.stopPropagation(); + this.layoutDoc._itemIndex = (NumCast(this.layoutDoc._itemIndex) - 1 + this.childLayoutPairs.length) % this.childLayoutPairs.length; + } + + @computed get content() { const index = NumCast(this.layoutDoc._itemIndex); return !(this.childLayoutPairs?.[index]?.layout instanceof Doc) ? (null) : -
- -
{ e.stopPropagation(); this.layoutDoc._itemIndex = (index - 1 + this.childLayoutPairs.length) % this.childLayoutPairs.length }}> - -
-
{ e.stopPropagation(); this.layoutDoc._itemIndex = (index + 1) % this.childLayoutPairs.length }}> - -
-
; + + } + @computed get buttons() { + return <> +
+ +
+
+ +
+ ; + } + render() { + return
+ {this.content} + {this.buttons} +
; } } \ No newline at end of file diff --git a/src/client/views/collections/CollectionPivotView.tsx b/src/client/views/collections/CollectionPivotView.tsx index 98fc54b3b..66c7c9745 100644 --- a/src/client/views/collections/CollectionPivotView.tsx +++ b/src/client/views/collections/CollectionPivotView.tsx @@ -1,61 +1,37 @@ -import { CollectionSubView } from "./CollectionSubView"; -import React = require("react"); -import { computed, action, IReactionDisposer, reaction, runInAction, observable } from "mobx"; -import { faEdit, faChevronCircleUp } from "@fortawesome/free-solid-svg-icons"; -import { Doc, DocListCast, Field, DocCastAsync } from "../../../new_fields/Doc"; -import "./CollectionPivotView.scss"; -import { observer } from "mobx-react"; -import { CollectionFreeFormView } from "./collectionFreeForm/CollectionFreeFormView"; -import { CollectionTreeView } from "./CollectionTreeView"; -import { Cast, StrCast, NumCast } from "../../../new_fields/Types"; -import { Docs } from "../../documents/Documents"; -import { ScriptField, ComputedField } from "../../../new_fields/ScriptField"; -import { CompileScript, Scripting } from "../../util/Scripting"; -import { anchorPoints, Flyout } from "../TemplateMenu"; +import { faEdit } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { List } from "../../../new_fields/List"; +import { action, computed, IReactionDisposer, observable } from "mobx"; +import { observer } from "mobx-react"; import { Set } from "typescript-collections"; -import { PrefetchProxy } from "../../../new_fields/Proxy"; -import { EditableView } from "../EditableView"; +import { Doc, DocListCast } from "../../../new_fields/Doc"; +import { List } from "../../../new_fields/List"; import { listSpec } from "../../../new_fields/Schema"; +import { ComputedField, ScriptField } from "../../../new_fields/ScriptField"; +import { Cast, StrCast } from "../../../new_fields/Types"; +import { Docs } from "../../documents/Documents"; +import { CompileScript } from "../../util/Scripting"; +import { EditableView } from "../EditableView"; +import { anchorPoints, Flyout } from "../TemplateMenu"; +import { CollectionFreeFormView } from "./collectionFreeForm/CollectionFreeFormView"; +import "./CollectionPivotView.scss"; +import { CollectionSubView } from "./CollectionSubView"; +import { CollectionTreeView } from "./CollectionTreeView"; +import React = require("react"); @observer export class CollectionPivotView extends CollectionSubView(doc => doc) { - private _narrativeDisposer: IReactionDisposer | undefined; - componentWillUnmount() { - this._narrativeDisposer?.(); - } componentDidMount() { this.props.Document._freeformLayoutEngine = "pivot"; + const childDetailed = this.props.Document.childDetailed; // bcz: needs to be here to make sure the childDetailed layout template has been loaded when the first item is clicked; if (!this.props.Document._facetCollection) { const facetCollection = Docs.Create.TreeDocument([], { title: "facetFilters", _yMargin: 0, treeViewHideTitle: true }); facetCollection.target = this.props.Document; - this.props.Document.excludeFields = new List(["_facetCollection", "_docFilter", "viewSpecScript"]); + this.props.Document.excludeFields = new List(["_facetCollection", "_docFilter"]); const scriptText = "setDocFilter(containingTreeView.target, heading, this.title, checked)"; - const script = CompileScript(scriptText, { - params: { this: Doc.name, heading: "boolean", checked: "boolean", containingTreeView: Doc.name }, - typecheck: false, - editable: true, - }); - if (script.compiled) { - facetCollection.onCheckedClick = new ScriptField(script); - } - const openDocText = "const alias = getAlias(this); Doc.ApplyTemplateTo(childDetailed, alias, 'layout_detailed'); useRightSplit(alias); "; - this._narrativeDisposer = reaction(() => DocCastAsync(this.props.Document.childDetailed), - (childDetailedPromise) => childDetailedPromise.then(childDetailed => { - if (childDetailed) { - const openDocScript = CompileScript(openDocText, { - params: { this: Doc.name, heading: "boolean", containingTreeView: Doc.name }, - capturedVariables: { childDetailed: new PrefetchProxy(childDetailed) }, - typecheck: false, - editable: true, - }); - if (openDocScript.compiled) { - this.props.Document.onChildClick = new ScriptField(openDocScript); - } - } - }), { fireImmediately: true }); + const childText = "const alias = getAlias(this); Doc.ApplyTemplateTo(containingCollection.childDetailed, alias, 'layout_detailed'); useRightSplit(alias); "; + 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 }); this.props.Document._facetCollection = facetCollection; this.props.Document._fitToBox = true; } diff --git a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx index 6a6f7aa6d..9cd9c1465 100644 --- a/src/client/views/collections/CollectionStackingViewFieldColumn.tsx +++ b/src/client/views/collections/CollectionStackingViewFieldColumn.tsx @@ -283,6 +283,7 @@ export class CollectionStackingViewFieldColumn extends React.Component this.props.parent.props.addDocument(Docs.Create.FreeformDocument([], { _width: 200, _height: 200, _LODdisable: true })), icon: "compress-arrows-alt" }); + layoutItems.push({ description: ":carousel", event: () => this.props.parent.props.addDocument(Docs.Create.CarouselDocument([], { _width: 400, _height: 200, _LODdisable: true })), icon: "compress-arrows-alt" }); layoutItems.push({ description: ":columns", event: () => this.props.parent.props.addDocument(Docs.Create.MulticolumnDocument([], { _width: 200, _height: 200 })), icon: "compress-arrows-alt" }); layoutItems.push({ description: ":image", event: () => this.props.parent.props.addDocument(Docs.Create.ImageDocument("http://www.cs.brown.edu/~bcz/face.gif", { _width: 200, _height: 200 })), icon: "compress-arrows-alt" }); diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index ea3c505d8..846d402ab 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -114,6 +114,7 @@ export class CollectionFreeFormDocumentView extends DocComponent : d instanceof Doc && MakeMetadataFieldTemplate(d, templateDoc)); (Doc.GetProto(templateField)[metadataFieldKey] = ObjectField.MakeCopy(templateField.data)); } + if (templateField.data instanceof RichTextField && templateField.data.Data) { + templateField._textTemplate = ObjectField.MakeCopy(templateField.data); + } // get the layout string that the template uses to specify its layout const templateFieldLayoutString = StrCast(Doc.LayoutField(Doc.Layout(templateField))); -- cgit v1.2.3-70-g09d2 From 0361c04360362c31e4bdd5d27b52707b4e288662 Mon Sep 17 00:00:00 2001 From: bob Date: Tue, 28 Jan 2020 18:14:59 -0500 Subject: added captions to carousel. cleaned up some stuff. --- src/client/documents/Documents.ts | 7 +++- src/client/util/RichTextSchema.tsx | 2 +- .../views/collections/CollectionCarouselView.scss | 12 ++++++ .../views/collections/CollectionCarouselView.tsx | 24 ++++++++---- .../views/collections/CollectionDockingView.tsx | 44 +++++++++++++++++++++- .../views/collections/CollectionPivotView.tsx | 5 +-- src/client/views/collections/CollectionSubView.tsx | 6 +-- .../views/collections/CollectionTreeView.tsx | 44 ++++++++++++---------- src/client/views/nodes/FormattedTextBox.tsx | 4 +- src/scraping/buxton/scraper.py | 20 ++++------ 10 files changed, 116 insertions(+), 52 deletions(-) (limited to 'src/client/views/collections/CollectionCarouselView.tsx') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index a7f939d7d..e481b1a4a 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -74,7 +74,8 @@ export interface DocumentOptions { _xMargin?: number; // gap between left edge of document and start of masonry/stacking layouts _yMargin?: number; // gap between top edge of dcoument and start of masonry/stacking layouts _textTemplate?: RichTextField; // template used by a formattedTextBox to create a text box to render - _itemIndex?: number; + _itemIndex?: number; // which item index the carousel viewer is showing + _hideSidebar?: boolean; //whether an annotationsidebar should be displayed for text docuemnts x?: number; y?: number; z?: number; @@ -127,6 +128,7 @@ export interface DocumentOptions { color?: string; treeViewHideTitle?: boolean; // whether to hide the title of a tree view treeViewOpen?: boolean; // whether this document is expanded in a tree view + treeViewChecked?: ScriptField; // script to call when a tree view checkbox is checked isFacetFilter?: boolean; // whether document functions as a facet filter in a tree view limitHeight?: number; // maximum height for newly created (eg, from pasting) text documents // [key: string]: Opt; @@ -336,7 +338,8 @@ export namespace Docs { */ export namespace Create { - const delegateKeys = ["x", "y", "_width", "_height", "_panX", "_panY", "_viewType", "_nativeWidth", "_nativeHeight", "_dropAction", "_annotationOn", "_chromeStatus", "_forceActive", "_autoHeight", "_fitWidth", "_LODdisable", "_itemIndex"]; + const delegateKeys = ["x", "y", "_width", "_height", "_panX", "_panY", "_viewType", "_nativeWidth", "_nativeHeight", "_dropAction", "_annotationOn", + "_chromeStatus", "_forceActive", "_autoHeight", "_fitWidth", "_LODdisable", "_itemIndex", "_hideSidebar"]; /** * This function receives the relevant document prototype and uses diff --git a/src/client/util/RichTextSchema.tsx b/src/client/util/RichTextSchema.tsx index 7051ba1c3..f667b86af 100644 --- a/src/client/util/RichTextSchema.tsx +++ b/src/client/util/RichTextSchema.tsx @@ -757,7 +757,7 @@ export class DashDocView { DocServer.GetRefField(node.attrs.docid).then(async dashDoc => { if (dashDoc instanceof Doc) { self._dashDoc = dashDoc; - dashDoc.hideSidebar = true; + dashDoc._hideSidebar = true; if (node.attrs.width !== dashDoc._width + "px" || node.attrs.height !== dashDoc._height + "px") { try { // bcz: an exception will be thrown if two aliases are open at the same time when a doc view comment is made view.dispatch(view.state.tr.setNodeMarkup(getPos(), null, { ...node.attrs, width: dashDoc._width + "px", height: dashDoc._height + "px" })); diff --git a/src/client/views/collections/CollectionCarouselView.scss b/src/client/views/collections/CollectionCarouselView.scss index 2e0e293b8..4815f1a59 100644 --- a/src/client/views/collections/CollectionCarouselView.scss +++ b/src/client/views/collections/CollectionCarouselView.scss @@ -1,6 +1,18 @@ .collectionCarouselView-outer { background: gray; + .collectionCarouselView-caption { + margin-left: 10%; + margin-right: 10%; + height: 50; + display: inline-block; + width: 80%; + } + .collectionCarouselView-image { + height: calc(100% - 50px); + display: inline-block; + width: 100%; + } } .carouselView-back { position: absolute; diff --git a/src/client/views/collections/CollectionCarouselView.tsx b/src/client/views/collections/CollectionCarouselView.tsx index 815dfb35a..0933d5924 100644 --- a/src/client/views/collections/CollectionCarouselView.tsx +++ b/src/client/views/collections/CollectionCarouselView.tsx @@ -4,13 +4,14 @@ import { observer } from 'mobx-react'; import * as React from 'react'; import { documentSchema } from '../../../new_fields/documentSchemas'; import { makeInterface } from '../../../new_fields/Schema'; -import { NumCast } from '../../../new_fields/Types'; +import { NumCast, StrCast } from '../../../new_fields/Types'; import { DragManager } from '../../util/DragManager'; import { ContentFittingDocumentView } from '../nodes/ContentFittingDocumentView'; import "./CollectionCarouselView.scss"; import { CollectionSubView } from './CollectionSubView'; import { faCaretLeft, faCaretRight } from '@fortawesome/free-solid-svg-icons'; import { Doc } from '../../../new_fields/Doc'; +import { FormattedTextBox } from '../nodes/FormattedTextBox'; @@ -45,20 +46,29 @@ export class CollectionCarouselView extends CollectionSubView(CarouselDocument) this.layoutDoc._itemIndex = (NumCast(this.layoutDoc._itemIndex) - 1 + this.childLayoutPairs.length) % this.childLayoutPairs.length; } + panelHeight = () => this.props.PanelHeight() - 50; @computed get content() { const index = NumCast(this.layoutDoc._itemIndex); return !(this.childLayoutPairs?.[index]?.layout instanceof Doc) ? (null) : - +
+
+ +
+
+ +
+
} @computed get buttons() { return <> -
+
-
+
; diff --git a/src/client/views/collections/CollectionDockingView.tsx b/src/client/views/collections/CollectionDockingView.tsx index 8cfaa5951..160279efd 100644 --- a/src/client/views/collections/CollectionDockingView.tsx +++ b/src/client/views/collections/CollectionDockingView.tsx @@ -174,6 +174,45 @@ export class CollectionDockingView extends React.Component { + if (child.contentItems.length === 1 && child.contentItems[0].config.component === "DocumentFrameRenderer" && + DocumentManager.Instance.getDocumentViewById(child.contentItems[0].config.props.documentId)?.Document.isDisplayPanle) { + child.contentItems[0].remove(); + child.addChild(newContentItem, undefined, true); + instance.layoutChanged(document); + return true; + } else { + Array.from(child.contentItems).filter((tab: any) => tab.config.component === "DocumentFrameRenderer").some((tab: any, j: number) => { + if (DocumentManager.Instance.getDocumentViewById(tab.config.props.documentId)?.Document.isDisplayPanel) { + child.contentItems[j].remove(); + child.addChild(newContentItem, undefined, true); + return true; + } + return false; + }); + } + return false; + }); + } + if (retVal) { + instance.stateChanged(); + } + return retVal; + } + // // Creates a vertical split on the right side of the docking view, and then adds the Document to the right of that split @@ -217,8 +256,9 @@ export class CollectionDockingView extends React.Component doc) { const flyout = (
{this._allFacets.map(facet => )} diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 321a6d34c..65d421c52 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -70,10 +70,10 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T) { (args) => { const childLayout = Cast(this.props.Document.childLayout, Doc); if (childLayout instanceof Doc) { - this.childDocs.map(doc => Doc.ApplyTemplateTo(childLayout, doc, "layoutFromParent")); + this.childDocs.map(doc => Doc.ApplyTemplateTo(childLayout, doc, "layout_fromParent")); } else if (!(childLayout instanceof Promise)) { - this.childDocs.filter(d => !d.isTemplateForField).map(doc => doc.layoutKey === "layoutFromParent" && (doc.layoutKey = "layout")); + this.childDocs.filter(d => !d.isTemplateForField).map(doc => doc.layoutKey === "layout_fromParent" && (doc.layoutKey = "layout")); } }, { fireImmediately: true }); @@ -183,7 +183,7 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T) { if (docDragData && !docDragData.applyAsTemplate) { if (de.altKey && docDragData.draggedDocuments.length) { this.childDocs.map(doc => - Doc.ApplyTemplateTo(docDragData.draggedDocuments[0], doc, "layoutFromParent")); + Doc.ApplyTemplateTo(docDragData.draggedDocuments[0], doc, "layout_fromParent")); e.stopPropagation(); return true; } diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 6927f2856..66055d31d 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -34,6 +34,7 @@ import "./CollectionTreeView.scss"; import React = require("react"); import { CollectionViewType } from './CollectionView'; import { RichTextField } from '../../../new_fields/RichTextField'; +import { ObjectField } from '../../../new_fields/ObjectField'; export interface TreeViewProps { @@ -629,13 +630,23 @@ export class CollectionTreeView extends CollectionSubView(Document) { } ContextMenu.Instance.addItem({ description: "Buxton Layout", icon: "eye", event: () => { - const { TextDocument, ImageDocument, MulticolumnDocument, TreeDocument, CarouselDocument } = Docs.Create; + DocListCast(this.dataDoc[this.props.fieldKey]).map(d => { + DocListCast(d.data).map((img, i) => { + const caption = (d.captions as any)[i]?.data; + if (caption instanceof ObjectField) { + Doc.GetProto(img).caption = ObjectField.MakeCopy(caption as ObjectField); + } + img._hideSidebar = true; + d.captions = undefined; + }); + }); + const { TextDocument, ImageDocument, CarouselDocument } = 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 detailedLayout = Docs.Create.StackingDocument([ - CarouselDocument([], { title: "data", _height: 350, _itemIndex: 0 }), + CarouselDocument([], { title: "data", _height: 350, _itemIndex: 0, backgroundColor: "#9b9b9b3F" }), TextDocument("", { title: "details", _autoHeight: true, _textTemplate: new RichTextField(detailedTemplate, "short_description year company") }) ], { _chromeStatus: "disabled", title: "detailed layout stack" }); detailedLayout.isTemplateDoc = makeTemplate(detailedLayout); @@ -711,23 +722,18 @@ export class CollectionTreeView extends CollectionSubView(Document) { } Scripting.addGlobal(function readFacetData(layoutDoc: Doc, dataDoc: Doc, dataKey: string, facetHeader: string) { - const facetValues = new Set(); - DocListCast(dataDoc[dataKey]).forEach(child => { - Object.keys(Doc.GetProto(child)).forEach(key => child[key] instanceof Doc && facetValues.add((child[key] as Doc)[facetHeader]?.toString() || "(null)")); - facetValues.add(Field.toString(child[facetHeader] as Field)); - }); - const text = "determineCheckedState(layoutDoc, facetHeader, facetValue)"; - const params = { - layoutDoc: Doc.name, - facetHeader: "string", - facetValue: "string" - }; - const capturedVariables = { layoutDoc, facetHeader }; - return new List(Array.from(facetValues).sort().map(facetValue => { - const value = Docs.Create.TextDocument("", { title: facetValue.toString() }); - value.treeViewChecked = ComputedField.MakeFunction(text, params, { ...capturedVariables, facetValue }); - return value; - })); + const allCollectionDocs = DocListCast(dataDoc[dataKey]); + const facetValues = Array.from(allCollectionDocs.reduce((set, child) => + set.add(Field.toString(child[facetHeader] as Field)), new Set())); + + const facetValueDocSet = facetValues.sort().map(facetValue => + Docs.Create.TextDocument("", { + title: facetValue.toString(), + treeViewChecked: ComputedField.MakeFunction("determineCheckedState(layoutDoc, facetHeader, facetValue)", + { layoutDoc: Doc.name, facetHeader: "string", facetValue: "string" }, + { layoutDoc, facetHeader, facetValue }) + })); + return new List(facetValueDocSet); }); Scripting.addGlobal(function determineCheckedState(layoutDoc: Doc, facetHeader: string, facetValue: string) { diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 5c9f1a754..732bbc976 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -1099,7 +1099,7 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps &
- {this.props.Document.hideSidebar ? (null) : this.sidebarWidthPercent === "0%" ? + {this.props.Document._hideSidebar ? (null) : this.sidebarWidthPercent === "0%" ?
this.toggleSidebar()} /> :
@@ -1116,7 +1116,7 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps & whenActiveChanged={this.whenActiveChanged} removeDocument={this.removeDocument} moveDocument={this.moveDocument} - addDocument={(doc: Doc) => { doc.hideSidebar = true; return this.addDocument(doc); }} + addDocument={(doc: Doc) => { doc._hideSidebar = true; return this.addDocument(doc); }} CollectionView={undefined} ScreenToLocalTransform={() => this.props.ScreenToLocalTransform().translate(-(this.props.PanelWidth() - this.sidebarWidth), 0)} renderDepth={this.props.renderDepth + 1} diff --git a/src/scraping/buxton/scraper.py b/src/scraping/buxton/scraper.py index 16b248ae7..7cfa4696d 100644 --- a/src/scraping/buxton/scraper.py +++ b/src/scraping/buxton/scraper.py @@ -112,10 +112,6 @@ def write_collection(parse_results, display_fields, storage_key, viewType): "url": parse_results["image_urls"][0], "__type": "image" } - fields["activeHero"] = { - "url": parse_results["image_urls"][0], - "__type": "image" - } fields["isPrototype"] = True fields["page"] = -1 @@ -139,7 +135,7 @@ def write_text_doc(content): "proto": protofy(data_doc_guid), "x": 10, "y": 10, - "width": 400, + "_width": 400, "zIndex": 2 }, "__type": "Doc" @@ -154,7 +150,7 @@ def write_text_doc(content): "__type": "RichTextField" }, "title": content, - "nativeWidth": 200, + "_nativeWidth": 200, "author": "Bill Buxton", "creationDate": { "date": datetime.datetime.utcnow().microsecond, @@ -163,8 +159,8 @@ def write_text_doc(content): "isPrototype": True, "_autoHeight": True, "page": -1, - "nativeHeight": 200, - "height": 200, + "_nativeHeight": 200, + "_height": 200, "data_text": content }, "__type": "Doc" @@ -194,7 +190,7 @@ def write_image(folder, name): "proto": protofy(data_doc_guid), "x": 10, "y": 10, - "width": min(800, native_width), + "_width": min(800, native_width), "zIndex": 2, "widthUnit": "*", "widthMagnitude": 1 @@ -211,7 +207,7 @@ def write_image(folder, name): "__type": "image" }, "title": name, - "nativeWidth": native_width, + "_nativeWidth": native_width, "author": "Bill Buxton", "creationDate": { "date": datetime.datetime.utcnow().microsecond, @@ -219,8 +215,8 @@ def write_image(folder, name): }, "isPrototype": True, "page": -1, - "nativeHeight": native_height, - "height": native_height + "_nativeHeight": native_height, + "_height": native_height }, "__type": "Doc" } -- cgit v1.2.3-70-g09d2 From 5ff28653b90dde7b97b757794bc1f4ae5ee0f6c4 Mon Sep 17 00:00:00 2001 From: bob Date: Tue, 4 Feb 2020 18:59:58 -0500 Subject: small carousel/tree fixes. --- src/client/views/collections/CollectionCarouselView.tsx | 2 +- src/client/views/collections/CollectionTreeView.tsx | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'src/client/views/collections/CollectionCarouselView.tsx') diff --git a/src/client/views/collections/CollectionCarouselView.tsx b/src/client/views/collections/CollectionCarouselView.tsx index 0933d5924..e30d08592 100644 --- a/src/client/views/collections/CollectionCarouselView.tsx +++ b/src/client/views/collections/CollectionCarouselView.tsx @@ -74,7 +74,7 @@ export class CollectionCarouselView extends CollectionSubView(CarouselDocument) ; } render() { - return
+ return
{this.content} {this.buttons}
; diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 631870866..9e3fb1d67 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -626,6 +626,7 @@ export class CollectionTreeView extends CollectionSubView(Document) { const layoutItems: ContextMenuProps[] = []; layoutItems.push({ description: (this.props.Document.preventTreeViewOpen ? "Persist" : "Abandon") + "Treeview State", event: () => this.props.Document.preventTreeViewOpen = !this.props.Document.preventTreeViewOpen, icon: "paint-brush" }); layoutItems.push({ description: (this.props.Document.hideHeaderFields ? "Show" : "Hide") + " Header Fields", event: () => this.props.Document.hideHeaderFields = !this.props.Document.hideHeaderFields, icon: "paint-brush" }); + layoutItems.push({ description: (this.props.Document.treeViewHideTitle ? "Show" : "Hide") + " Title", event: () => this.props.Document.treeViewHideTitle = !this.props.Document.treeViewHideTitle, icon: "paint-brush" }); ContextMenu.Instance.addItem({ description: "Treeview Options ...", subitems: layoutItems, icon: "eye" }); } ContextMenu.Instance.addItem({ -- 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/collections/CollectionCarouselView.tsx') 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