aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBob Zeleznik <zzzman@gmail.com>2020-04-27 02:56:11 -0400
committerBob Zeleznik <zzzman@gmail.com>2020-04-27 02:56:11 -0400
commitdefb7f42492def07befe63c4c6075fe47073cae9 (patch)
treeb8c436bfa38036a2108d46f4f56ccfaafc890a8d
parent7f6bc06f72e070bd8b45eba8b4c0669ee398387b (diff)
parentfc470b25759e8f051dc527066f9bebcaf5e7707d (diff)
Merge branch 'master' of https://github.com/browngraphicslab/Dash-Web
-rw-r--r--src/client/views/collections/CollectionTreeView.tsx37
-rw-r--r--src/client/views/nodes/DocumentContentsView.tsx8
-rw-r--r--src/client/views/nodes/FormattedTextBox.tsx53
-rw-r--r--src/scraping/buxton/final/BuxtonImporter.ts39
4 files changed, 67 insertions, 70 deletions
diff --git a/src/client/views/collections/CollectionTreeView.tsx b/src/client/views/collections/CollectionTreeView.tsx
index 218c5705d..dcb5e116c 100644
--- a/src/client/views/collections/CollectionTreeView.tsx
+++ b/src/client/views/collections/CollectionTreeView.tsx
@@ -732,21 +732,36 @@ export class CollectionTreeView extends CollectionSubView<Document, Partial<coll
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": "year" } } ] }, { "type": "paragraph", "content": [ { "type": "dashField", "attrs": { "fieldKey": "company" } } ] } ] }, "selection":{"type":"text","anchor":1,"head":1},"storedMarks":[] }`;
+ const carousel = CarouselDocument([], { title: "data", _height: 350, _itemIndex: 0, backgroundColor: "#9b9b9b3F" });
const textDoc = TextDocument("", { title: "details", _autoHeight: true });
- const detailView = Docs.Create.StackingDocument([
- CarouselDocument([], { title: "data", _height: 350, _itemIndex: 0, backgroundColor: "#9b9b9b3F" }),
- TreeDocument([
- // textDoc,
- TextDocument("", { title: "shortDescription", _autoHeight: true }),
- // TreeDocument([], { title: "narratives", _height: 75, treeViewHideTitle: true }),
- TextDocument("", { title: "longDescription", _height: 350 })
- ], { title: "stuff", _height: 100 })
- ], { _chromeStatus: "disabled", _width: 300, _height: 300, _autoHeight: true, title: "detailView" });
- textDoc.data = new RichTextField(detailedTemplate, "year company");
+ const short = TextDocument("", { title: "shortDescription", _autoHeight: true });
+ const long = TextDocument("", { title: "longDescription", _height: 350 });
+ long.treeViewExpandedView = "layout";
+ const long_wrapper = TreeDocument([long], { title: "Descriptions", _height: 350 });
+
+ // const narratives = TreeDocument([], { title: "narratives", _height: 75, treeViewHideTitle: true }),
+ // const detailView = Cast(Cast(Doc.UserDoc()["template-button-detail"], Doc, null)?.dragFactory, Doc, null);
+
+ textDoc.fontFamily = short.fontFamily = long.fontFamily = carousel.fontFamily = "Arial";
+
+ const detailViewOpts = { _chromeStatus: "disabled", _width: 300, _height: 300, _autoHeight: true, title: "detailView" };
+ const detailView = Docs.Create.StackingDocument([carousel, textDoc, short, long_wrapper], detailViewOpts);
detailView.isTemplateDoc = makeTemplate(detailView);
+ 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");
heroView._showTitle = "title";
diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx
index 8582f92ed..cd78ac7b3 100644
--- a/src/client/views/nodes/DocumentContentsView.tsx
+++ b/src/client/views/nodes/DocumentContentsView.tsx
@@ -78,7 +78,7 @@ export class HTMLtag extends React.Component<HTMLtagProps> {
const style: { [key: string]: any } = {};
const divKeys = OmitKeys(this.props, ["children", "htmltag", "RootDoc", "Document", "key", "onInput", "onClick", "__proto__"]).omit;
Object.keys(divKeys).map((prop: string) => {
- let p = (this.props as any)[prop] as string;
+ const p = (this.props as any)[prop] as string;
const replacer = (match: any, expr: string, offset: any, string: any) => { // bcz: this executes a script to convert a propery expression string: { script } into a value
return ScriptField.MakeFunction(expr, { self: Doc.name, this: Doc.name })?.script.run({ self: this.props.RootDoc, this: this.props.Document }).result as string || "";
};
@@ -178,9 +178,9 @@ export class DocumentContentsView extends React.Component<DocumentViewProps & {
}
return undefined;
// add input function to props
- }
- let onClick = makeFuncProp("onClick");
- let onInput = makeFuncProp("onInput");
+ };
+ const onClick = makeFuncProp("onClick");
+ const onInput = makeFuncProp("onInput");
const bindings = this.CreateBindings(onClick, onInput);
// layoutFrame = splits.length > 1 ? splits[0] + splits[1].replace(/{([^{}]|(?R))*}/, replacer4) : ""; // might have been more elegant if javascript supported recursive patterns
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 7fc0cbb94..23598f47e 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,8 @@ 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 { state: { tr }, dispatch } = this._editorView;
+ dispatch(tr.insertText(startupText));
}
}
@@ -906,17 +891,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..713207a07 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[];
+ longDescription: 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 longDescription = paragraphs.slice(start, end).filter(paragraph => paragraph.length).join("\n\n");
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, longDescription, imageData, captions, embeddedFileNames, hyperlinks };
}
const imageEntry = /^word\/media\/\w+\.(jpeg|jpg|png|gif)/;
@@ -306,26 +308,30 @@ async function writeImages(zip: any): Promise<ImageData[]> {
const imageEntries = allEntries.filter(name => imageEntry.test(name));
const imageUrls: ImageData[] = [];
- for (const mediaPath of imageEntries) {
- const getImageStream = () => new Promise<Readable>((resolve, reject) => {
- zip.stream(mediaPath, (error: any, stream: any) => error ? reject(error) : resolve(stream));
- });
+ const valid: any[] = [];
+ const getImageStream = (mediaPath: string) => new Promise<Readable>((resolve, reject) => {
+ zip.stream(mediaPath, (error: any, stream: any) => error ? reject(error) : resolve(stream));
+ });
+
+ for (const mediaPath of imageEntries) {
const { width, height, type } = await new Promise<Dimensions>(async resolve => {
const sizeStream = (createImageSizeStream() as PassThrough).on('size', (dimensions: Dimensions) => {
readStream.destroy();
resolve(dimensions);
}).on("error", () => readStream.destroy());
- const readStream = await getImageStream();
+ const readStream = await getImageStream(mediaPath);
readStream.pipe(sizeStream);
});
- if (Math.abs(width - height) < 10) {
- continue;
+
+ if (Math.abs(width - height) > 10) {
+ valid.push({ width, height, type, mediaPath });
}
+ }
+ for (const { type, width, height, mediaPath } of valid) {
const generatedFileName = `upload_${Utils.GenerateGuid()}.${type.toLowerCase()}`;
- await DashUploadUtils.outputResizedImages(getImageStream, generatedFileName, imageDir);
-
+ await DashUploadUtils.outputResizedImages(() => getImageStream(mediaPath), generatedFileName, imageDir);
imageUrls.push({
url: `/files/images/buxton/${generatedFileName}`,
nativeWidth: width,
@@ -337,11 +343,12 @@ 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, longDescription } = contents;
const device: any = {
hyperlinks,
captions,
embeddedFileNames,
+ longDescription,
__images: imageData
};
const errors: { [key: string]: string } = { fileName };