diff options
author | bobzel <zzzman@gmail.com> | 2022-04-29 13:57:42 -0400 |
---|---|---|
committer | bobzel <zzzman@gmail.com> | 2022-04-29 13:57:42 -0400 |
commit | 7b08cb4fd86a7e7048e14c05ab980f5b008d18d8 (patch) | |
tree | d1b66246de9bc25ac596c728ef0e9ece89f13a16 | |
parent | 15bc17cbbe3816ab78ce653105ddff06bce18c59 (diff) |
cleaned up creation of icon templates. fixed labelBox to support padding and to work with multiple lines and min font sizes.
-rw-r--r-- | src/client/util/CurrentUserUtils.ts | 141 | ||||
-rw-r--r-- | src/client/util/DropConverter.ts | 5 | ||||
-rw-r--r-- | src/client/views/nodes/LabelBigText.js | 7 | ||||
-rw-r--r-- | src/client/views/nodes/LabelBox.tsx | 46 |
4 files changed, 105 insertions, 94 deletions
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index c7309d15e..7948aa70b 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -9,7 +9,7 @@ import { RichTextField } from "../../fields/RichTextField"; import { listSpec } from "../../fields/Schema"; import { ComputedField, ScriptField } from "../../fields/ScriptField"; import { BoolCast, Cast, DateCast, NumCast, PromiseValue, StrCast } from "../../fields/Types"; -import { ImageField, nullAudio } from "../../fields/URLField"; +import { nullAudio } from "../../fields/URLField"; import { SharingPermissions } from "../../fields/util"; import { Utils } from "../../Utils"; import { DocServer } from "../DocServer"; @@ -22,11 +22,10 @@ import { Colors } from "../views/global/globalEnums"; import { MainView } from "../views/MainView"; import { ButtonType, NumButtonType } from "../views/nodes/button/FontIconBox"; import { FormattedTextBox } from "../views/nodes/formattedText/FormattedTextBox"; -import { LabelBox } from "../views/nodes/LabelBox"; import { OverlayView } from "../views/OverlayView"; import { DocumentManager } from "./DocumentManager"; import { DragManager } from "./DragManager"; -import { makeTemplate } from "./DropConverter"; +import { makeTemplate, MakeTemplate } from "./DropConverter"; import { HistoryUtil } from "./History"; import { LinkManager } from "./LinkManager"; import { ScriptingGlobals } from "./ScriptingGlobals"; @@ -289,82 +288,68 @@ export class CurrentUserUtils { // setup templates for different document types when they are iconified from Document Decorations static setupDefaultIconTemplates(doc: Doc) { - if (doc["template-icon-view"] === undefined) { - const iconView = Docs.Create.LabelDocument({ - title: "icon", textTransform: "unset", letterSpacing: "unset", layout: LabelBox.LayoutString("title"), _backgroundColor: "dimgray", - _width: 150, _height: 70, _xPadding: 10, _yPadding: 10, isTemplateDoc: true, onClick: ScriptField.MakeScript("deiconifyView(documentView)", { documentView: "any" }), system: true - }); - // Docs.Create.TextDocument("", { - // title: "icon", _width: 150, _height: 30, isTemplateDoc: true, onDoubleClick: ScriptField.MakeScript("deiconifyView(documentView)", { documentView: "any" }) - // }); - // Doc.GetProto(iconView).icon = new RichTextField('{"doc":{"type":"doc","content":[{"type":"paragraph","attrs":{"align":null,"color":null,"id":null,"indent":null,"inset":null,"lineSpacing":null,"paddingBottom":null,"paddingTop":null},"content":[{"type":"dashField","attrs":{"fieldKey":"title","docid":""}}]}]},"selection":{"type":"text","anchor":2,"head":2},"storedMarks":[]}', ""); - iconView.isTemplateDoc = makeTemplate(iconView); - doc["template-icon-view"] = new PrefetchProxy(iconView); - } - if (doc["template-icon-view-rtf"] === undefined) { - const iconRtfView = Docs.Create.LabelDocument({ - title: "icon_" + DocumentType.RTF, _showTitle: "creationDate", textTransform: "unset", letterSpacing: "unset", layout: LabelBox.LayoutString("text"), - _singleLine: false, _minFontSize: 18, _maxFontSize: 24, - _width: 150, _height: 70, _xPadding: 10, _yPadding: 10, isTemplateDoc: true, onClick: ScriptField.MakeScript("deiconifyView(documentView)", { documentView: "any" }), system: true - }); - iconRtfView.isTemplateDoc = makeTemplate(iconRtfView, true, "icon_" + DocumentType.RTF); - doc["template-icon-view-rtf"] = new PrefetchProxy(iconRtfView); - } - if (doc["template-icon-view-button"] === undefined) { - const iconBtnView = Docs.Create.FontIconDocument({ - title: "icon_" + DocumentType.BUTTON, _nativeHeight: 30, _nativeWidth: 30, - _width: 30, _height: 30, isTemplateDoc: true, onDoubleClick: ScriptField.MakeScript("deiconifyView(documentView)", { documentView: "any" }), system: true - }); - iconBtnView.isTemplateDoc = makeTemplate(iconBtnView, true, "icon_" + DocumentType.BUTTON); - doc["template-icon-view-button"] = new PrefetchProxy(iconBtnView); - } - if (doc["template-icon-view-img"] === undefined) { - const iconImageView = Docs.Create.ImageDocument("http://www.cs.brown.edu/~bcz/face.gif", { - title: "data", _width: 150, isTemplateDoc: true, _showTitle: "title", onClick: ScriptField.MakeScript("deiconifyView(documentView)", { documentView: "any" }), system: true - }); - iconImageView.isTemplateDoc = makeTemplate(iconImageView, true, "icon_" + DocumentType.IMG); - doc["template-icon-view-img"] = new PrefetchProxy(iconImageView); - } - if (doc["template-icon-view-col"] === undefined) { - const iconColView = Docs.Create.ImageDocument("", { title: "icon", _showTitle: "title", _width: 360 / 4, _height: 270 / 4, onClick: ScriptField.MakeScript("deiconifyView(documentView)", { documentView: "any" }), system: true }); - iconColView.isTemplateDoc = makeTemplate(iconColView, true, "icon_" + DocumentType.COL); - const proto = iconColView.proto as Doc; - proto["icon-nativeWidth"] = 360 / 4; - proto["icon-nativeHeight"] = 270 / 4; - proto.icon = new ImageField("http://www.cs.brown.edu/~bcz/noImage.png"); - doc["template-icon-view-col"] = new PrefetchProxy(iconColView); - } - if (doc["template-icon-view-video"] === undefined) { - const iconVidView = Docs.Create.ImageDocument("", { title: "icon", _width: 360 / 4, _height: 270 / 4, _showTitle: "title", onClick: ScriptField.MakeScript("deiconifyView(documentView)", { documentView: "any" }), system: true }); - iconVidView.isTemplateDoc = makeTemplate(iconVidView, true, "icon_" + DocumentType.VID); - const proto = iconVidView.proto as Doc; - proto["icon-nativeWidth"] = 360 / 4; - proto["icon-nativeHeight"] = 270 / 4; - proto.icon = new ImageField("http://www.cs.brown.edu/~bcz/noImage.png"); - doc["template-icon-view-video"] = new PrefetchProxy(iconVidView); - } - if (doc["template-icon-view-pdf"] === undefined) { - const iconPdfView = Docs.Create.ImageDocument("", { title: "icon", _width: 360 / 4, _height: 270 / 4, _showTitle: "title", onClick: ScriptField.MakeScript("deiconifyView(documentView)", { documentView: "any" }), system: true }); - iconPdfView.isTemplateDoc = makeTemplate(iconPdfView, true, "icon_" + DocumentType.PDF); - const proto = iconPdfView.proto as Doc; - proto["icon-nativeWidth"] = 360 / 4; - proto["icon-nativeHeight"] = 270 / 4; - proto.icon = new ImageField("http://www.cs.brown.edu/~bcz/noImage.png"); - doc["template-icon-view-pdf"] = new PrefetchProxy(iconPdfView); - } - if (doc["template-icons"] === undefined) { - doc["template-icons"] = new PrefetchProxy(Docs.Create.TreeDocument([doc["template-icon-view"] as Doc, doc["template-icon-view-img"] as Doc, doc["template-icon-view-button"] as Doc, - doc["template-icon-view-col"] as Doc, doc["template-icon-view-rtf"] as Doc, doc["template-icon-view-video"] as Doc, doc["template-icon-view-pdf"] as Doc], { title: "icon templates", _height: 75, system: true })); - } else { - const templateIconsDoc = Cast(doc["template-icons"], Doc, null); - const requiredTypes = [doc["template-icon-view"] as Doc, doc["template-icon-view-img"] as Doc, doc["template-icon-view-button"] as Doc, - doc["template-icon-view-col"] as Doc, doc["template-icon-view-rtf"] as Doc]; - DocListCastAsync(templateIconsDoc.data).then(async curIcons => { - curIcons && await Promise.all(curIcons); - requiredTypes.map(ntype => Doc.AddDocToList(templateIconsDoc, "data", ntype)); - }); + const templateIconsDoc = Cast(doc["template-icons"], Doc, null); + + const makeIconTemplate = (type: DocumentType | undefined, templateField: string, iconTemplate: () => Doc, finalize: (icon: Doc) => Doc = (doc: Doc) => doc) => { + const iconFieldName = type ? "icon_" + type : "icon"; + if (templateIconsDoc?.[iconFieldName] === undefined) { + const template = finalize(MakeTemplate(iconTemplate(), true, iconFieldName, templateField)); + if (templateIconsDoc) { + templateIconsDoc[iconFieldName] = new PrefetchProxy(template); + Doc.AddDocToList(templateIconsDoc, "data", template); + } + return template; + } + return templateIconsDoc[iconFieldName] as Doc; + }; + const finalizeIconTemplate = (icon: Doc) => { + const iconProto = Doc.GetProto(icon); + iconProto["icon-nativeWidth"] = iconProto.width; + iconProto["icon-nativeHeight"] = iconProto.height; + return icon; + }; + const iconList = [ + makeIconTemplate(undefined, "title", () => Docs.Create.LabelDocument({ + textTransform: "unset", letterSpacing: "unset", _backgroundColor: "dimgray", _singleLine: false, _minFontSize: 14, _maxFontSize: 24, borderRounding: "5px", + _width: 150, _height: 70, _xPadding: 10, _yPadding: 10, + onClick: ScriptField.MakeScript("deiconifyView(documentView)", { documentView: "any" }), system: true + })), + makeIconTemplate(DocumentType.AUDIO, "title", () => Docs.Create.LabelDocument({ + textTransform: "unset", letterSpacing: "unset", _backgroundColor: "lightgreen", _singleLine: false, _minFontSize: 14, _maxFontSize: 24, borderRounding: "5px", + _width: 150, _height: 70, _xPadding: 10, _yPadding: 10, + onClick: ScriptField.MakeScript("deiconifyView(documentView)", { documentView: "any" }), system: true + })), + makeIconTemplate(DocumentType.RTF, "text", () => Docs.Create.LabelDocument({ + _showTitle: "creationDate", textTransform: "unset", letterSpacing: "unset", _singleLine: false, _minFontSize: 14, _maxFontSize: 24, borderRounding: "5px", + _width: 150, _height: 70, _xPadding: 10, _yPadding: 10, + onClick: ScriptField.MakeScript("deiconifyView(documentView)", { documentView: "any" }), system: true + })), + makeIconTemplate(DocumentType.PDF, "title", () => Docs.Create.LabelDocument({ + textTransform: "unset", letterSpacing: "unset", _backgroundColor: "pink", _singleLine: false, _minFontSize: 10, _maxFontSize: 24, borderRounding: "5px", + _width: 75, _height: 125, _xPadding: 10, _yPadding: 10, + onClick: ScriptField.MakeScript("deiconifyView(documentView)", { documentView: "any" }), system: true + })), + makeIconTemplate(DocumentType.BUTTON, "data", () => Docs.Create.FontIconDocument({ + _nativeHeight: 30, _nativeWidth: 30, _width: 30, _height: 30, + onDoubleClick: ScriptField.MakeScript("deiconifyView(documentView)", { documentView: "any" }), system: true + })), + makeIconTemplate(DocumentType.IMG, "data", () => Docs.Create.ImageDocument("", { + _width: 150, _showTitle: "title", onClick: ScriptField.MakeScript("deiconifyView(documentView)", { documentView: "any" }), system: true + })), + makeIconTemplate(DocumentType.COL, "icon", () => Docs.Create.ImageDocument("http://www.cs.brown.edu/~bcz/noImage.png", { + _width: 360 / 4, _height: 270 / 4, _showTitle: "title", onClick: ScriptField.MakeScript("deiconifyView(documentView)", { documentView: "any" }), system: true + }), finalizeIconTemplate), + makeIconTemplate(DocumentType.VID, "icon", () => Docs.Create.ImageDocument("http://www.cs.brown.edu/~bcz/noImage.png", { + _width: 360 / 4, _height: 270 / 4, _showTitle: "title", onClick: ScriptField.MakeScript("deiconifyView(documentView)", { documentView: "any" }), system: true + }), finalizeIconTemplate), + // makeIconTemplate(DocumentType.PDF, "data", () => Docs.Create.ImageDocument("http://www.cs.brown.edu/~bcz/noImage.png", { + // _width: 360 / 4, _height: 270 / 4, _showTitle: "title", onClick: ScriptField.MakeScript("deiconifyView(documentView)", { documentView: "any" }), system: true + // }), setIconProtoFields) + ]; + if (!templateIconsDoc) { + doc["template-icons"] = Docs.Create.TreeDocument(iconList, { title: "icon templates", _height: 75, system: true }); + iconList.map(ntype => (doc["template-icons"] as Doc)[StrCast(ntype.title)] = new PrefetchProxy(ntype)); } - return doc["template-icons"] as Doc; } static creatorBtnDescriptors(doc: Doc): { diff --git a/src/client/util/DropConverter.ts b/src/client/util/DropConverter.ts index 082b6d8bd..076afd3a0 100644 --- a/src/client/util/DropConverter.ts +++ b/src/client/util/DropConverter.ts @@ -10,6 +10,11 @@ import { ImageField } from "../../fields/URLField"; import { ScriptingGlobals } from "./ScriptingGlobals"; import { listSpec } from "../../fields/Schema"; +export function MakeTemplate(doc: Doc, first: boolean = true, rename: Opt<string> = undefined, templateField: string = "") { + if (templateField) Doc.GetProto(doc).title = templateField; /// the title determines which field is being templated + doc.isTemplateDoc = makeTemplate(doc, first, rename); + return doc; +} // // converts 'doc' into a template that can be used to render other documents. // the title of doc is used to determine which field is being templated, so diff --git a/src/client/views/nodes/LabelBigText.js b/src/client/views/nodes/LabelBigText.js index 02c36c4bc..6a212d9ea 100644 --- a/src/client/views/nodes/LabelBigText.js +++ b/src/client/views/nodes/LabelBigText.js @@ -193,11 +193,12 @@ export default function BigText(element, options) { if (fontSize < options.minimumFontSize) { parentStyle.display = "flex"; parentStyle.alignItems = "center"; - style.whiteSpace = "pre-wrap"; style.textAlign = "center"; style.visibility = ""; - style.fontSize = "18px"; - style.lineHeight = "20px"; + style.fontSize = options.minimumFontSize + "px"; + style.lineHeight = ""; + style.overflow = "hidden"; + style.textOverflow = "ellipsis"; style.top = ""; style.left = ""; style.margin = ""; diff --git a/src/client/views/nodes/LabelBox.tsx b/src/client/views/nodes/LabelBox.tsx index d539ca9b8..dfff59005 100644 --- a/src/client/views/nodes/LabelBox.tsx +++ b/src/client/views/nodes/LabelBox.tsx @@ -27,14 +27,19 @@ export class LabelBox extends ViewBoxBaseComponent<(FieldViewProps & LabelBoxPro return `<${fieldType.name} fieldKey={'${fieldStr}'} label={'${label}'} {...props} />`; //e.g., "<ImageBox {...props} fieldKey={"data} />" } private dropDisposer?: DragManager.DragDropDisposer; - + private _timeout: any; componentDidMount() { this.props.setContentView?.(this); } + componentWillUnMount() { + this._timeout && clearTimeout(this._timeout); + } getTitle() { - return this.rootDoc["title-custom"] ? StrCast(this.rootDoc.title) : this.props.label ? this.props.label : - typeof this.rootDoc[this.fieldKey] === "string" ? StrCast(this.rootDoc[this.fieldKey]) : StrCast(this.rootDoc.title); + return this.rootDoc["title-custom"] ? StrCast(this.rootDoc.title) : + this.props.label ? this.props.label : + typeof this.rootDoc[this.fieldKey] === "string" ? StrCast(this.rootDoc[this.fieldKey]) : + StrCast(this.rootDoc.title); } protected createDropTarget = (ele: HTMLDivElement) => { @@ -73,8 +78,8 @@ export class LabelBox extends ViewBoxBaseComponent<(FieldViewProps & LabelBoxPro @observable _mouseOver = false; @computed get hoverColor() { return this._mouseOver ? StrCast(this.layoutDoc._hoverBackgroundColor) : "unset"; } - fitTextToBox = (r: any) => { - BigText(r, { + fitTextToBox = (r: any): any => { + const params = { rotateText: null, fontSizeFactor: 1, minimumFontSize: NumCast(this.layoutDoc._minFontSize), @@ -83,11 +88,25 @@ export class LabelBox extends ViewBoxBaseComponent<(FieldViewProps & LabelBoxPro horizontalAlign: "center", verticalAlign: "center", textAlign: "center", - whiteSpace: "nowrap" - }); + whiteSpace: this.layoutDoc._singleLine ? "nowrap" : "pre-wrap" + }; + this._timeout = undefined; + if (!r) return params; + if (!r.offsetHeight || !r.offsetWidth) return this._timeout = setTimeout(() => this.fitTextToBox(r)); + const parent = r.parentNode; + const parentStyle = parent.style; + parentStyle.display = ""; + parentStyle.alignItems = ""; + r.setAttribute("style", ""); + r.style.width = this.layoutDoc._singleLine ? "" : "100%"; + + r.style.textOverflow = "ellipsis"; + r.style.overflow = "hidden"; + BigText(r, params); } // (!missingParams || !missingParams.length ? "" : "(" + missingParams.map(m => m + ":").join(" ") + ")") render() { + this.fitTextToBox(null);// this causes mobx to trigger re-render when data changes const params = Cast(this.paramsDoc["onClick-paramFieldKeys"], listSpec("string"), []); const missingParams = params?.filter(p => !this.paramsDoc[p]); params?.map(p => DocListCast(this.paramsDoc[p])); // bcz: really hacky form of prefetching ... @@ -104,16 +123,17 @@ export class LabelBox extends ViewBoxBaseComponent<(FieldViewProps & LabelBoxPro fontFamily: StrCast(this.layoutDoc._fontFamily) || "inherit", letterSpacing: StrCast(this.layoutDoc.letterSpacing), textTransform: StrCast(this.layoutDoc.textTransform) as any, + paddingLeft: NumCast(this.rootDoc._xPadding), + paddingRight: NumCast(this.rootDoc._xPadding), + paddingTop: NumCast(this.rootDoc._yPadding), + paddingBottom: NumCast(this.rootDoc._yPadding), width: this.props.PanelWidth(), height: this.props.PanelHeight(), whiteSpace: this.layoutDoc._singleLine ? "pre" : "pre-wrap" }} > - <span ref={r => { - if (r) { - if (!r.offsetWidth || !r.offsetHeight) setTimeout(() => this.fitTextToBox(r)); - else this.fitTextToBox(r); - } - }}>{label.startsWith("#") ? (null) : label}</span> + <span ref={action((r: any) => this.fitTextToBox(r))}> + {label.startsWith("#") ? (null) : label} + </span> </div> <div className="labelBox-fieldKeyParams" > {!missingParams?.length ? (null) : missingParams.map(m => <div key={m} className="labelBox-missingParam">{m}</div>)} |