diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/client/views/EditableView.tsx | 113 | ||||
-rw-r--r-- | src/client/views/nodes/LinkDescriptionPopup.tsx | 74 | ||||
-rw-r--r-- | src/client/views/nodes/formattedText/DashDocView.tsx | 30 | ||||
-rw-r--r-- | src/client/views/nodes/formattedText/FormattedTextBox.tsx | 64 | ||||
-rw-r--r-- | src/client/views/nodes/formattedText/RichTextMenu.tsx | 2 |
5 files changed, 158 insertions, 125 deletions
diff --git a/src/client/views/EditableView.tsx b/src/client/views/EditableView.tsx index d7707a6fe..8036df471 100644 --- a/src/client/views/EditableView.tsx +++ b/src/client/views/EditableView.tsx @@ -3,7 +3,7 @@ import { action, observable } from 'mobx'; import { observer } from 'mobx-react'; import * as Autosuggest from 'react-autosuggest'; import { ObjectField } from '../../fields/ObjectField'; -import "./EditableView.scss"; +import './EditableView.scss'; export interface EditableProps { /** @@ -26,17 +26,16 @@ export interface EditableProps { contents: any; fontStyle?: string; fontSize?: number; - height?: number | "auto"; + height?: number | 'auto'; sizeToContent?: boolean; maxHeight?: number; display?: string; overflow?: string; autosuggestProps?: { resetValue: () => void; - value: string, - onChange: (e: React.ChangeEvent, { newValue }: { newValue: string }) => void, - autosuggestProps: Autosuggest.AutosuggestProps<string, any> - + value: string; + onChange: (e: React.ChangeEvent, { newValue }: { newValue: string }) => void; + autosuggestProps: Autosuggest.AutosuggestProps<string, any>; }; oneLine?: boolean; editing?: boolean; @@ -81,16 +80,16 @@ export class EditableView extends React.Component<EditableProps> { @action onKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => { switch (e.key) { - case "Tab": + case 'Tab': e.stopPropagation(); this.finalizeEdit(e.currentTarget.value, e.shiftKey, false, false); this.props.OnTab?.(e.shiftKey); break; - case "Backspace": + case 'Backspace': e.stopPropagation(); if (!e.currentTarget.value) this.props.OnEmpty?.(); break; - case "Enter": + case 'Enter': e.stopPropagation(); if (!e.ctrlKey) { this.finalizeEdit(e.currentTarget.value, e.shiftKey, false, true); @@ -100,22 +99,26 @@ export class EditableView extends React.Component<EditableProps> { this.props.isEditingCallback?.(false); } break; - case "Escape": + case 'Escape': e.stopPropagation(); this._editing = false; this.props.isEditingCallback?.(false); break; - case ":": + case ':': this.props.menuCallback?.(e.currentTarget.getBoundingClientRect().x, e.currentTarget.getBoundingClientRect().y); break; - case "Shift": case "Alt": case "Meta": case "Control": break; + case 'Shift': + case 'Alt': + case 'Meta': + case 'Control': + break; default: if (this.props.textCallback?.(e.key)) { this._editing = false; - this.props.isEditingCallback?.(false,); + this.props.isEditingCallback?.(false); } } - } + }; @action onClick = (e: React.MouseEvent) => { @@ -129,40 +132,44 @@ export class EditableView extends React.Component<EditableProps> { } e.stopPropagation(); } - } + }; @action finalizeEdit(value: string, shiftDown: boolean, lostFocus: boolean, enterKey: boolean) { if (this.props.SetValue(value, shiftDown, enterKey)) { this._editing = false; - this.props.isEditingCallback?.(false,); + this.props.isEditingCallback?.(false); } else { this._editing = false; this.props.isEditingCallback?.(false); - !lostFocus && setTimeout(action(() => { - this._editing = true; - this.props.isEditingCallback?.(true); - }), 0); + !lostFocus && + setTimeout( + action(() => { + this._editing = true; + this.props.isEditingCallback?.(true); + }), + 0 + ); } } - stopPropagation(e: React.SyntheticEvent) { e.stopPropagation(); } + stopPropagation(e: React.SyntheticEvent) { + e.stopPropagation(); + } @action setIsFocused = (value: boolean) => { const wasFocused = this._editing; this._editing = value; return wasFocused !== this._editing; - } - - + }; renderEditor() { - return this.props.autosuggestProps - ? <Autosuggest + return this.props.autosuggestProps ? ( + <Autosuggest {...this.props.autosuggestProps.autosuggestProps} inputProps={{ - className: "editableView-input", + className: 'editableView-input', onKeyDown: this.onKeyDown, autoFocus: true, onBlur: e => this.finalizeEdit(e.currentTarget.value, false, true, false), @@ -171,39 +178,49 @@ export class EditableView extends React.Component<EditableProps> { onPointerUp: this.stopPropagation, onKeyPress: this.stopPropagation, value: this.props.autosuggestProps.value, - onChange: this.props.autosuggestProps.onChange + onChange: this.props.autosuggestProps.onChange, }} /> - : <input className="editableView-input" ref={this._inputref} - style={{ display: this.props.display, overflow: "auto", fontSize: this.props.fontSize, minWidth: 20, background: this.props.background }} + ) : ( + <input + className="editableView-input" + ref={this._inputref} + style={{ display: this.props.display, overflow: 'auto', fontSize: this.props.fontSize, minWidth: 20, background: this.props.background }} placeholder={this.props.placeholder} onBlur={e => this.finalizeEdit(e.currentTarget.value, false, true, false)} defaultValue={this.props.GetValue()} autoFocus={true} onKeyDown={this.onKeyDown} - onKeyPress={this.stopPropagation} onPointerDown={this.stopPropagation} onClick={this.stopPropagation} onPointerUp={this.stopPropagation} - />; + onKeyPress={this.stopPropagation} + onPointerDown={this.stopPropagation} + onClick={this.stopPropagation} + onPointerUp={this.stopPropagation} + /> + ); } render() { if (this._editing && this.props.GetValue() !== undefined) { - return this.props.sizeToContent ? - <div style={{ display: "grid", minWidth: 100 }}> - <div style={{ display: "inline-block", position: "relative", height: 0, width: "100%", overflow: "hidden" }}> - {this.props.GetValue()} - </div> + return this.props.sizeToContent ? ( + <div style={{ display: 'grid', minWidth: 100 }}> + <div style={{ display: 'inline-block', position: 'relative', height: 0, width: '100%', overflow: 'hidden' }}>{this.props.GetValue()}</div> {this.renderEditor()} - </div> : - this.renderEditor(); + </div> + ) : ( + this.renderEditor() + ); } setTimeout(() => this.props.autosuggestProps?.resetValue()); - return this.props.contents instanceof ObjectField ? (null) : - <div className={`editableView-container-editing${this.props.oneLine ? "-oneLine" : ""}`} ref={this._ref} - style={{ display: this.props.display, textOverflow: this.props.overflow, minHeight: "10px", whiteSpace: "nowrap", height: this.props.height || "auto", maxHeight: this.props.maxHeight }} - onClick={this.onClick} placeholder={this.props.placeholder}> - <span style={{ fontStyle: this.props.fontStyle, fontSize: this.props.fontSize }} > - {this.props.contents ? this.props.contents?.valueOf() : this.props.placeholder?.valueOf()} - </span> - </div>; + return this.props.contents instanceof ObjectField ? null : ( + <div + className={`editableView-container-editing${this.props.oneLine ? '-oneLine' : ''}`} + ref={this._ref} + style={{ display: this.props.display, textOverflow: this.props.overflow, minHeight: '10px', whiteSpace: 'nowrap', height: this.props.height || 'auto', maxHeight: this.props.maxHeight }} + onPointerDown={e => e.stopPropagation()} + onClick={this.onClick} + placeholder={this.props.placeholder}> + <span style={{ fontStyle: this.props.fontStyle, fontSize: this.props.fontSize }}>{this.props.contents ? this.props.contents?.valueOf() : this.props.placeholder?.valueOf()}</span> + </div> + ); } -}
\ No newline at end of file +} diff --git a/src/client/views/nodes/LinkDescriptionPopup.tsx b/src/client/views/nodes/LinkDescriptionPopup.tsx index ccac66996..91bd505c5 100644 --- a/src/client/views/nodes/LinkDescriptionPopup.tsx +++ b/src/client/views/nodes/LinkDescriptionPopup.tsx @@ -1,26 +1,24 @@ -import React = require("react"); -import { action, observable } from "mobx"; -import { observer } from "mobx-react"; -import { Doc } from "../../../fields/Doc"; -import { LinkManager } from "../../util/LinkManager"; -import "./LinkDescriptionPopup.scss"; -import { TaskCompletionBox } from "./TaskCompletedBox"; - +import React = require('react'); +import { action, observable } from 'mobx'; +import { observer } from 'mobx-react'; +import { Doc } from '../../../fields/Doc'; +import { LinkManager } from '../../util/LinkManager'; +import './LinkDescriptionPopup.scss'; +import { TaskCompletionBox } from './TaskCompletedBox'; @observer export class LinkDescriptionPopup extends React.Component<{}> { - @observable public static descriptionPopup: boolean = false; - @observable public static showDescriptions: string = "ON"; + @observable public static showDescriptions: string = 'ON'; @observable public static popupX: number = 700; @observable public static popupY: number = 350; - @observable description: string = ""; + @observable description: string = ''; @observable popupRef = React.createRef<HTMLDivElement>(); @action descriptionChanged = (e: React.ChangeEvent<HTMLInputElement>) => { this.description = e.currentTarget.value; - } + }; @action onDismiss = (add: boolean) => { @@ -28,7 +26,7 @@ export class LinkDescriptionPopup extends React.Component<{}> { if (add) { LinkManager.currentLink && (Doc.GetProto(LinkManager.currentLink).description = this.description); } - } + }; @action onClick = (e: PointerEvent) => { @@ -36,35 +34,43 @@ export class LinkDescriptionPopup extends React.Component<{}> { LinkDescriptionPopup.descriptionPopup = false; TaskCompletionBox.taskCompleted = false; } - } + }; @action componentDidMount() { - document.addEventListener("pointerdown", this.onClick); + document.addEventListener('pointerdown', this.onClick, true); } componentWillUnmount() { - document.removeEventListener("pointerdown", this.onClick); + document.removeEventListener('pointerdown', this.onClick, true); } render() { - return <div className="linkDescriptionPopup" ref={this.popupRef} - style={{ - left: LinkDescriptionPopup.popupX ? LinkDescriptionPopup.popupX : 700, - top: LinkDescriptionPopup.popupY ? LinkDescriptionPopup.popupY : 350, - }}> - <input className="linkDescriptionPopup-input" - onKeyDown={e => e.stopPropagation()} - onKeyPress={e => e.key === "Enter" && this.onDismiss(true)} - placeholder={"(Optional) Enter link description..."} - onChange={(e) => this.descriptionChanged(e)}> - </input> - <div className="linkDescriptionPopup-btn"> - <div className="linkDescriptionPopup-btn-dismiss" - onPointerDown={e => this.onDismiss(false)}> Dismiss </div> - <div className="linkDescriptionPopup-btn-add" - onPointerDown={e => this.onDismiss(true)}> Add </div> + return ( + <div + className="linkDescriptionPopup" + ref={this.popupRef} + style={{ + left: LinkDescriptionPopup.popupX ? LinkDescriptionPopup.popupX : 700, + top: LinkDescriptionPopup.popupY ? LinkDescriptionPopup.popupY : 350, + }}> + <input + className="linkDescriptionPopup-input" + onKeyDown={e => e.stopPropagation()} + onKeyPress={e => e.key === 'Enter' && this.onDismiss(true)} + placeholder={'(Optional) Enter link description...'} + onChange={e => this.descriptionChanged(e)}></input> + <div className="linkDescriptionPopup-btn"> + <div className="linkDescriptionPopup-btn-dismiss" onPointerDown={e => this.onDismiss(false)}> + {' '} + Dismiss{' '} + </div> + <div className="linkDescriptionPopup-btn-add" onPointerDown={e => this.onDismiss(true)}> + {' '} + Add{' '} + </div> + </div> </div> - </div>; + ); } -}
\ No newline at end of file +} diff --git a/src/client/views/nodes/formattedText/DashDocView.tsx b/src/client/views/nodes/formattedText/DashDocView.tsx index 08f255cab..73a711b9d 100644 --- a/src/client/views/nodes/formattedText/DashDocView.tsx +++ b/src/client/views/nodes/formattedText/DashDocView.tsx @@ -70,6 +70,8 @@ export class DashDocViewInternal extends React.Component<IDashDocViewInternal> { @observable _dashDoc: Doc | undefined; @observable _finalLayout: any; @observable _resolvedDataDoc: any; + @observable _width: number = 0; + @observable _height: number = 0; updateDoc = action((dashDoc: Doc) => { this._dashDoc = dashDoc; @@ -83,12 +85,14 @@ export class DashDocViewInternal extends React.Component<IDashDocViewInternal> { } if (this.props.width !== (this._dashDoc?._width ?? '') + 'px' || this.props.height !== (this._dashDoc?._height ?? '') + 'px') { try { + this._width = NumCast(this._dashDoc?._width); + this._height = NumCast(this._dashDoc?._height); // bcz: an exception will be thrown if two aliases are open at the same time when a doc view comment is made this.props.view.dispatch( this.props.view.state.tr.setNodeMarkup(this.props.getPos(), null, { ...this.props.node.attrs, - width: (this._dashDoc?._width ?? '') + 'px', - height: (this._dashDoc?._height ?? '') + 'px', + width: this._width + 'px', + height: this._height + 'px', }) ); } catch (e) { @@ -121,17 +125,17 @@ export class DashDocViewInternal extends React.Component<IDashDocViewInternal> { componentDidMount() { this._disposers.upater = reaction( () => this._dashDoc && NumCast(this._dashDoc._height) + NumCast(this._dashDoc._width), - () => { + action(() => { if (this._dashDoc) { - this.props.view.dispatch( - this.props.view.state.tr.setNodeMarkup(this.props.getPos(), null, { - ...this.props.node.attrs, - width: (this._dashDoc?._width ?? '') + 'px', - height: (this._dashDoc?._height ?? '') + 'px', - }) - ); + this._width = NumCast(this._dashDoc._width); + this._height = NumCast(this._dashDoc._height); + const parent = this._spanRef.current?.parentNode as HTMLElement; + if (parent) { + parent.style.width = this._width + 'px'; + parent.style.height = this._height + 'px'; + } } - } + }) ); } @@ -172,8 +176,8 @@ export class DashDocViewInternal extends React.Component<IDashDocViewInternal> { ref={this._spanRef} className="dash-span" style={{ - width: this.props.width, - height: this.props.height, + width: this._width, + height: this._height, position: 'absolute', display: 'inline-block', }} diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx index bbb7ddc85..eb87d11a4 100644 --- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx +++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx @@ -20,7 +20,7 @@ import { RichTextUtils } from '../../../../fields/RichTextUtils'; import { ComputedField } from '../../../../fields/ScriptField'; import { BoolCast, Cast, FieldValue, NumCast, ScriptCast, StrCast } from '../../../../fields/Types'; import { GetEffectiveAcl, TraceMobx } from '../../../../fields/util'; -import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, emptyFunction, numberRange, OmitKeys, returnZero, setupMoveUpEvents, smoothScroll, unimplementedFunction, Utils } from '../../../../Utils'; +import { addStyleSheet, addStyleSheetRule, clearStyleSheetRules, emptyFunction, numberRange, OmitKeys, returnFalse, returnZero, setupMoveUpEvents, smoothScroll, unimplementedFunction, Utils } from '../../../../Utils'; import { GoogleApiClientUtils, Pulls, Pushes } from '../../../apis/google_docs/GoogleApiClientUtils'; import { DocServer } from '../../../DocServer'; import { Docs, DocUtils } from '../../../documents/Documents'; @@ -62,6 +62,7 @@ import { SummaryView } from './SummaryView'; import applyDevTools = require('prosemirror-dev-tools'); import React = require('react'); import { text } from 'body-parser'; +import { CollectionTreeView } from '../../collections/CollectionTreeView'; const translateGoogleApi = require('translate-google-api'); export interface FormattedTextBoxProps { @@ -1500,7 +1501,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps onFocused = (e: React.FocusEvent): void => { //applyDevTools.applyDevTools(this._editorView); FormattedTextBox.Focused = this; - this._editorView && RichTextMenu.Instance?.updateMenu(this._editorView, undefined, this.props); + this.ProseRef?.children[0] === e.nativeEvent.target && this._editorView && RichTextMenu.Instance?.updateMenu(this._editorView, undefined, this.props); }; @observable public static Focused: FormattedTextBox | undefined; @@ -1588,6 +1589,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps @action onBlur = (e: any) => { + if (this.ProseRef?.children[0] !== e.nativeEvent.target) return; this.autoLink(); FormattedTextBox.Focused === this && (FormattedTextBox.Focused = undefined); if (RichTextMenu.Instance?.view === this._editorView && !this.props.isSelected(true)) { @@ -1702,7 +1704,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps }; fitContentsToBox = () => this.props.Document._fitContentsToBox; sidebarContentScaling = () => (this.props.NativeDimScaling?.() || 1) * NumCast(this.layoutDoc._viewScale, 1); - sidebarAddDocument = (doc: Doc | Doc[], sidebarKey?: string) => { + sidebarAddDocument = (doc: Doc | Doc[], sidebarKey: string = this.SidebarKey) => { if (!this.layoutDoc._showSidebar) this.toggleSidebar(); // console.log("printting allSideBarDocs"); // console.log(this.allSidebarDocs); @@ -1716,7 +1718,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps this.props .ScreenToLocalTransform() .translate(-(this.props.PanelWidth() - this.sidebarWidth()) / (this.props.NativeDimScaling?.() || 1), 0) - .scale(1 / NumCast(this.layoutDoc._viewScale, 1)); + .scale(1 / NumCast(this.layoutDoc._viewScale, 1) / (this.props.NativeDimScaling?.() || 1)); @computed get audioHandle() { return ( @@ -1746,7 +1748,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps } @computed get sidebarCollection() { const renderComponent = (tag: string) => { - const ComponentTag = tag === 'freeform' ? CollectionFreeFormView : tag === 'translation' ? FormattedTextBox : CollectionStackingView; + const ComponentTag = tag === 'freeform' ? CollectionFreeFormView : tag === 'tree' ? CollectionTreeView : tag === 'translation' ? FormattedTextBox : CollectionStackingView; return ComponentTag === CollectionStackingView ? ( <SidebarAnnos ref={this._sidebarRef} @@ -1755,6 +1757,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps rootDoc={this.rootDoc} layoutDoc={this.layoutDoc} dataDoc={this.dataDoc} + ScreenToLocalTransform={this.sidebarScreenToLocal} nativeWidth={NumCast(this.layoutDoc._nativeWidth)} whenChildContentsActiveChanged={this.whenChildContentsActiveChanged} showSidebar={this.SidebarShown} @@ -1765,30 +1768,33 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps removeDocument={this.removeDocument} /> ) : ( - <ComponentTag - {...OmitKeys(this.props, ['NativeWidth', 'NativeHeight', 'setContentView']).omit} - NativeWidth={returnZero} - NativeHeight={returnZero} - PanelHeight={this.props.PanelHeight} - PanelWidth={this.sidebarWidth} - xPadding={0} - yPadding={0} - scaleField={this.SidebarKey + '-scale'} - isAnnotationOverlay={false} - select={emptyFunction} - NativeDimScaling={this.sidebarContentScaling} - whenChildContentsActiveChanged={this.whenChildContentsActiveChanged} - removeDocument={this.sidebarRemDocument} - moveDocument={this.sidebarMoveDocument} - addDocument={this.sidebarAddDocument} - CollectionView={undefined} - ScreenToLocalTransform={this.sidebarScreenToLocal} - renderDepth={this.props.renderDepth + 1} - setHeight={this.setSidebarHeight} - fitContentsToBox={this.fitContentsToBox} - noSidebar={true} - fieldKey={this.layoutDoc.sidebarViewType === 'translation' ? `${this.fieldKey}-translation` : `${this.fieldKey}-annotations`} - /> + <div onPointerDown={e => setupMoveUpEvents(this, e, returnFalse, emptyFunction, () => SelectionManager.SelectView(this.props.DocumentView?.()!), true)}> + <ComponentTag + {...OmitKeys(this.props, ['NativeWidth', 'NativeHeight', 'setContentView']).omit} + NativeWidth={returnZero} + NativeHeight={returnZero} + PanelHeight={this.props.PanelHeight} + PanelWidth={this.sidebarWidth} + xPadding={0} + yPadding={0} + scaleField={this.SidebarKey + '-scale'} + isAnnotationOverlay={false} + select={emptyFunction} + NativeDimScaling={this.sidebarContentScaling} + whenChildContentsActiveChanged={this.whenChildContentsActiveChanged} + removeDocument={this.sidebarRemDocument} + moveDocument={this.sidebarMoveDocument} + addDocument={this.sidebarAddDocument} + CollectionView={undefined} + ScreenToLocalTransform={this.sidebarScreenToLocal} + renderDepth={this.props.renderDepth + 1} + setHeight={this.setSidebarHeight} + fitContentsToBox={this.fitContentsToBox} + noSidebar={true} + treeViewHideTitle={true} + fieldKey={this.layoutDoc.sidebarViewType === 'translation' ? `${this.fieldKey}-translation` : `${this.fieldKey}-sidebar`} + /> + </div> ); }; return ( diff --git a/src/client/views/nodes/formattedText/RichTextMenu.tsx b/src/client/views/nodes/formattedText/RichTextMenu.tsx index 22ca76b2e..21326efaa 100644 --- a/src/client/views/nodes/formattedText/RichTextMenu.tsx +++ b/src/client/views/nodes/formattedText/RichTextMenu.tsx @@ -394,7 +394,7 @@ export class RichTextMenu extends AntimodeMenu<AntimodeMenuProps> { // remove all node type and apply the passed-in one to the selected text changeListType = (mapStyle: string) => { const active = this.view?.state && RichTextMenu.Instance.getActiveListStyle(); - const nodeType = this.view?.state.schema.nodes.ordered_list.create({ mapStyle: active === mapStyle ? "" : mapStyle }); + const nodeType = this.view?.state.schema.nodes.ordered_list.create({ mapStyle: active === mapStyle ? '' : mapStyle }); if (!this.view || nodeType?.attrs.mapStyle === '') return; const nextIsOL = this.view.state.selection.$from.nodeAfter?.type === schema.nodes.ordered_list; |