diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/client/documents/Documents.ts | 7 | ||||
-rw-r--r-- | src/client/util/RichTextSchema.tsx | 2 | ||||
-rw-r--r-- | src/client/views/collections/CollectionCarouselView.scss | 12 | ||||
-rw-r--r-- | src/client/views/collections/CollectionCarouselView.tsx | 24 | ||||
-rw-r--r-- | src/client/views/collections/CollectionDockingView.tsx | 44 | ||||
-rw-r--r-- | src/client/views/collections/CollectionPivotView.tsx | 5 | ||||
-rw-r--r-- | src/client/views/collections/CollectionSubView.tsx | 6 | ||||
-rw-r--r-- | src/client/views/collections/CollectionTreeView.tsx | 44 | ||||
-rw-r--r-- | src/client/views/nodes/FormattedTextBox.tsx | 4 | ||||
-rw-r--r-- | src/scraping/buxton/scraper.py | 20 |
10 files changed, 116 insertions, 52 deletions
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<Field>; @@ -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) : - <ContentFittingDocumentView {...this.props} - Document={this.childLayoutPairs[index].layout} - DataDocument={this.childLayoutPairs[index].data} - getTransform={this.props.ScreenToLocalTransform} /> + <div> + <div className="collectionCarouselView-image"> + <ContentFittingDocumentView {...this.props} + Document={this.childLayoutPairs[index].layout} + DataDocument={this.childLayoutPairs[index].data} + PanelHeight={this.panelHeight} + getTransform={this.props.ScreenToLocalTransform} /> + </div> + <div className="collectionCarouselView-caption" style={{ background: `${StrCast(this.props.Document.backgroundColor)}` }}> + <FormattedTextBox key={index} {...this.props} Document={this.childLayoutPairs[index].layout} DataDoc={undefined} fieldKey={"caption"}></FormattedTextBox> + </div> + </div> } @computed get buttons() { return <> - <div key="back" className="carouselView-back" onClick={this.goback}> + <div key="back" className="carouselView-back" style={{ background: `${StrCast(this.props.Document.backgroundColor)}` }} onClick={this.goback}> <FontAwesomeIcon icon={faCaretLeft} size={"2x"} /> </div> - <div key="fwd" className="carouselView-fwd" onClick={this.advance}> + <div key="fwd" className="carouselView-fwd" style={{ background: `${StrCast(this.props.Document.backgroundColor)}` }} onClick={this.advance}> <FontAwesomeIcon icon={faCaretRight} size={"2x"} /> </div> </>; 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<SubCollectionViewProp if (removed) CollectionDockingView.Instance._removedDocs.push(removed); this.stateChanged(); } + @undoBatch + @action + public static ReplaceRightSplit(document: Doc, dataDoc: Doc | undefined, libraryPath?: Doc[]): boolean { + if (!CollectionDockingView.Instance) return false; const instance = CollectionDockingView.Instance; + const newItemStackConfig = { + type: 'stack', + content: [CollectionDockingView.makeDocumentConfig(document, dataDoc, undefined, libraryPath)] + }; + + const newContentItem = instance._goldenLayout.root.layoutManager.createContentItem(newItemStackConfig, instance._goldenLayout); + + let retVal = false; + if (instance._goldenLayout.root.contentItems[0].isRow) { + retVal = Array.from(instance._goldenLayout.root.contentItems[0].contentItems).some((child: any) => { + 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<SubCollectionViewProp @action public static UseRightSplit(document: Doc, dataDoc: Doc | undefined, libraryPath?: Doc[]) { document.isDisplayPanel = true; - CollectionDockingView.CloseRightSplit(undefined); - CollectionDockingView.AddRightSplit(document, dataDoc, libraryPath); + if (!CollectionDockingView.ReplaceRightSplit(document, dataDoc, libraryPath)) { + CollectionDockingView.AddRightSplit(document, dataDoc, libraryPath); + } } @undoBatch diff --git a/src/client/views/collections/CollectionPivotView.tsx b/src/client/views/collections/CollectionPivotView.tsx index 66c7c9745..6de20593b 100644 --- a/src/client/views/collections/CollectionPivotView.tsx +++ b/src/client/views/collections/CollectionPivotView.tsx @@ -9,7 +9,6 @@ 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"; @@ -104,9 +103,7 @@ export class CollectionPivotView extends CollectionSubView(doc => doc) { const flyout = ( <div className="collectionPivotView-flyout" style={{ width: `${this._facetWidth}` }}> {this._allFacets.map(facet => <label className="collectionPivotView-flyout-item" key={`${facet}`} onClick={e => this.facetClick(facet)}> - <input type="checkbox" onChange={e => { }} checked={this.props.Document._facetCollection instanceof Doc && DocListCast(this.props.Document._facetCollection.data).some(d => { - return d.title === facet; - })} /> + <input type="checkbox" onChange={e => { }} checked={DocListCast((this.props.Document._facetCollection as Doc)?.data).some(d => d.title === facet)} /> <span className="checkmark" /> {facet} </label>)} 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<T>(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<T>(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<string>(); - 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<Doc>(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<string>())); + + 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<Doc>(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 & <div className={`formattedTextBox-outer`} style={{ width: `calc(100% - ${this.sidebarWidthPercent})`, }} ref={this._scrollRef}> <div className={`formattedTextBox-inner${rounded}`} style={{ whiteSpace: "pre-wrap", pointerEvents: ((this.Document.isButton || this.props.onClick) && !this.props.isSelected()) ? "none" : undefined }} ref={this.createDropTarget} /> </div> - {this.props.Document.hideSidebar ? (null) : this.sidebarWidthPercent === "0%" ? + {this.props.Document._hideSidebar ? (null) : this.sidebarWidthPercent === "0%" ? <div className="formattedTextBox-sidebar-handle" onPointerDown={this.sidebarDown} onClick={e => this.toggleSidebar()} /> : <div className={"formattedTextBox-sidebar" + (InkingControl.Instance.selectedTool !== InkTool.None ? "-inking" : "")} style={{ width: `${this.sidebarWidthPercent}`, backgroundColor: `${this.sidebarColor}` }}> @@ -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" } |