aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/nodes
diff options
context:
space:
mode:
authormonikahedman <monika_hedman@brown.edu>2019-08-23 11:04:56 -0400
committermonikahedman <monika_hedman@brown.edu>2019-08-23 11:04:56 -0400
commitdd4227a125c0cd679f6437fab85b1cd772a34f78 (patch)
tree20f8b37248c3bbcdf68c3e6207f312d54798621b /src/client/views/nodes
parent1fb290bcc1c46214cfd553f31c1282d2694530ea (diff)
parent20f7d2dca1c115c84f6ac89981ef1e3c7c9a2757 (diff)
pulled from master
Diffstat (limited to 'src/client/views/nodes')
-rw-r--r--src/client/views/nodes/ButtonBox.tsx27
-rw-r--r--src/client/views/nodes/CollectionFreeFormDocumentView.tsx2
-rw-r--r--src/client/views/nodes/DocumentView.tsx64
-rw-r--r--src/client/views/nodes/FormattedTextBox.tsx126
-rw-r--r--src/client/views/nodes/KeyValueBox.tsx2
-rw-r--r--src/client/views/nodes/PresBox.tsx282
-rw-r--r--src/client/views/nodes/VideoBox.tsx6
7 files changed, 202 insertions, 307 deletions
diff --git a/src/client/views/nodes/ButtonBox.tsx b/src/client/views/nodes/ButtonBox.tsx
index 8b6f11aac..ca5f0acc2 100644
--- a/src/client/views/nodes/ButtonBox.tsx
+++ b/src/client/views/nodes/ButtonBox.tsx
@@ -15,7 +15,11 @@ import { Doc } from '../../../new_fields/Doc';
import './ButtonBox.scss';
import { observer } from 'mobx-react';
import { DocumentIconContainer } from './DocumentIcon';
-import { StrCast } from '../../../new_fields/Types';
+import { StrCast, BoolCast } from '../../../new_fields/Types';
+import { DragManager } from '../../util/DragManager';
+import { undoBatch } from '../../util/UndoManager';
+import { action, computed } from 'mobx';
+import { List } from '../../../new_fields/List';
library.add(faEdit as any);
@@ -30,10 +34,29 @@ const ButtonDocument = makeInterface(ButtonSchema);
@observer
export class ButtonBox extends DocComponent<FieldViewProps, ButtonDocument>(ButtonDocument) {
public static LayoutString() { return FieldView.LayoutString(ButtonBox); }
+ private dropDisposer?: DragManager.DragDropDisposer;
+ @computed get dataDoc() { return this.props.DataDoc && (BoolCast(this.props.Document.isTemplate) || BoolCast(this.props.DataDoc.isTemplate) || this.props.DataDoc.layout === this.props.Document) ? this.props.DataDoc : Doc.GetProto(this.props.Document); }
+
+
+ protected createDropTarget = (ele: HTMLDivElement) => {
+ if (this.dropDisposer) {
+ this.dropDisposer();
+ }
+ if (ele) {
+ this.dropDisposer = DragManager.MakeDropTarget(ele, { handlers: { drop: this.drop.bind(this) } });
+ }
+ }
+ @undoBatch
+ @action
+ drop = (e: Event, de: DragManager.DropEvent) => {
+ if (de.data instanceof DragManager.DocumentDragData) {
+ Doc.GetProto(this.dataDoc).source = new List<Doc>(de.data.droppedDocuments);
+ }
+ }
render() {
return (
- <div className="buttonBox-outerDiv" >
+ <div className="buttonBox-outerDiv" ref={this.createDropTarget} >
<div className="buttonBox-mainButton" style={{ background: StrCast(this.props.Document.backgroundColor), color: StrCast(this.props.Document.color, "black") }} >{this.Document.text || this.Document.title}</div>
</div>
);
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index ee596c841..7631ecc6c 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -83,7 +83,7 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
transformOrigin: "left top",
position: "absolute",
backgroundColor: "transparent",
- boxShadow: this.props.Document.z ? `#9c9396 ${StrCast(this.props.Document.boxShadow, "10px 10px 0.9vw")}` :
+ boxShadow: this.props.Document.opacity === 0 ? undefined : this.props.Document.z ? `#9c9396 ${StrCast(this.props.Document.boxShadow, "10px 10px 0.9vw")}` :
this.clusterColor ? (
this.props.Document.isBackground ? `0px 0px 50px 50px ${this.clusterColor}` :
`${this.clusterColor} ${StrCast(this.props.Document.boxShadow, `0vw 0vw ${50 / this.props.ContentScaling()}px`)}`) : undefined,
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 9f1d98bb5..31c12c994 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -40,7 +40,7 @@ import { DocumentContentsView } from "./DocumentContentsView";
import "./DocumentView.scss";
import { FormattedTextBox } from './FormattedTextBox';
import React = require("react");
-import { PresBox } from './PresBox';
+import { DocumentType } from '../../documents/DocumentTypes';
const JsxParser = require('react-jsx-parser').default; //TODO Why does this need to be imported like this?
library.add(fa.faTrash);
@@ -295,8 +295,8 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
onClick = async (e: React.MouseEvent) => {
if (e.nativeEvent.cancelBubble) return; // needed because EditableView may stopPropagation which won't apparently stop this event from firing.
- e.stopPropagation();
if (this.onClickHandler && this.onClickHandler.script) {
+ e.stopPropagation();
this.onClickHandler.script.run({ this: this.props.Document.isTemplate && this.props.DataDoc ? this.props.DataDoc : this.props.Document });
e.preventDefault();
return;
@@ -304,6 +304,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
let altKey = e.altKey;
let ctrlKey = e.ctrlKey;
if (this._doubleTap && this.props.renderDepth) {
+ e.stopPropagation();
let fullScreenAlias = Doc.MakeAlias(this.props.Document);
fullScreenAlias.templates = new List<string>();
Doc.UseDetailLayout(fullScreenAlias);
@@ -315,10 +316,13 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
else if (CurrentUserUtils.MainDocId !== this.props.Document[Id] &&
(Math.abs(e.clientX - this._downX) < Utils.DRAG_THRESHOLD &&
Math.abs(e.clientY - this._downY) < Utils.DRAG_THRESHOLD)) {
+ if (BoolCast(this.props.Document.ignoreClick)) {
+ return;
+ }
+ e.stopPropagation();
SelectionManager.SelectDoc(this, e.ctrlKey);
let isExpander = (e.target as any).id === "isExpander";
- if (BoolCast(this.props.Document.isButton) || isExpander) {
- SelectionManager.DeselectAll();
+ if (BoolCast(this.props.Document.isButton) || this.props.Document.type === DocumentType.BUTTON || isExpander) {
let subBulletDocs = await DocListCastAsync(this.props.Document.subBulletDocs);
let maximizedDocs = await DocListCastAsync(this.props.Document.maximizedDocs);
let summarizedDocs = await DocListCastAsync(this.props.Document.summarizedDocs);
@@ -329,6 +333,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
expandedDocs = summarizedDocs ? [...summarizedDocs, ...expandedDocs] : expandedDocs;
// let expandedDocs = [...(subBulletDocs ? subBulletDocs : []), ...(maximizedDocs ? maximizedDocs : []), ...(summarizedDocs ? summarizedDocs : []),];
if (expandedDocs.length) { // bcz: need a better way to associate behaviors with click events on widget-documents
+ SelectionManager.DeselectAll();
let maxLocation = StrCast(this.props.Document.maximizeLocation, "inPlace");
let getDispDoc = (target: Doc) => Object.getOwnPropertyNames(target).indexOf("isPrototype") === -1 ? target : Doc.MakeDelegate(target);
if (altKey || ctrlKey) {
@@ -357,6 +362,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
}
}
else if (linkedDocs.length) {
+ SelectionManager.DeselectAll();
let first = linkedDocs.filter(d => Doc.AreProtosEqual(d.anchor1 as Doc, this.props.Document));
let linkedFwdDocs = first.length ? [first[0].anchor2 as Doc, first[0].anchor1 as Doc] : [expandedDocs[0], expandedDocs[0]];
@@ -394,13 +400,15 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
}
if (this.active) e.stopPropagation(); // events stop at the lowest document that is active.
document.removeEventListener("pointermove", this.onPointerMove);
- document.addEventListener("pointermove", this.onPointerMove);
document.removeEventListener("pointerup", this.onPointerUp);
+ document.addEventListener("pointermove", this.onPointerMove);
document.addEventListener("pointerup", this.onPointerUp);
- // }
}
onPointerMove = (e: PointerEvent): void => {
- if (!e.cancelBubble && this.active) {
+ if (e.cancelBubble && this.active) {
+ document.removeEventListener("pointermove", this.onPointerMove);
+ }
+ else if (!e.cancelBubble && this.active) {
if (!this.props.Document.excludeFromLibrary && (Math.abs(this._downX - e.clientX) > 3 || Math.abs(this._downY - e.clientY) > 3)) {
if (!e.altKey && !this.topMost && e.buttons === 1 && !BoolCast(this.props.Document.lockedPosition)) {
document.removeEventListener("pointermove", this.onPointerMove);
@@ -583,7 +591,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
cm.addItem({ description: "Open...", subitems: subitems, icon: "external-link-alt" });
let existingMake = ContextMenu.Instance.findByDescription("Make...");
let makes: ContextMenuProps[] = existingMake && "subitems" in existingMake ? existingMake.subitems : [];
- makes.push({ description: this.props.Document.isBackground ? "Remove Background" : "Into Background", event: this.makeBackground, icon: BoolCast(this.props.Document.lockedPosition) ? "unlock" : "lock" });
+ makes.push({ description: this.props.Document.isBackground ? "Remove Background" : "Into Background", event: this.makeBackground, icon: this.props.Document.lockedPosition ? "unlock" : "lock" });
makes.push({ description: this.props.Document.isButton ? "Remove Button" : "Into Button", event: this.makeBtnClicked, icon: "concierge-bell" });
makes.push({ description: "OnClick script", icon: "edit", event: () => ScriptBox.EditClickScript(this.props.Document, "onClick") });
makes.push({
@@ -593,6 +601,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
this.makeBtnClicked();
}, icon: "window-restore"
});
+ makes.push({ description: this.props.Document.ignoreClick ? "Selectable" : "Unselectable", event: () => this.props.Document.ignoreClick = !this.props.Document.ignoreClick, icon: this.props.Document.ignoreClick ? "unlock" : "lock" })
!existingMake && cm.addItem({ description: "Make...", subitems: makes, icon: "hand-point-right" });
let existing = ContextMenu.Instance.findByDescription("Layout...");
let layoutItems: ContextMenuProps[] = existing && "subitems" in existing ? existing.subitems : [];
@@ -629,35 +638,6 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
}
});
- cm.addItem({
- description: "Import document", icon: "upload", event: () => {
- const input = document.createElement("input");
- input.type = "file";
- input.accept = ".zip";
- input.onchange = async _e => {
- const files = input.files;
- if (!files) return;
- const file = files[0];
- let formData = new FormData();
- formData.append('file', file);
- formData.append('remap', "true");
- const upload = Utils.prepend("/uploadDoc");
- const response = await fetch(upload, { method: "POST", body: formData });
- const json = await response.json();
- if (json === "error") {
- return;
- }
- const doc = await DocServer.GetRefField(json);
- if (!doc || !(doc instanceof Doc)) {
- return;
- }
- const [x, y] = this.props.ScreenToLocalTransform().transformPoint(e.pageX, e.pageY);
- doc.x = x, doc.y = y;
- this.props.addDocument && this.props.addDocument(doc, false);
- };
- input.click();
- }
- });
cm.addItem({ description: "Delete", event: this.deleteClicked, icon: "trash" });
type User = { email: string, userDocumentId: string };
let usersMenu: ContextMenuProps[] = [];
@@ -745,7 +725,13 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
chromeHeight = () => {
let showOverlays = this.props.showOverlays ? this.props.showOverlays(this.layoutDoc) : undefined;
let showTitle = showOverlays && "title" in showOverlays ? showOverlays.title : StrCast(this.layoutDoc.showTitle);
- return showTitle ? 25 : 0;
+ let templates = Cast(this.layoutDoc.templates, listSpec("string"));
+ if (!showOverlays && templates instanceof List) {
+ templates.map(str => {
+ if (!showTitle && str.indexOf("{props.Document.title}") !== -1) showTitle = "title";
+ });
+ }
+ return (showTitle ? 25 : 0) + 1;// bcz: why 8??
}
get layoutDoc() {
@@ -801,7 +787,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
{!showTitle && !showCaption ? this.contents :
<div style={{ position: "absolute", display: "inline-block", width: "100%", height: "100%", pointerEvents: "none" }}>
- <div style={{ width: "100%", height: showTextTitle ? "calc(100% - 33px)" : "100%", display: "inline-block", position: "absolute", top: showTextTitle ? "29px" : undefined }}>
+ <div style={{ width: "100%", height: showTextTitle ? "calc(100% - 29px)" : "100%", display: "inline-block", position: "absolute", top: showTextTitle ? "29px" : undefined }}>
{this.contents}
</div>
{!showTitle ? (null) :
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 9652a3a78..467f10ab8 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -6,7 +6,7 @@ import { baseKeymap } from "prosemirror-commands";
import { history } from "prosemirror-history";
import { keymap } from "prosemirror-keymap";
import { Fragment, Node, Node as ProsNode, NodeType, Slice } from "prosemirror-model";
-import { EditorState, Plugin, Transaction } from "prosemirror-state";
+import { EditorState, Plugin, Transaction, TextSelection } from "prosemirror-state";
import { EditorView } from "prosemirror-view";
import { DateField } from '../../../new_fields/DateField';
import { Doc, DocListCast, Opt, WidthSym } from "../../../new_fields/Doc";
@@ -35,6 +35,8 @@ import React = require("react");
import { GoogleApiClientUtils, Pulls, Pushes } from '../../apis/google_docs/GoogleApiClientUtils';
import { DocumentDecorations } from '../DocumentDecorations';
import { MainOverlayTextBox } from '../MainOverlayTextBox';
+import { DictationManager } from '../../util/DictationManager';
+import { ReplaceStep } from 'prosemirror-transform';
library.add(faEdit);
library.add(faSmile, faTextHeight, faUpload);
@@ -62,7 +64,7 @@ export const GoogleRef = "googleDocId";
type RichTextDocument = makeInterface<[typeof richTextSchema]>;
const RichTextDocument = makeInterface(richTextSchema);
-type PullHandler = (exportState: GoogleApiClientUtils.Docs.ReadResult, dataDoc: Doc) => void;
+type PullHandler = (exportState: GoogleApiClientUtils.ReadResult, dataDoc: Doc) => void;
@observer
export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTextBoxProps), RichTextDocument>(RichTextDocument) {
@@ -85,7 +87,6 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
private pushReactionDisposer: Opt<IReactionDisposer>;
private dropDisposer?: DragManager.DragDropDisposer;
public get CurrentDiv(): HTMLDivElement { return this._ref.current!; }
- private isGoogleDocsUpdate = false;
@observable _entered = false;
@observable public static InputBoxOverlay?: FormattedTextBox = undefined;
@@ -183,6 +184,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
const marks = tx.storedMarks;
if (marks) { FormattedTextBox._toolTipTextMenu.mark_key_pressed(marks); }
}
+
this._applyingChange = true;
const fieldkey = "preview";
if (this.extensionDoc) this.extensionDoc.text = state.doc.textBetween(0, state.doc.content.size, "\n\n");
@@ -268,6 +270,64 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
}
}
+ recordKeyHandler = (e: KeyboardEvent) => {
+ if (this.props.Document !== SelectionManager.SelectedDocuments()[0].props.Document) {
+ return;
+ }
+ if (e.key === "R" && e.altKey) {
+ e.stopPropagation();
+ e.preventDefault();
+ this.recordBullet();
+ }
+ }
+
+ recordBullet = async () => {
+ let completedCue = "end session";
+ let results = await DictationManager.Controls.listen({
+ interimHandler: this.setCurrentBulletContent,
+ continuous: { indefinite: false },
+ terminators: [completedCue, "bullet", "next"]
+ });
+ if (results && [DictationManager.Controls.Infringed, completedCue].includes(results)) {
+ DictationManager.Controls.stop();
+ return;
+ }
+ this.nextBullet(this._editorView!.state.selection.to);
+ setTimeout(this.recordBullet, 2000);
+ }
+
+ setCurrentBulletContent = (value: string) => {
+ if (this._editorView) {
+ let state = this._editorView.state;
+ let from = state.selection.from;
+ let to = state.selection.to;
+ this._editorView.dispatch(state.tr.insertText(value, from, to));
+ state = this._editorView.state;
+ let updated = TextSelection.create(state.doc, from, from + value.length);
+ this._editorView.dispatch(state.tr.setSelection(updated));
+ }
+ }
+
+ nextBullet = (pos: number) => {
+ if (this._editorView) {
+ let frag = Fragment.fromArray(this.newListItems(2));
+ let slice = new Slice(frag, 2, 2);
+ let state = this._editorView.state;
+ this._editorView.dispatch(state.tr.step(new ReplaceStep(pos, pos, slice)));
+ pos += 4;
+ state = this._editorView.state;
+ this._editorView.dispatch(state.tr.setSelection(TextSelection.create(this._editorView.state.doc, pos, pos)));
+ }
+ }
+
+ private newListItems = (count: number) => {
+ let listItems: any[] = [];
+ for (let i = 0; i < count; i++) {
+ listItems.push(schema.nodes.list_item.create(undefined, schema.nodes.paragraph.create()));
+ }
+ return listItems;
+ }
+
componentDidMount() {
const config = {
schema,
@@ -301,7 +361,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
}
this.pullFromGoogleDoc(this.checkState);
- runInAction(() => DocumentDecorations.Instance.isAnimatingFetch = true);
+ this.dataDoc[GoogleRef] && this.dataDoc.unchanged && runInAction(() => DocumentDecorations.Instance.isAnimatingFetch = true);
this._reactionDisposer = reaction(
() => {
@@ -312,13 +372,6 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
if (this._editorView && !this._applyingChange) {
let updatedState = JSON.parse(incomingValue);
this._editorView.updateState(EditorState.fromJSON(config, updatedState));
- // manually sets cursor selection at the end of the text on focus
- if (this.isGoogleDocsUpdate) {
- this.isGoogleDocsUpdate = false;
- let end = this._editorView.state.doc.content.size - 1;
- updatedState.selection = { type: "text", anchor: end, head: end };
- this._editorView.updateState(EditorState.fromJSON(config, updatedState));
- }
this.tryUpdateHeight();
}
}
@@ -377,25 +430,24 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
this.unhighlightSearchTerms();
}
}, { fireImmediately: true });
+ setTimeout(() => this.tryUpdateHeight(), 0);
}
pushToGoogleDoc = async () => {
- this.pullFromGoogleDoc(async (exportState: GoogleApiClientUtils.Docs.ReadResult, dataDoc: Doc) => {
- let modes = GoogleApiClientUtils.Docs.WriteMode;
+ this.pullFromGoogleDoc(async (exportState: GoogleApiClientUtils.ReadResult, dataDoc: Doc) => {
+ let modes = GoogleApiClientUtils.WriteMode;
let mode = modes.Replace;
- let reference: Opt<GoogleApiClientUtils.Docs.Reference> = Cast(this.dataDoc[GoogleRef], "string");
+ let reference: Opt<GoogleApiClientUtils.Reference> = Cast(this.dataDoc[GoogleRef], "string");
if (!reference) {
mode = modes.Insert;
- reference = {
- title: StrCast(this.dataDoc.title),
- handler: id => this.dataDoc[GoogleRef] = id
- };
+ reference = { service: GoogleApiClientUtils.Service.Documents, title: StrCast(this.dataDoc.title) };
}
let redo = async () => {
let data = Cast(this.dataDoc.data, RichTextField);
if (this._editorView && reference && data) {
let content = data[ToPlainText]();
let response = await GoogleApiClientUtils.Docs.write({ reference, content, mode });
+ response && (this.dataDoc[GoogleRef] = response.documentId);
let pushSuccess = response !== undefined && !("errors" in response);
dataDoc.unchanged = pushSuccess;
DocumentDecorations.Instance.startPushOutcome(pushSuccess);
@@ -415,32 +467,38 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
pullFromGoogleDoc = async (handler: PullHandler) => {
let dataDoc = this.dataDoc;
let documentId = StrCast(dataDoc[GoogleRef]);
- let exportState: GoogleApiClientUtils.Docs.ReadResult = {};
+ let exportState: GoogleApiClientUtils.ReadResult = {};
if (documentId) {
- exportState = await GoogleApiClientUtils.Docs.read({ documentId });
+ exportState = await GoogleApiClientUtils.Docs.read({ identifier: documentId });
}
UndoManager.RunInBatch(() => handler(exportState, dataDoc), Pulls);
}
- updateState = (exportState: GoogleApiClientUtils.Docs.ReadResult, dataDoc: Doc) => {
+ updateState = (exportState: GoogleApiClientUtils.ReadResult, dataDoc: Doc) => {
let pullSuccess = false;
if (exportState !== undefined && exportState.body !== undefined && exportState.title !== undefined) {
- let data = Cast(dataDoc.data, RichTextField);
- if (data) {
+ const data = Cast(dataDoc.data, RichTextField);
+ if (data instanceof RichTextField) {
pullSuccess = true;
- this.isGoogleDocsUpdate = true;
dataDoc.data = new RichTextField(data[FromPlainText](exportState.body));
+ setTimeout(() => {
+ if (this._editorView) {
+ let state = this._editorView.state;
+ let end = state.doc.content.size - 1;
+ this._editorView.dispatch(state.tr.setSelection(TextSelection.create(state.doc, end, end)));
+ }
+ }, 0);
dataDoc.title = exportState.title;
+ this.Document.customTitle = true;
dataDoc.unchanged = true;
}
} else {
delete dataDoc[GoogleRef];
}
DocumentDecorations.Instance.startPullOutcome(pullSuccess);
- this.tryUpdateHeight();
}
- checkState = (exportState: GoogleApiClientUtils.Docs.ReadResult, dataDoc: Doc) => {
+ checkState = (exportState: GoogleApiClientUtils.ReadResult, dataDoc: Doc) => {
if (exportState !== undefined && exportState.body !== undefined && exportState.title !== undefined) {
let data = Cast(dataDoc.data, RichTextField);
if (data) {
@@ -575,7 +633,6 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
if (!this.props.isOverlay) this.props.select(false);
else this._editorView!.focus();
}
- this.tryUpdateHeight();
}
componentWillUnmount() {
@@ -661,6 +718,9 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
@action
onFocused = (e: React.FocusEvent): void => {
+ document.removeEventListener("keypress", this.recordKeyHandler);
+ document.addEventListener("keypress", this.recordKeyHandler);
+ this.tryUpdateHeight();
if (!this.props.isOverlay) {
FormattedTextBox.InputBoxOverlay = this;
} else {
@@ -710,6 +770,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
});
}
onBlur = (e: any) => {
+ document.removeEventListener("keypress", this.recordKeyHandler);
if (this._undoTyping) {
this._undoTyping.end();
this._undoTyping = undefined;
@@ -738,14 +799,11 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
@action
tryUpdateHeight() {
- if (this.props.Document.autoHeight && this._ref.current!.scrollHeight !== 0) {
- // console.log("DT = " + this.props.Document.title + " " + this._ref.current!.clientHeight + " " + this._ref.current!.scrollHeight + " " + this._ref.current!.textContent);
- let xf = this._ref.current!.getBoundingClientRect();
- let scrBounds = this.props.ScreenToLocalTransform().transformBounds(0, 0, xf.width, this._ref.current!.textContent === "" ? 35 : this._ref.current!.scrollHeight);
+ const ChromeHeight = this.props.ChromeHeight;
+ let sh = this._ref.current ? this._ref.current.scrollHeight : 0;
+ if (this.props.Document.autoHeight && sh !== 0) {
let nh = this.props.Document.isTemplate ? 0 : NumCast(this.dataDoc.nativeHeight, 0);
let dh = NumCast(this.props.Document.height, 0);
- let sh = scrBounds.height;
- const ChromeHeight = MainOverlayTextBox.Instance.ChromeHeight;
this.props.Document.height = Math.max(10, (nh ? dh / nh * sh : sh) + (ChromeHeight ? ChromeHeight() : 0));
this.dataDoc.nativeHeight = nh ? sh : undefined;
}
@@ -781,7 +839,7 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
<div className={`formattedTextBox-cont-${style}`} ref={this._ref}
style={{
overflowY: this.props.Document.autoHeight ? "hidden" : "auto",
- height: this.props.height ? this.props.height : undefined,
+ height: this.props.Document.autoHeight ? "max-content" : this.props.height ? this.props.height : undefined,
background: this.props.hideOnLeave ? "rgba(0,0,0 ,0.4)" : undefined,
opacity: this.props.hideOnLeave ? (this._entered || this.props.isSelected() || Doc.IsBrushed(this.props.Document) ? 1 : 0.1) : 1,
color: this.props.color ? this.props.color : this.props.hideOnLeave ? "white" : "inherit",
diff --git a/src/client/views/nodes/KeyValueBox.tsx b/src/client/views/nodes/KeyValueBox.tsx
index 0d4b377dd..653c5c27f 100644
--- a/src/client/views/nodes/KeyValueBox.tsx
+++ b/src/client/views/nodes/KeyValueBox.tsx
@@ -128,7 +128,7 @@ export class KeyValueBox extends React.Component<FieldViewProps> {
let rows: JSX.Element[] = [];
let i = 0;
const self = this;
- for (let key of Object.keys(ids).sort()) {
+ for (let key of Object.keys(ids).slice().sort()) {
rows.push(<KeyValuePair doc={realDoc} ref={(function () {
let oldEl: KeyValuePair | undefined;
return (el: KeyValuePair) => {
diff --git a/src/client/views/nodes/PresBox.tsx b/src/client/views/nodes/PresBox.tsx
index 112d39c32..e376fbddb 100644
--- a/src/client/views/nodes/PresBox.tsx
+++ b/src/client/views/nodes/PresBox.tsx
@@ -12,7 +12,7 @@ import { BoolCast, Cast, FieldValue, NumCast, StrCast } from "../../../new_field
import { Utils } from "../../../Utils";
import { DocumentManager } from "../../util/DocumentManager";
import { undoBatch } from "../../util/UndoManager";
-import PresentationElement, { buttonIndex } from "../presentationview/PresentationElement";
+import PresentationElement from "../presentationview/PresentationElement";
import PresentationViewList from "../presentationview/PresentationList";
import "../presentationview/PresentationView.scss";
import { FieldView, FieldViewProps } from './FieldView';
@@ -45,17 +45,12 @@ export class PresBox extends React.Component<FieldViewProps> { //FieldViewProps?
//Keeping track of the doc for the current presentation -- bcz: keeping a list of current presentations shouldn't be needed. Let users create them, store them, as they see fit.
@computed get curPresentation() { return this.props.Document; }
- //Mapping from presentation ids to a list of doc that represent a group
- @observable groupMappings: Map<String, Doc[]> = new Map();
//mapping from docs to their rendered component
@observable presElementsMappings: Map<Doc, PresentationElement> = new Map();
//variable that holds all the docs in the presentation
@observable childrenDocs: Doc[] = [];
//variable to hold if presentation is started
@observable presStatus: boolean = false;
- //back-up so that presentation stays the way it's when refreshed
- @observable presGroupBackUp: Doc = new Doc();
- @observable presButtonBackUp: Doc = new Doc();
//Mapping of guids to presentations.
@observable presentationsMapping: Map<String, Doc> = new Map();
//Mapping of presentations to guid, so that select option values can be given.
@@ -102,87 +97,11 @@ export class PresBox extends React.Component<FieldViewProps> { //FieldViewProps?
* otherwise initializes.
*/
setPresentationBackUps = async () => {
- //getting both backUp documents
-
- let castedGroupBackUp = Cast(this.curPresentation.presGroupBackUp, Doc);
- let castedButtonBackUp = Cast(this.curPresentation.presButtonBackUp, Doc);
- //if instantiated before
- if (castedGroupBackUp instanceof Promise) {
- castedGroupBackUp.then(doc => {
- let toAssign = doc ? doc : new Doc();
- this.curPresentation.presGroupBackUp = toAssign;
- runInAction(() => this.presGroupBackUp = toAssign);
- if (doc) {
- if (toAssign[Id] === doc[Id]) {
- this.retrieveGroupMappings();
- }
- }
- });
-
- //if never instantiated a store doc yet
- } else if (castedGroupBackUp instanceof Doc) {
- let castedDoc: Doc = await castedGroupBackUp;
- runInAction(() => this.presGroupBackUp = castedDoc);
- this.retrieveGroupMappings();
- } else {
- runInAction(() => {
- let toAssign = new Doc();
- this.presGroupBackUp = toAssign;
- this.curPresentation.presGroupBackUp = toAssign;
-
- });
-
- }
- //if instantiated before
- if (castedButtonBackUp instanceof Promise) {
- castedButtonBackUp.then(doc => {
- let toAssign = doc ? doc : new Doc();
- this.curPresentation.presButtonBackUp = toAssign;
- runInAction(() => this.presButtonBackUp = toAssign);
- });
-
- //if never instantiated a store doc yet
- } else if (castedButtonBackUp instanceof Doc) {
- let castedDoc: Doc = await castedButtonBackUp;
- runInAction(() => this.presButtonBackUp = castedDoc);
-
- } else {
- runInAction(() => {
- let toAssign = new Doc();
- this.presButtonBackUp = toAssign;
- this.curPresentation.presButtonBackUp = toAssign;
- });
-
- }
-
-
//storing the presentation status,ie. whether it was stopped or playing
let presStatusBackUp = BoolCast(this.curPresentation.presStatus);
runInAction(() => this.presStatus = presStatusBackUp);
}
- /**
- * This is the function that is called to retrieve the groups that have been stored and
- * push them to the groupMappings.
- */
- retrieveGroupMappings = async () => {
- let castedGroupDocs = await DocListCastAsync(this.presGroupBackUp.groupDocs);
- if (castedGroupDocs !== undefined) {
- castedGroupDocs.forEach(async (groupDoc: Doc, index: number) => {
- let castedGrouping = await DocListCastAsync(groupDoc.grouping);
- let castedKey = StrCast(groupDoc.presentIdStore, null);
- if (castedGrouping) {
- castedGrouping.forEach((doc: Doc) => {
- doc.presentId = castedKey;
- });
- }
- if (castedGrouping !== undefined && castedKey !== undefined) {
- this.groupMappings.set(castedKey, castedGrouping);
- }
- });
- }
- }
-
//observable means render is re-called every time variable is changed
@observable
collapsed: boolean = false;
@@ -193,17 +112,13 @@ export class PresBox extends React.Component<FieldViewProps> { //FieldViewProps?
if (docAtCurrentNext === undefined) {
return;
}
- //asking for it's presentation id
- let curNextPresId = StrCast(docAtCurrentNext.presentId);
let nextSelected = current + 1;
- //if curDoc is in a group, selection slides until last one, if not it's next one
- if (this.groupMappings.has(curNextPresId)) {
- let currentsArray = this.groupMappings.get(StrCast(docAtCurrentNext.presentId))!;
- nextSelected = current + currentsArray.length - currentsArray.indexOf(docAtCurrentNext);
-
- //end of grup so go beyond
- if (nextSelected === current) nextSelected = current + 1;
+ let presDocs = DocListCast(this.curPresentation.data);
+ for (; nextSelected < presDocs.length - 1; nextSelected++) {
+ if (!this.presElementsMappings.get(presDocs[nextSelected + 1])!.props.document.groupButton) {
+ break;
+ }
}
this.gotoDocument(nextSelected, current);
@@ -219,31 +134,31 @@ export class PresBox extends React.Component<FieldViewProps> { //FieldViewProps?
//asking for its presentation id.
let curPresId = StrCast(docAtCurrent.presentId);
- let prevSelected = current - 1;
+ let prevSelected = current;
let zoomOut: boolean = false;
//checking if this presentation id is mapped to a group, if so chosing the first element in group
- if (this.groupMappings.has(curPresId)) {
- let currentsArray = this.groupMappings.get(StrCast(docAtCurrent.presentId))!;
- prevSelected = current - currentsArray.length + (currentsArray.length - currentsArray.indexOf(docAtCurrent)) - 1;
- //end of grup so go beyond
- if (prevSelected === current) prevSelected = current - 1;
-
- //checking if any of the group members had used zooming in
- currentsArray.forEach((doc: Doc) => {
- //let presElem: PresentationElement | undefined = this.presElementsMappings.get(doc);
- if (this.presElementsMappings.get(doc)!.selected[buttonIndex.Show]) {
- zoomOut = true;
- return;
- }
- });
-
+ let presDocs = DocListCast(this.curPresentation.data);
+ let currentsArray: Doc[] = [];
+ for (; prevSelected > 0 && presDocs[prevSelected].groupButton; prevSelected--) {
+ currentsArray.push(presDocs[prevSelected]);
}
+ prevSelected = Math.max(0, prevSelected - 1);
+
+ //checking if any of the group members had used zooming in
+ currentsArray.forEach((doc: Doc) => {
+ //let presElem: PresentationElement | undefined = this.presElementsMappings.get(doc);
+ if (this.presElementsMappings.get(doc)!.props.document.showButton) {
+ zoomOut = true;
+ return;
+ }
+ });
+
// if a group set that flag to zero or a single element
//If so making sure to zoom out, which goes back to state before zooming action
if (current > 0) {
- if (zoomOut || this.presElementsMappings.get(docAtCurrent)!.selected[buttonIndex.Show]) {
+ if (zoomOut || this.presElementsMappings.get(docAtCurrent)!.showButton) {
let prevScale = NumCast(this.childrenDocs[prevSelected].viewScale, null);
let curScale = DocumentManager.Instance.getScaleOfDocView(this.childrenDocs[current]);
if (prevScale !== undefined) {
@@ -264,19 +179,18 @@ export class PresBox extends React.Component<FieldViewProps> { //FieldViewProps?
*/
showAfterPresented = (index: number) => {
this.presElementsMappings.forEach((presElem: PresentationElement, key: Doc) => {
- let selectedButtons: boolean[] = presElem.selected;
//the order of cases is aligned based on priority
- if (selectedButtons[buttonIndex.HideTillPressed]) {
+ if (presElem.props.document.hideTillShownButton) {
if (this.childrenDocs.indexOf(key) <= index) {
key.opacity = 1;
}
}
- if (selectedButtons[buttonIndex.HideAfter]) {
+ if (presElem.props.document.hideAfterButton) {
if (this.childrenDocs.indexOf(key) < index) {
key.opacity = 0;
}
}
- if (selectedButtons[buttonIndex.FadeAfter]) {
+ if (presElem.props.document.fadeButton) {
if (this.childrenDocs.indexOf(key) < index) {
key.opacity = 0.5;
}
@@ -291,21 +205,19 @@ export class PresBox extends React.Component<FieldViewProps> { //FieldViewProps?
*/
hideIfNotPresented = (index: number) => {
this.presElementsMappings.forEach((presElem: PresentationElement, key: Doc) => {
- let selectedButtons: boolean[] = presElem.selected;
-
//the order of cases is aligned based on priority
- if (selectedButtons[buttonIndex.HideAfter]) {
+ if (presElem.props.document.hideAfterButton) {
if (this.childrenDocs.indexOf(key) >= index) {
key.opacity = 1;
}
}
- if (selectedButtons[buttonIndex.FadeAfter]) {
+ if (presElem.props.document.fadeButton) {
if (this.childrenDocs.indexOf(key) >= index) {
key.opacity = 1;
}
}
- if (selectedButtons[buttonIndex.HideTillPressed]) {
+ if (presElem.props.document.hideTillShownButton) {
if (this.childrenDocs.indexOf(key) > index) {
key.opacity = 0;
}
@@ -320,34 +232,36 @@ export class PresBox extends React.Component<FieldViewProps> { //FieldViewProps?
*/
navigateToElement = async (curDoc: Doc, fromDoc: number) => {
let docToJump: Doc = curDoc;
- let curDocPresId = StrCast(curDoc.presentId, null);
let willZoom: boolean = false;
- //checking if in group
- if (curDocPresId !== undefined) {
- if (this.groupMappings.has(curDocPresId)) {
- let currentDocGroup = this.groupMappings.get(curDocPresId)!;
- currentDocGroup.forEach((doc: Doc, index: number) => {
- let selectedButtons: boolean[] = this.presElementsMappings.get(doc)!.selected;
- if (selectedButtons[buttonIndex.Navigate]) {
- docToJump = doc;
- willZoom = false;
- }
- if (selectedButtons[buttonIndex.Show]) {
- docToJump = doc;
- willZoom = true;
- }
- });
- }
+ let presDocs = DocListCast(this.curPresentation.data);
+ let nextSelected = presDocs.indexOf(curDoc);
+ let currentDocGroups: Doc[] = [];
+ for (; nextSelected < presDocs.length - 1; nextSelected++) {
+ if (!this.presElementsMappings.get(presDocs[nextSelected + 1])!.props.document.groupButton) {
+ break;
+ }
+ currentDocGroups.push(presDocs[nextSelected]);
}
+
+ currentDocGroups.forEach((doc: Doc, index: number) => {
+ if (this.presElementsMappings.get(doc)!.navButton) {
+ docToJump = doc;
+ willZoom = false;
+ }
+ if (this.presElementsMappings.get(doc)!.showButton) {
+ docToJump = doc;
+ willZoom = true;
+ }
+ });
+
//docToJump stayed same meaning, it was not in the group or was the last element in the group
if (docToJump === curDoc) {
//checking if curDoc has navigation open
- let curDocButtons = this.presElementsMappings.get(curDoc)!.selected;
- if (curDocButtons[buttonIndex.Navigate]) {
+ if (this.presElementsMappings.get(curDoc)!.navButton) {
DocumentManager.Instance.jumpToDocument(curDoc, false);
- } else if (curDocButtons[buttonIndex.Show]) {
+ } else if (this.presElementsMappings.get(curDoc)!.showButton) {
let curScale = DocumentManager.Instance.getScaleOfDocView(this.childrenDocs[fromDoc]);
//awaiting jump so that new scale can be found, since jumping is async
await DocumentManager.Instance.jumpToDocument(curDoc, true);
@@ -406,69 +320,6 @@ export class PresBox extends React.Component<FieldViewProps> { //FieldViewProps?
//removing the Presentation Element stored for it
this.presElementsMappings.delete(removedDoc);
- let removedDocPresentId = StrCast(removedDoc.presentId);
-
- //Removing it from local mapping of the groups
- if (this.groupMappings.has(removedDocPresentId)) {
- let removedDocsGroup = this.groupMappings.get(removedDocPresentId);
- if (removedDocsGroup) {
- removedDocsGroup.splice(removedDocsGroup.indexOf(removedDoc), 1);
- if (removedDocsGroup.length === 0) {
- this.groupMappings.delete(removedDocPresentId);
- }
- }
- }
-
- //removing it from the backUp of selected Buttons
- // let castedList = Cast(this.presButtonBackUp.selectedButtonDocs, listSpec(Doc));
- // if (castedList) {
- // castedList.forEach(async (doc, indexOfDoc) => {
- // let curDoc = await doc;
- // let curDocId = StrCast(curDoc.docId);
- // if (curDocId === removedDoc[Id]) {
- // if (castedList) {
- // castedList.splice(indexOfDoc, 1);
- // return;
- // }
- // }
- // });
-
- // }
- //removing it from the backUp of selected Buttons
-
- let castedList = Cast(this.presButtonBackUp.selectedButtonDocs, listSpec(Doc));
- if (castedList) {
- for (let doc of castedList) {
- let curDoc = await doc;
- let curDocId = StrCast(curDoc.docId);
- if (curDocId === removedDoc[Id]) {
- castedList.splice(castedList.indexOf(curDoc), 1);
- break;
-
- }
- }
- }
-
- //removing it from the backup of groups
- let castedGroupDocs = await DocListCastAsync(this.presGroupBackUp.groupDocs);
- if (castedGroupDocs) {
- castedGroupDocs.forEach(async (groupDoc: Doc, index: number) => {
- let castedKey = StrCast(groupDoc.presentIdStore, null);
- if (castedKey === removedDocPresentId) {
- let castedGrouping = await DocListCastAsync(groupDoc.grouping);
- if (castedGrouping) {
- castedGrouping.splice(castedGrouping.indexOf(removedDoc), 1);
- if (castedGrouping.length === 0) {
- castedGroupDocs!.splice(castedGroupDocs!.indexOf(groupDoc), 1);
- }
- }
- }
-
- });
-
- }
-
-
}
}
@@ -489,6 +340,7 @@ export class PresBox extends React.Component<FieldViewProps> { //FieldViewProps?
//it'll also execute the necessary actions if presentation is playing.
@action
public gotoDocument = async (index: number, fromDoc: number) => {
+ Doc.UnBrushAllDocs();
const list = FieldValue(Cast(this.curPresentation.data, listSpec(Doc)));
if (!list) {
return;
@@ -509,26 +361,7 @@ export class PresBox extends React.Component<FieldViewProps> { //FieldViewProps?
this.hideIfNotPresented(index);
this.showAfterPresented(index);
}
-
}
-
- //Function that is called to resetGroupIds, so that documents get new groupIds at
- //first load, when presentation is changed.
- resetGroupIds = async () => {
- let castedGroupDocs = await DocListCastAsync(this.presGroupBackUp.groupDocs);
- if (castedGroupDocs !== undefined) {
- castedGroupDocs.forEach(async (groupDoc: Doc, index: number) => {
- let castedGrouping = await DocListCastAsync(groupDoc.grouping);
- if (castedGrouping) {
- castedGrouping.forEach((doc: Doc) => {
- doc.presentId = Utils.GenerateGuid();
- });
- }
- });
- }
- runInAction(() => this.groupMappings = new Map());
- }
-
//Function that sets the store of the children docs.
@action
setChildrenDocs = (docList: Doc[]) => {
@@ -580,21 +413,19 @@ export class PresBox extends React.Component<FieldViewProps> { //FieldViewProps?
//The function that starts the presentation, also checking if actions should be applied
//directly at start.
startPresentation = (startIndex: number) => {
- let selectedButtons: boolean[];
this.presElementsMappings.forEach((component: PresentationElement, doc: Doc) => {
- selectedButtons = component.selected;
- if (selectedButtons[buttonIndex.HideTillPressed]) {
+ if (component.props.document.hideTillShownButton) {
if (this.childrenDocs.indexOf(doc) > startIndex) {
doc.opacity = 0;
}
}
- if (selectedButtons[buttonIndex.HideAfter]) {
+ if (component.props.document.hideAfterButton) {
if (this.childrenDocs.indexOf(doc) < startIndex) {
doc.opacity = 0;
}
}
- if (selectedButtons[buttonIndex.FadeAfter]) {
+ if (component.props.document.fadeButton) {
if (this.childrenDocs.indexOf(doc) < startIndex) {
doc.opacity = 0.5;
}
@@ -684,12 +515,9 @@ export class PresBox extends React.Component<FieldViewProps> { //FieldViewProps?
mainDocument={this.curPresentation}
deleteDocument={this.RemoveDoc}
gotoDocument={this.gotoDocument}
- groupMappings={this.groupMappings}
PresElementsMappings={this.presElementsMappings}
setChildrenDocs={this.setChildrenDocs}
presStatus={this.presStatus}
- presButtonBackUp={this.presButtonBackUp}
- presGroupBackUp={this.presGroupBackUp}
removeDocByRef={this.removeDocByRef}
clearElemMap={() => this.presElementsMappings.clear()}
/>
diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx
index 704030d85..3f4ee8960 100644
--- a/src/client/views/nodes/VideoBox.tsx
+++ b/src/client/views/nodes/VideoBox.tsx
@@ -34,7 +34,7 @@ library.add(faVideo);
export class VideoBox extends DocComponent<FieldViewProps, VideoDocument>(VideoDocument) {
private _reactionDisposer?: IReactionDisposer;
private _youtubeReactionDisposer?: IReactionDisposer;
- private _youtubePlayer: any = undefined;
+ private _youtubePlayer: YT.Player | undefined = undefined;
private _videoRef: HTMLVideoElement | null = null;
private _youtubeIframeId: number = -1;
private _youtubeContentCreated = false;
@@ -78,7 +78,7 @@ export class VideoBox extends DocComponent<FieldViewProps, VideoDocument>(VideoD
@action public Pause = (update: boolean = true) => {
this.Playing = false;
update && this.player && this.player.pause();
- update && this._youtubePlayer && this._youtubePlayer.pauseVideo();
+ update && this._youtubePlayer && this._youtubePlayer.pauseVideo && this._youtubePlayer.pauseVideo();
this._youtubePlayer && this._playTimer && clearInterval(this._playTimer);
this._playTimer = undefined;
this.updateTimecode();
@@ -244,7 +244,7 @@ export class VideoBox extends DocComponent<FieldViewProps, VideoDocument>(VideoD
let onYoutubePlayerStateChange = (event: any) => runInAction(() => {
if (started && event.data === YT.PlayerState.PLAYING) {
started = false;
- this._youtubePlayer.unMute();
+ this._youtubePlayer && this._youtubePlayer.unMute();
this.Pause();
return;
}