aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSam Wilkins <samwilkins333@gmail.com>2019-08-19 22:39:56 -0400
committerSam Wilkins <samwilkins333@gmail.com>2019-08-19 22:39:56 -0400
commit00cecb10d80bad8d717cd06ddc4bf156664b9f2d (patch)
treef68193b3cafd52c19181041a564eb473290fc839 /src
parentdf11d1afdb271b37618ab9e1d362b2f4a1145982 (diff)
fixed push pull UI
Diffstat (limited to 'src')
-rw-r--r--src/client/apis/google_docs/GoogleApiClientUtils.ts3
-rw-r--r--src/client/views/DocumentDecorations.tsx14
-rw-r--r--src/client/views/nodes/FormattedTextBox.tsx122
-rw-r--r--src/new_fields/RichTextField.ts8
4 files changed, 81 insertions, 66 deletions
diff --git a/src/client/apis/google_docs/GoogleApiClientUtils.ts b/src/client/apis/google_docs/GoogleApiClientUtils.ts
index 55b4a76f8..821c52270 100644
--- a/src/client/apis/google_docs/GoogleApiClientUtils.ts
+++ b/src/client/apis/google_docs/GoogleApiClientUtils.ts
@@ -4,6 +4,9 @@ import { RouteStore } from "../../../server/RouteStore";
import { Opt } from "../../../new_fields/Doc";
import { isArray } from "util";
+export const Pulls = "googleDocsPullCount";
+export const Pushes = "googleDocsPushCount";
+
export namespace GoogleApiClientUtils {
export namespace Docs {
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 80d4ecb9b..797b43add 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -30,6 +30,7 @@ import { ObjectField } from '../../new_fields/ObjectField';
import { MetadataEntryMenu } from './MetadataEntryMenu';
import { ImageBox } from './nodes/ImageBox';
import { CurrentUserUtils } from '../../server/authentication/models/current_user_utils';
+import { Pulls, Pushes } from '../apis/google_docs/GoogleApiClientUtils';
const higflyout = require("@hig/flyout");
export const { anchorPoints } = higflyout;
export const Flyout = higflyout.default;
@@ -626,7 +627,10 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
if (!canPush) return (null);
return (
<div className={"linkButtonWrapper"}>
- <div title="Push to Google Docs" className="linkButton-linker" onClick={() => thisDoc.pushToGoogleDocsTrigger = !thisDoc.pushToGoogleDocsTrigger}>
+ <div title="Push to Google Docs" className="linkButton-linker" onClick={() => {
+ DocumentDecorations.hasPushedHack = false;
+ thisDoc[Pushes] = NumCast(thisDoc[Pushes]) + 1;
+ }}>
<FontAwesomeIcon className="documentdecorations-icon" icon="arrow-alt-circle-up" size="sm" />
</div>
</div>
@@ -639,13 +643,19 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
if (!canPull) return (null);
return (
<div className={"linkButtonWrapper"}>
- <div title="Pull From Google Docs" className="linkButton-linker" onClick={() => thisDoc.pullFromGoogleDocsTrigger = !thisDoc.pullFromGoogleDocsTrigger}>
+ <div title="Pull From Google Docs" className="linkButton-linker" onClick={() => {
+ DocumentDecorations.hasPulledHack = false;
+ thisDoc[Pulls] = NumCast(thisDoc[Pulls]) + 1;
+ }}>
<FontAwesomeIcon className="documentdecorations-icon" icon="arrow-alt-circle-down" size="sm" />
</div>
</div>
);
}
+ public static hasPushedHack = false;
+ public static hasPulledHack = false;
+
considerTooltip = () => {
let thisDoc = SelectionManager.SelectedDocuments()[0].props.Document;
let isTextDoc = thisDoc.data && thisDoc.data instanceof RichTextField;
diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx
index 406c2c4a6..d2eb71350 100644
--- a/src/client/views/nodes/FormattedTextBox.tsx
+++ b/src/client/views/nodes/FormattedTextBox.tsx
@@ -12,7 +12,7 @@ import { EditorView } from "prosemirror-view";
import { Doc, Opt, DocListCast } from "../../../new_fields/Doc";
import { Id, Copy } from '../../../new_fields/FieldSymbols';
import { List } from '../../../new_fields/List';
-import { RichTextField, ToGoogleDocText, FromGoogleDocText } from "../../../new_fields/RichTextField";
+import { RichTextField, ToPlainText, FromPlainText } from "../../../new_fields/RichTextField";
import { createSchema, listSpec, makeInterface } from "../../../new_fields/Schema";
import { BoolCast, Cast, NumCast, StrCast, DateCast } from "../../../new_fields/Types";
import { DocServer } from "../../DocServer";
@@ -30,16 +30,14 @@ import { ContextMenu } from "../../views/ContextMenu";
import { ContextMenuProps } from '../ContextMenuItem';
import { DocComponent } from "../DocComponent";
import { InkingControl } from "../InkingControl";
-import { Templates } from '../Templates';
import { FieldView, FieldViewProps } from "./FieldView";
import "./FormattedTextBox.scss";
import React = require("react");
-import { For } from 'babel-types';
import { DateField } from '../../../new_fields/DateField';
import { Utils } from '../../../Utils';
import { MainOverlayTextBox } from '../MainOverlayTextBox';
-import { GoogleApiClientUtils } from '../../apis/google_docs/GoogleApiClientUtils';
-import * as diff from "diff";
+import { GoogleApiClientUtils, Pulls, Pushes } from '../../apis/google_docs/GoogleApiClientUtils';
+import { DocumentDecorations } from '../DocumentDecorations';
library.add(faEdit);
library.add(faSmile, faTextHeight, faUpload);
@@ -84,6 +82,8 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
private _searchReactionDisposer?: Lambda;
private _textReactionDisposer: Opt<IReactionDisposer>;
private _proxyReactionDisposer: Opt<IReactionDisposer>;
+ private pullReactionDisposer: Opt<IReactionDisposer>;
+ private pushReactionDisposer: Opt<IReactionDisposer>;
private dropDisposer?: DragManager.DragDropDisposer;
public get CurrentDiv(): HTMLDivElement { return this._ref.current!; }
private isGoogleDocsUpdate = false;
@@ -345,13 +345,25 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
}
);
- reaction(() => this.props.Document.pullFromGoogleDocsTrigger, () => {
- this.pullFromGoogleDoc();
- });
+ this.pullReactionDisposer = reaction(
+ () => this.props.Document[Pulls],
+ () => {
+ if (!DocumentDecorations.hasPulledHack) {
+ DocumentDecorations.hasPulledHack = true;
+ this.pullFromGoogleDoc();
+ }
+ }
+ );
- reaction(() => this.props.Document.pushToGoogleDocsTrigger, () => {
- this.pushToGoogleDoc();
- });
+ this.pushReactionDisposer = reaction(
+ () => this.props.Document[Pushes],
+ () => {
+ if (!DocumentDecorations.hasPushedHack) {
+ DocumentDecorations.hasPushedHack = true;
+ this.pushToGoogleDoc();
+ }
+ }
+ );
this._textReactionDisposer = reaction(
() => this.extensionDoc,
@@ -380,13 +392,44 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
this.unhighlightSearchTerms();
}
}, { fireImmediately: true });
+ }
- ["pushToGoogleDocsTrigger", "pullFromGoogleDocsTrigger"].map(key => {
- let doc = this.props.Document;
- if (doc[key] === undefined) {
- untracked(() => doc[key] = false);
- }
- });
+ pushToGoogleDoc = () => {
+ let modes = GoogleApiClientUtils.Docs.WriteMode;
+ let mode = modes.Replace;
+ let reference: Opt<GoogleApiClientUtils.Docs.Reference> = Cast(this.dataDoc[googleDocId], "string");
+ if (!reference) {
+ mode = modes.Insert;
+ reference = {
+ title: StrCast(this.dataDoc.title),
+ handler: id => this.dataDoc[googleDocId] = id
+ };
+ }
+ if (this._editorView) {
+ let data = Cast(this.dataDoc.data, RichTextField);
+ let content = data ? data[ToPlainText]() : this._editorView.state.doc.textContent;
+ GoogleApiClientUtils.Docs.write({ reference, content, mode });
+ }
+ }
+
+ pullFromGoogleDoc = async () => {
+ let dataDoc = Doc.GetProto(this.props.Document);
+ let documentId = StrCast(dataDoc[googleDocId]);
+ if (documentId) {
+ let exportState = await GoogleApiClientUtils.Docs.read({ documentId });
+ UndoManager.RunInBatch(() => {
+ if (exportState && exportState.body && exportState.title) {
+ let data = Cast(dataDoc.data, RichTextField);
+ if (data) {
+ this.isGoogleDocsUpdate = true;
+ dataDoc.data = new RichTextField(data[FromPlainText](exportState.body));
+ dataDoc.title = exportState.title;
+ }
+ } else {
+ delete dataDoc[googleDocId];
+ }
+ }, Pulls);
+ }
}
clipboardTextSerializer = (slice: Slice): string => {
@@ -516,6 +559,8 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
this._reactionDisposer && this._reactionDisposer();
this._proxyReactionDisposer && this._proxyReactionDisposer();
this._textReactionDisposer && this._textReactionDisposer();
+ this.pushReactionDisposer && this.pushReactionDisposer();
+ this.pullReactionDisposer && this.pullReactionDisposer();
}
onPointerDown = (e: React.PointerEvent): void => {
@@ -693,49 +738,6 @@ export class FormattedTextBox extends DocComponent<(FieldViewProps & FormattedTe
event: action(() => Doc.GetProto(this.props.Document).autoHeight = !BoolCast(this.props.Document.autoHeight)), icon: "expand-arrows-alt"
});
ContextMenu.Instance.addItem({ description: "Text Funcs...", subitems: subitems, icon: "text-height" });
- if (!(googleDocId in Doc.GetProto(this.props.Document))) {
- ContextMenu.Instance.addItem({
- description: "Export to Google Doc...",
- event: this.pushToGoogleDoc,
- icon: "upload"
- });
- }
- }
-
- pushToGoogleDoc = () => {
- let modes = GoogleApiClientUtils.Docs.WriteMode;
- let mode = modes.Replace;
- let reference: Opt<GoogleApiClientUtils.Docs.Reference> = Cast(this.dataDoc[googleDocId], "string");
- if (!reference) {
- mode = modes.Insert;
- reference = {
- title: StrCast(this.dataDoc.title),
- handler: id => this.dataDoc[googleDocId] = id
- };
- }
- if (this._editorView) {
- let data = Cast(this.dataDoc.data, RichTextField);
- let content = data ? data[ToGoogleDocText]() : this._editorView.state.doc.textContent;
- GoogleApiClientUtils.Docs.write({ reference, content, mode });
- }
- }
-
- pullFromGoogleDoc = async () => {
- let dataDoc = Doc.GetProto(this.props.Document);
- let documentId = StrCast(dataDoc[googleDocId]);
- if (documentId) {
- let exportState = await GoogleApiClientUtils.Docs.read({ documentId });
- if (exportState && exportState.body && exportState.title) {
- let data = Cast(dataDoc.data, RichTextField);
- if (data) {
- this.isGoogleDocsUpdate = true;
- dataDoc.data = new RichTextField(data[FromGoogleDocText](exportState.body));
- dataDoc.title = exportState.title;
- }
- } else {
- delete dataDoc[googleDocId];
- }
- }
}
diff --git a/src/new_fields/RichTextField.ts b/src/new_fields/RichTextField.ts
index ec08293e9..ab58329f9 100644
--- a/src/new_fields/RichTextField.ts
+++ b/src/new_fields/RichTextField.ts
@@ -4,8 +4,8 @@ import { Deserializable } from "../client/util/SerializationHelper";
import { Copy, ToScriptString } from "./FieldSymbols";
import { scriptingGlobal } from "../client/util/Scripting";
-export const ToGoogleDocText = Symbol("PlainText");
-export const FromGoogleDocText = Symbol("PlainText");
+export const ToPlainText = Symbol("PlainText");
+export const FromPlainText = Symbol("PlainText");
const delimiter = "\n";
const joiner = "";
@@ -28,7 +28,7 @@ export class RichTextField extends ObjectField {
return `new RichTextField("${this.Data}")`;
}
- [ToGoogleDocText]() {
+ [ToPlainText]() {
// Because we're working with plain text, just concatenate all paragraphs
let content = JSON.parse(this.Data).doc.content;
let paragraphs = content.filter((item: any) => item.type === "paragraph");
@@ -43,7 +43,7 @@ export class RichTextField extends ObjectField {
return textParagraphs.join(joiner).trimEnd(delimiter);
}
- [FromGoogleDocText](plainText: string) {
+ [FromPlainText](plainText: string) {
// Remap the text, creating blocks split on newlines
let elements = plainText.split(delimiter);