diff options
-rw-r--r-- | src/client/documents/Documents.ts | 1 | ||||
-rw-r--r-- | src/client/views/collections/CollectionTreeView.tsx | 21 | ||||
-rw-r--r-- | src/client/views/nodes/FormattedTextBox.tsx | 60 | ||||
-rw-r--r-- | src/scraping/buxton/final/BuxtonImporter.ts | 17 |
4 files changed, 49 insertions, 50 deletions
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 1268c97b0..6bd2eee3c 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -407,6 +407,7 @@ export namespace Docs { const doc = StackingDocument(deviceImages, { title: device.title, _LODdisable: true }); const deviceProto = Doc.GetProto(doc); deviceProto.hero = new ImageField(constructed[0].url); + deviceProto.fontFamily = "Arial"; Docs.Get.FromJson({ data: device, appendToExisting: { targetDoc: deviceProto } }); Doc.AddDocToList(parentProto, "data", doc); } else if (errors) { diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx index 7f5dc98f1..49eb90bc2 100644 --- a/src/client/views/collections/CollectionTreeView.tsx +++ b/src/client/views/collections/CollectionTreeView.tsx @@ -730,18 +730,31 @@ export class CollectionTreeView extends CollectionSubView<Document, Partial<coll 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": "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 detailView = Docs.Create.StackingDocument([ CarouselDocument([], { title: "data", _height: 350, _itemIndex: 0, backgroundColor: "#9b9b9b3F" }), - // textDoc, + textDoc, TextDocument("", { title: "shortDescription", _autoHeight: true }), - // TreeDocument([], { title: "narratives", _height: 75, treeViewHideTitle: true }), TextDocument("", { title: "longDescription", _height: 350 }) + // TreeDocument([], { title: "narratives", _height: 75, treeViewHideTitle: true }), ], { _chromeStatus: "disabled", _width: 300, _height: 300, _autoHeight: true, title: "detailView" }); - textDoc.data = new RichTextField(detailedTemplate, "year company"); + // const detailView = Cast(Cast(Doc.UserDoc()["template-button-detail"], Doc, null)?.dragFactor, Doc, null); detailView.isTemplateDoc = makeTemplate(detailView); + detailView.fontFamily = "Arial"; + + const buxtonFieldKeys = ["year", "originalPrice", "degreesOfFreedom", "company", "attribute", "primaryKey", "secondaryKey", "dimensions"]; + const detailedTemplate = { + doc: { + type: "doc", content: buxtonFieldKeys.map(fieldKey => ({ + type: "paragraph", + content: [{ type: "dashField", attrs: { fieldKey } }] + })) + }, + selection: { type: "text", anchor: 1, head: 1 }, + storedMarks: [] + }; + textDoc.data = new RichTextField(JSON.stringify(detailedTemplate), buxtonFieldKeys.join(" ")); 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"); diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 425af8ccf..dd0df9f3f 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -83,17 +83,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp private _lastX = 0; private _lastY = 0; private _undoTyping?: UndoManager.Batch; - private _searchReactionDisposer?: Lambda; - private _recordReactionDisposer: Opt<IReactionDisposer>; - private _scrollToRegionReactionDisposer: Opt<IReactionDisposer>; - private _reactionDisposer: Opt<IReactionDisposer>; - private _heightReactionDisposer: Opt<IReactionDisposer>; - private _proxyReactionDisposer: Opt<IReactionDisposer>; - private _pullReactionDisposer: Opt<IReactionDisposer>; - private _pushReactionDisposer: Opt<IReactionDisposer>; - private _buttonBarReactionDisposer: Opt<IReactionDisposer>; - private _linkMakerDisposer: Opt<IReactionDisposer>; - private _scrollDisposer: Opt<IReactionDisposer>; + private _disposers: { [name: string]: IReactionDisposer } = {}; private dropDisposer?: DragManager.DragDropDisposer; @computed get _recording() { return this.dataDoc.audioState === "recording"; } @@ -564,7 +554,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp } } componentDidMount() { - this._buttonBarReactionDisposer = reaction( + this._disposers.buttonBar = reaction( () => DocumentButtonBar.Instance, instance => { if (instance) { @@ -573,7 +563,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp } } ); - this._linkMakerDisposer = reaction( + this._disposers.linkMaker = reaction( () => this.props.makeLink?.(), (linkDoc: Opt<Doc>) => { if (linkDoc) { @@ -584,8 +574,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp }, { fireImmediately: true } ); - - this._reactionDisposer = reaction( + this._disposers.editorState = reaction( () => { if (this.dataDoc[this.props.fieldKey + "-noTemplate"] || !this.props.Document[this.props.fieldKey + "-textTemplate"]) { return Cast(this.dataDoc[this.props.fieldKey], RichTextField, null)?.Data; @@ -600,8 +589,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp } } ); - - this._pullReactionDisposer = reaction( + this._disposers.pullDoc = reaction( () => this.props.Document[Pulls], () => { if (!DocumentButtonBar.hasPulledHack) { @@ -611,8 +599,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp } } ); - - this._pushReactionDisposer = reaction( + this._disposers.pushDoc = reaction( () => this.props.Document[Pushes], () => { if (!DocumentButtonBar.hasPushedHack) { @@ -621,19 +608,18 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp } } ); - - this._heightReactionDisposer = reaction( + this._disposers.height = reaction( () => [this.layoutDoc[WidthSym](), this.layoutDoc._autoHeight], () => this.tryUpdateHeight() ); this.setupEditor(this.config, this.props.fieldKey); - this._searchReactionDisposer = reaction(() => this.rootDoc.searchMatch, + this._disposers.search = reaction(() => this.rootDoc.searchMatch, search => search ? this.highlightSearchTerms([Doc.SearchQuery()]) : this.unhighlightSearchTerms(), { fireImmediately: true }); - this._recordReactionDisposer = reaction(() => this._recording, + this._disposers.record = reaction(() => this._recording, () => { if (this._recording) { setTimeout(action(() => { @@ -643,8 +629,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp } else setTimeout(() => this.stopDictation(true), 0); } ); - - this._scrollToRegionReactionDisposer = reaction( + this._disposers.scrollToRegion = reaction( () => StrCast(this.layoutDoc.scrollToLinkID), async (scrollToLinkID) => { const findLinkFrag = (frag: Fragment, editor: EditorView) => { @@ -689,8 +674,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp }, { fireImmediately: true } ); - - this._scrollDisposer = reaction(() => NumCast(this.props.Document.scrollPos), + this._disposers.scroll = reaction(() => NumCast(this.props.Document.scrollPos), pos => this._scrollRef.current && this._scrollRef.current.scrollTo({ top: pos }), { fireImmediately: true } ); @@ -876,7 +860,15 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp }); const startupText = !rtfField && this._editorView && Field.toString(this.dataDoc[fieldKey] as Field); if (startupText) { - this._editorView.dispatch(this._editorView.state.tr.insertText(startupText)); + const paragraphSegments = startupText.split("\n\n"); + const { state: { tr }, dispatch } = this._editorView; + if (paragraphSegments.length) { + for (const paragraph of paragraphSegments) { + dispatch(tr.insertText(paragraph)); + } + } else { + dispatch(tr.insertText(startupText)); + } } } @@ -906,17 +898,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp } componentWillUnmount() { - this._scrollDisposer?.(); - this._scrollToRegionReactionDisposer?.(); - this._reactionDisposer?.(); - this._proxyReactionDisposer?.(); - this._pushReactionDisposer?.(); - this._pullReactionDisposer?.(); - this._heightReactionDisposer?.(); - this._searchReactionDisposer?.(); - this._recordReactionDisposer?.(); - this._buttonBarReactionDisposer?.(); - this._linkMakerDisposer?.(); + Object.values(this._disposers).forEach(disposer => disposer?.()); this._editorView?.destroy(); } diff --git a/src/scraping/buxton/final/BuxtonImporter.ts b/src/scraping/buxton/final/BuxtonImporter.ts index 122415460..64b988610 100644 --- a/src/scraping/buxton/final/BuxtonImporter.ts +++ b/src/scraping/buxton/final/BuxtonImporter.ts @@ -16,6 +16,7 @@ interface DocumentContents { hyperlinks: string[]; captions: string[]; embeddedFileNames: string[]; + longDescriptionParagraphs: string[]; } export interface DeviceDocument { @@ -186,10 +187,6 @@ const RegexMap = new Map<keyof DeviceDocument, Processor<any>>([ exp: /Short Description:\s+(.*)Bill Buxton[’']s Notes/, transformer: Utilities.correctSentences }], - ["longDescription", { - exp: /Bill Buxton[’']s Notes(.*)Device Details/, - transformer: Utilities.correctSentences - }], ]); const sourceDir = path.resolve(__dirname, "source"); @@ -267,7 +264,12 @@ async function extractFileContents(pathToDocument: string): Promise<DocumentCont const body = document.root()?.text() ?? "No body found. Check the import script's XML parser."; const captions: string[] = []; const embeddedFileNames: string[] = []; - const captionTargets = document.find(tableCellXPath).map(node => node.text()); + const captionTargets = document.find(tableCellXPath).map(node => node.text().trim()); + + const paragraphs = document.find('//*[name()="w:p"]').map(node => Utilities.correctSentences(node.text()).transformed!); + const start = paragraphs.indexOf(paragraphs.find(el => /Bill Buxton[’']s Notes/.test(el))!) + 1; + const end = paragraphs.indexOf("Device Details"); + const longDescriptionParagraphs = paragraphs.slice(start, end); const { length } = captionTargets; strictEqual(length > 3, true, "No captions written."); @@ -290,7 +292,7 @@ async function extractFileContents(pathToDocument: string): Promise<DocumentCont zip.close(); - return { body, imageData, captions, embeddedFileNames, hyperlinks }; + return { body, longDescriptionParagraphs, imageData, captions, embeddedFileNames, hyperlinks }; } const imageEntry = /^word\/media\/\w+\.(jpeg|jpg|png|gif)/; @@ -337,7 +339,7 @@ async function writeImages(zip: any): Promise<ImageData[]> { } function analyze(fileName: string, contents: DocumentContents): AnalysisResult { - const { body, imageData, captions, hyperlinks, embeddedFileNames } = contents; + const { body, imageData, captions, hyperlinks, embeddedFileNames, longDescriptionParagraphs } = contents; const device: any = { hyperlinks, captions, @@ -376,6 +378,7 @@ function analyze(fileName: string, contents: DocumentContents): AnalysisResult { return { errors }; } + device.longDescription = longDescriptionParagraphs.join("\n\n"); return { device }; } |