aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorbobzel <zzzman@gmail.com>2024-03-12 09:09:59 -0400
committerbobzel <zzzman@gmail.com>2024-03-12 09:09:59 -0400
commitc563aec906c5728a5563fefac6ab573a31375641 (patch)
tree8a464f29b9975b644f6d78a64f56fad902d3dc08 /src
parentcf91f5d4db5ba822b30d06cae9934bc979aff829 (diff)
made text templates be both layout templates and prototypes of new text documents. fixed onPaint funcs to be undoable. fixed comparisonBox to render a text box if it's fieldKey has a richtext field - this makes flashcard templates much easier. fixed right-click on hyperlinks to bring up menu. fixed layout_centered to be settable on templates. added enable flashcard property for text.
Diffstat (limited to 'src')
-rw-r--r--src/client/documents/Documents.ts32
-rw-r--r--src/client/util/CurrentUserUtils.ts4
-rw-r--r--src/client/views/PropertiesButtons.tsx21
-rw-r--r--src/client/views/StyleProvider.tsx2
-rw-r--r--src/client/views/nodes/ComparisonBox.tsx13
-rw-r--r--src/client/views/nodes/DocumentView.tsx27
-rw-r--r--src/client/views/nodes/KeyValueBox.tsx2
-rw-r--r--src/client/views/nodes/formattedText/FormattedTextBox.tsx4
-rw-r--r--src/client/views/nodes/formattedText/RichTextMenu.tsx4
-rw-r--r--src/client/views/nodes/formattedText/RichTextRules.ts2
10 files changed, 75 insertions, 36 deletions
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 7a3b965fe..a13edec77 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -1982,27 +1982,29 @@ export namespace DocUtils {
}
export function GetNewTextDoc(title: string, x: number, y: number, width?: number, height?: number, annotationOn?: Doc, backgroundColor?: string) {
+ const defaultTextTemplate = DocCast(Doc.UserDoc().defaultTextLayout);
const tbox = Docs.Create.TextDocument('', {
annotationOn,
backgroundColor,
- _width: width || 200,
- _height: 35,
- x: x,
- y: y,
- _layout_centered: BoolCast(Doc.UserDoc().layout_centered),
- _layout_fitWidth: true,
- _layout_autoHeight: true,
- _layout_enableAltContentUI: BoolCast(Doc.UserDoc().defaultToFlashcards),
+ x,
+ y,
title,
+ ...(defaultTextTemplate
+ ? {} // if the new doc will inherit from a template, don't set any layout fields since that would block the inheritance
+ : {
+ _width: width || 200,
+ _height: 35,
+ _layout_centered: BoolCast(Doc.UserDoc()._layout_centered),
+ _layout_fitWidth: true,
+ _layout_autoHeight: true,
+ _layout_enableAltContentUI: BoolCast(Doc.UserDoc().defaultToFlashcards),
+ }),
});
- const template = Doc.UserDoc().defaultTextLayout;
- if (template instanceof Doc) {
- // if a default text template is specified
- tbox._width = NumCast(template._width);
- tbox.layout_fieldKey = 'layout_' + StrCast(template.title);
- Doc.GetProto(tbox)[StrCast(tbox.layout_fieldKey)] = template; // set the text doc's layout to render with the text template
- tbox[DocData].proto = template; // and also set the text doc to inherit from the template (this allows the template to specify default field values)
+ if (defaultTextTemplate) {
+ tbox.layout_fieldKey = 'layout_' + StrCast(defaultTextTemplate.title);
+ Doc.GetProto(tbox)[StrCast(tbox.layout_fieldKey)] = defaultTextTemplate; // set the text doc's layout to render with the text template
+ tbox[DocData].proto = defaultTextTemplate; // and also set the text doc to inherit from the template (this allows the template to specify default field values)
}
return tbox;
}
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index fc315fdbe..84a33500d 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -276,7 +276,7 @@ export class CurrentUserUtils {
slide[DocData].text = rtfield;
slide[DocData].layout_textPainted = `<CollectionView {...props} fieldKey={'text'}/>`;
slide[DocData]._type_collection = CollectionViewType.Freeform;
- slide.onPaint = ScriptField.MakeScript(`toggleDetail(documentView, "textPainted", "")`, {documentView:"any"});
+ slide.onPaint = ScriptField.MakeScript(`toggleDetail(documentView, "textPainted")`, {documentView:"any"});
return slide;
}
const mermaidsApi = () => {
@@ -330,7 +330,7 @@ pie title Minerals in my tap water
slide[DocData].text = rtfield;
slide[DocData].layout_textPainted = `<CollectionView {...props} fieldKey={'text'}/>`;
slide[DocData]._type_collection = CollectionViewType.Freeform;
- slide.onPaint = ScriptField.MakeScript(`toggleDetail(documentView, "textPainted", "")`, {documentView:"any"});
+ slide.onPaint = ScriptField.MakeScript(`toggleDetail(documentView, "textPainted")`, {documentView:"any"});
return slide;
}
const apis = [plotlyApi(), mermaidsApi()]
diff --git a/src/client/views/PropertiesButtons.tsx b/src/client/views/PropertiesButtons.tsx
index 3cb835e39..02f288a68 100644
--- a/src/client/views/PropertiesButtons.tsx
+++ b/src/client/views/PropertiesButtons.tsx
@@ -13,7 +13,8 @@ import { RxWidth } from 'react-icons/rx';
import { TbEditCircle, TbEditCircleOff, TbHandOff, TbHandStop, TbHighlight, TbHighlightOff } from 'react-icons/tb';
import { TfiBarChart } from 'react-icons/tfi';
import { Doc, DocListCast, Opt } from '../../fields/Doc';
-import { RichTextField } from '../../fields/RichTextField';
+import { DocData } from '../../fields/DocSymbols';
+import { ScriptField } from '../../fields/ScriptField';
import { BoolCast, ScriptCast } from '../../fields/Types';
import { ImageField } from '../../fields/URLField';
import { CollectionViewType, DocumentType } from '../documents/DocumentTypes';
@@ -27,6 +28,7 @@ import { InkingStroke } from './InkingStroke';
import './PropertiesButtons.scss';
import { Colors } from './global/globalEnums';
import { DocumentView, OpenWhere } from './nodes/DocumentView';
+import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox';
@observer
export class PropertiesButtons extends React.Component<{}, {}> {
@@ -174,6 +176,20 @@ export class PropertiesButtons extends React.Component<{}, {}> {
);
}
+ @computed get flashcardButton() {
+ return this.propertyToggleBtn(
+ on => (on ? 'DISABLE FLASHCARD' : 'ENABLE FLASHCARD'),
+ 'layout_textPainted',
+ on => `${on ? 'Flashcard enabled' : 'Flashcard disabled'} `,
+ on => <MdTouchApp />,
+ (dv, doc) => {
+ const on = doc.onPaint ? true : false;
+ doc[DocData].onPaint = on ? undefined : ScriptField.MakeScript(`toggleDetail(documentView, "textPainted")`, { documentView: 'any' });
+ doc[DocData].layout_textPainted = on ? undefined : `<ComparisonBox {...props} fieldKey={'${dv?.LayoutFieldKey ?? 'text'}'}/>`;
+ }
+ );
+ }
+
@computed get fitContentButton() {
return this.propertyToggleBtn(
on => (on ? 'PREVIOUS VIEW' : 'VIEW ALL'), //'View All',
@@ -481,7 +497,7 @@ export class PropertiesButtons extends React.Component<{}, {}> {
render() {
const layoutField = this.selectedDoc?.[Doc.LayoutFieldKey(this.selectedDoc)];
- const isText = layoutField instanceof RichTextField;
+ const isText = SelectionManager.Views.lastElement()?.ComponentView instanceof FormattedTextBox;
const isInk = this.selectedDoc?.layout_isSvg;
const isImage = layoutField instanceof ImageField;
const isMap = this.selectedDoc?.type === DocumentType.MAP;
@@ -507,6 +523,7 @@ export class PropertiesButtons extends React.Component<{}, {}> {
{/* {toggle(this.freezeThumb)} */}
{toggle(this.forceActiveButton)}
{toggle(this.verticalAlignButton, { display: !isText ? 'none' : '' })}
+ {toggle(this.flashcardButton, { display: !isText ? 'none' : '' })}
{toggle(this.fitContentButton, { display: !isFreeForm && !isMap ? 'none' : '' })}
{/* {toggle(this.isLightboxButton, { display: !isFreeForm && !isMap ? 'none' : '' })} */}
{toggle(this.layout_autoHeightButton, { display: !isText && !isStacking && !isTree ? 'none' : '' })}
diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx
index 0794efe4c..ab811858a 100644
--- a/src/client/views/StyleProvider.tsx
+++ b/src/client/views/StyleProvider.tsx
@@ -61,7 +61,7 @@ function togglePaintView(e: React.MouseEvent, doc: Opt<Doc>, props: Opt<FieldVie
value: undefined,
};
e.stopPropagation();
- UndoManager.RunInBatch(() => doc && ScriptCast(doc.onPaint).script.run(scriptProps), 'togglePaintView');
+ ScriptCast(doc?.onPaint)?.script.run(scriptProps);
}
export function wavyBorderPath(pw: number, ph: number, inset: number = 0.05) {
diff --git a/src/client/views/nodes/ComparisonBox.tsx b/src/client/views/nodes/ComparisonBox.tsx
index ef8c045cc..2b57178f4 100644
--- a/src/client/views/nodes/ComparisonBox.tsx
+++ b/src/client/views/nodes/ComparisonBox.tsx
@@ -14,6 +14,8 @@ import './ComparisonBox.scss';
import { DocumentView } from './DocumentView';
import { FieldView, FieldViewProps } from './FieldView';
import { PinProps, PresBox } from './trails';
+import { FormattedTextBox } from './formattedText/FormattedTextBox';
+import { RichTextField } from '../../../fields/RichTextField';
@observer
export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>() implements ViewBoxInterface {
@@ -172,12 +174,15 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
const displayDoc = (which: string) => {
const whichDoc = DocCast(this.dataDoc[which]);
const targetDoc = DocCast(whichDoc?.annotationOn, whichDoc);
- return targetDoc ? (
+ // if there is no Doc in the first comparison slot, but the comparison box's fieldKey slot has a RichTextField, then render a text box to show the contents of the document's field key slot
+ const layoutTemplateString = !targetDoc && which.endsWith('1') && this.Document[this.fieldKey] instanceof RichTextField ? FormattedTextBox.LayoutString(this.fieldKey) : undefined;
+ return targetDoc || layoutTemplateString ? (
<>
<DocumentView
{...this._props}
- Document={targetDoc}
- TemplateDataDocument={undefined}
+ renderDepth={this.props.renderDepth + 1}
+ LayoutTemplateString={layoutTemplateString}
+ Document={layoutTemplateString ? this.Document : targetDoc}
containerViewPath={this.DocumentView?.().docViewPath}
moveDocument={which.endsWith('1') ? this.moveDoc1 : this.moveDoc2}
removeDocument={which.endsWith('1') ? this.remDoc1 : this.remDoc2}
@@ -190,7 +195,7 @@ export class ComparisonBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
hideLinkButton={true}
pointerEvents={this._isAnyChildContentActive ? undefined : returnNone}
/>
- {clearButton(which)}
+ {layoutTemplateString ? null : clearButton(which)}
</> // placeholder image if doc is missing
) : (
<div className="placeholder">
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 29266bd8e..40592c2cd 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -457,11 +457,11 @@ export class DocumentViewInternal extends DocComponent<FieldViewProps & Document
deleteClicked = undoable(() => this._props.removeDocument?.(this.Document), 'delete doc');
setToggleDetail = undoable(
- (defaultLayout: string, scriptFieldKey: 'onClick') =>
+ (scriptFieldKey: 'onClick') =>
(this.Document[scriptFieldKey] = ScriptField.MakeScript(
`toggleDetail(documentView, "${StrCast(this.Document.layout_fieldKey)
.replace('layout_', '')
- .replace(/^layout$/, 'detail')}", "${defaultLayout}")`,
+ .replace(/^layout$/, 'detail')}")`,
{ documentView: 'any' }
)),
'set toggle detail'
@@ -1201,7 +1201,7 @@ export class DocumentView extends DocComponent<DocumentViewProps>() {
};
public noOnClick = () => this._docViewInternal?.noOnClick();
public toggleFollowLink = (zoom?: boolean, setTargetToggle?: boolean): void => this._docViewInternal?.toggleFollowLink(zoom, setTargetToggle);
- public setToggleDetail = (defaultLayout = '', scriptFieldKey = 'onClick') => this._docViewInternal?.setToggleDetail(defaultLayout, scriptFieldKey);
+ public setToggleDetail = (scriptFieldKey = 'onClick') => this._docViewInternal?.setToggleDetail(scriptFieldKey);
public onContextMenu = (e?: React.MouseEvent, pageX?: number, pageY?: number) => this._docViewInternal?.onContextMenu?.(e, pageX, pageY);
public cleanupPointerEvents = () => this._docViewInternal?.cleanupPointerEvents();
public startDragging = (x: number, y: number, dropAction: dropActionType, hideSource = false) => this._docViewInternal?.startDragging(x, y, dropAction, hideSource);
@@ -1279,7 +1279,22 @@ export class DocumentView extends DocComponent<DocumentViewProps>() {
custom && DocUtils.makeCustomViewClicked(this.Document, Docs.Create.StackingDocument, layout, undefined);
}, 'set custom view');
+ /**
+ * This switches between the current view of a Doc and a specified alternate layout view.
+ * The current view of the Doc is stored in the layout_default field so that it can be restored.
+ * If the current view of the Doc is already the specified alternate layout view, this will switch
+ * back to the original layout (stored in layout_default)
+ * @param detailLayoutKeySuffix the name of the alternate layout field key (NOTE: 'layout_' will be prepended to this string to get the actual field nam)
+ */
+ public toggleDetail = (detailLayoutKeySuffix: string) => {
+ const curLayout = StrCast(this.Document.layout_fieldKey).replace('layout_', '').replace('layout', '');
+ if (!this.Document.layout_default && curLayout !== detailLayoutKeySuffix) this.Document.layout_default = curLayout;
+ const defaultLayout = StrCast(this.Document.layout_default);
+ if (this.Document.layout_fieldKey === 'layout_' + detailLayoutKeySuffix) this.switchViews(defaultLayout ? true : false, defaultLayout, undefined, true);
+ else this.switchViews(true, detailLayoutKeySuffix, undefined, true);
+ };
public switchViews = (custom: boolean, view: string, finished?: () => void, useExistingLayout = false) => {
+ const batch = UndoManager.StartBatch('switchView:' + view);
runInAction(() => this._docViewInternal && (this._docViewInternal._animateScalingTo = 0.1)); // shrink doc
setTimeout(
action(() => {
@@ -1292,6 +1307,7 @@ export class DocumentView extends DocComponent<DocumentViewProps>() {
setTimeout(
action(() => {
this._docViewInternal && (this._docViewInternal._animateScalingTo = 0);
+ batch.end();
finished?.();
}),
Math.max(0, (this._docViewInternal?.animateScaleTime() ?? 0) - 10)
@@ -1451,9 +1467,8 @@ ScriptingGlobals.add(function deiconifyViewToLightbox(documentView: DocumentView
LightboxView.Instance.AddDocTab(documentView.Document, OpenWhere.lightbox, 'layout'); //, 0);
});
-ScriptingGlobals.add(function toggleDetail(dv: DocumentView, detailLayoutKeySuffix: string, defaultLayout = '') {
- if (dv.Document.layout_fieldKey === 'layout_' + detailLayoutKeySuffix) dv.switchViews(defaultLayout ? true : false, defaultLayout, undefined, true);
- else dv.switchViews(true, detailLayoutKeySuffix, undefined, true);
+ScriptingGlobals.add(function toggleDetail(dv: DocumentView, detailLayoutKeySuffix: string) {
+ dv.toggleDetail(detailLayoutKeySuffix);
});
ScriptingGlobals.add(function updateLinkCollection(linkCollection: Doc, linkSource: Doc) {
diff --git a/src/client/views/nodes/KeyValueBox.tsx b/src/client/views/nodes/KeyValueBox.tsx
index 39a45693e..89a5ac0b8 100644
--- a/src/client/views/nodes/KeyValueBox.tsx
+++ b/src/client/views/nodes/KeyValueBox.tsx
@@ -76,7 +76,7 @@ export class KeyValueBox extends ObservableReactComponent<FieldViewProps> {
value = eq ? value.substring(1) : value;
const dubEq = value.startsWith(':=') ? 'computed' : value.startsWith('$=') ? 'script' : false;
value = dubEq ? value.substring(2) : value;
- const options: ScriptOptions = { addReturn: true, typecheck: false, params: { this: Doc.name, self: Doc.name, _last_: 'any', _readOnly_: 'boolean' }, editable: true };
+ const options: ScriptOptions = { addReturn: true, typecheck: false, params: { this: Doc.name, self: Doc.name, documentView: 'any', _last_: 'any', _readOnly_: 'boolean' }, editable: true };
if (dubEq) options.typecheck = false;
const script = CompileScript(value, { ...options, transformer: DocumentIconContainer.getTransformer() });
return !script.compiled ? undefined : { script, type: dubEq, onDelegate: eq };
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 1ff7274f8..1bd230891 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -1574,7 +1574,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
}
if (!state || !editor || !this.ProseRef?.children[0].className.includes('-focused')) return;
if (!state.selection.empty && !(state.selection instanceof NodeSelection)) this.setupAnchorMenu();
- else if (this._props.isContentActive()) {
+ else if (this._props.isContentActive() && !e.button) {
const pcords = editor.posAtCoords({ left: e.clientX, top: e.clientY });
let xpos = pcords?.pos || 0;
while (xpos > 0 && !state.doc.resolve(xpos).node()?.isTextblock) {
@@ -2074,7 +2074,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
onScroll={this.onScroll}
onDrop={this.ondrop}>
<div
- className={`formattedTextBox-inner${rounded} ${this.layoutDoc.layout_centered ? 'centered' : ''}`}
+ className={`formattedTextBox-inner${rounded} ${this.layoutDoc._layout_centered ? 'centered' : ''}`}
ref={this.createDropTarget}
style={{
padding: StrCast(this.layoutDoc._textBoxPadding),
diff --git a/src/client/views/nodes/formattedText/RichTextMenu.tsx b/src/client/views/nodes/formattedText/RichTextMenu.tsx
index cd0cdaa74..dc2c06701 100644
--- a/src/client/views/nodes/formattedText/RichTextMenu.tsx
+++ b/src/client/views/nodes/formattedText/RichTextMenu.tsx
@@ -104,7 +104,7 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> {
return this._activeAlignment;
}
@computed get textVcenter() {
- return BoolCast(this.layoutDoc?.layout_centered);
+ return BoolCast(this.layoutDoc?._layout_centered);
}
_disposer: IReactionDisposer | undefined;
componentDidMount() {
@@ -450,7 +450,7 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> {
}
vcenterToggle = (view: EditorView, dispatch: any) => {
- this.layoutDoc && (this.layoutDoc.layout_centered = !this.layoutDoc.layout_centered);
+ this.layoutDoc && (this.layoutDoc._layout_centered = !this.layoutDoc._layout_centered);
};
align = (view: EditorView, dispatch: any, alignment: 'left' | 'right' | 'center') => {
if (this.TextView?._props.rootSelected?.()) {
diff --git a/src/client/views/nodes/formattedText/RichTextRules.ts b/src/client/views/nodes/formattedText/RichTextRules.ts
index 9bd41f42c..d5c91fc09 100644
--- a/src/client/views/nodes/formattedText/RichTextRules.ts
+++ b/src/client/views/nodes/formattedText/RichTextRules.ts
@@ -78,7 +78,7 @@ export class RichTextRules {
this.TextBox.dataDoc[paintedField] = CollectionView.LayoutString(this.TextBox.fieldKey);
const layoutFieldKey = StrCast(this.TextBox.layoutDoc.layout_fieldKey); // save the current layout fieldkey
this.TextBox.layoutDoc.layout_fieldKey = paintedField; // setup the paint layout field key
- this.TextBox.DocumentView?.().setToggleDetail(layoutFieldKey.replace('layout_', '').replace('layout', ''), 'onPaint'); // create the script to toggle between the painted and regular view
+ this.TextBox.DocumentView?.().setToggleDetail('onPaint'); // create the script to toggle between the painted and regular view
this.TextBox.layoutDoc.layout_fieldKey = layoutFieldKey; // restore the layout field key to text
return state.tr.delete(start, end).setBlockType(start, start, schema.nodes.code_block);