diff options
author | Tyler Schicke <tyler_schicke@brown.edu> | 2019-08-07 21:37:14 -0400 |
---|---|---|
committer | Tyler Schicke <tyler_schicke@brown.edu> | 2019-08-07 21:37:14 -0400 |
commit | 35cb61f0d93983464b29152f159d09ea6bd4edf9 (patch) | |
tree | 85f9ffadb021d85074b6dd9606a9e7551ece4f19 /src | |
parent | 221acd0cfb4831435d1d1b61b86c2cc5e3d3b413 (diff) |
Mostly have field level read only working
Diffstat (limited to 'src')
-rw-r--r-- | src/client/DocServer.ts | 34 | ||||
-rw-r--r-- | src/client/views/MainView.tsx | 8 | ||||
-rw-r--r-- | src/client/views/nodes/WebBox.tsx | 3 | ||||
-rw-r--r-- | src/new_fields/Doc.ts | 38 | ||||
-rw-r--r-- | src/new_fields/util.ts | 11 | ||||
-rw-r--r-- | src/server/GarbageCollector.ts | 2 |
6 files changed, 84 insertions, 12 deletions
diff --git a/src/client/DocServer.ts b/src/client/DocServer.ts index 87a87be92..5af89cf49 100644 --- a/src/client/DocServer.ts +++ b/src/client/DocServer.ts @@ -1,6 +1,6 @@ import * as OpenSocket from 'socket.io-client'; import { MessageStore, Diff, YoutubeQueryTypes } from "./../server/Message"; -import { Opt } from '../new_fields/Doc'; +import { Opt, Doc } from '../new_fields/Doc'; import { Utils, emptyFunction } from '../Utils'; import { SerializationHelper } from './util/SerializationHelper'; import { RefField } from '../new_fields/RefField'; @@ -26,6 +26,38 @@ export namespace DocServer { let GUID: string; // indicates whether or not a document is currently being udpated, and, if so, its id + export enum WriteMode { + Always = 0, + None = 1, + SameUser = 2, + } + + const fieldWriteModes: { [field: string]: WriteMode } = {}; + const docsWithUpdates: { [field: string]: Doc[] } = {}; + + export function setFieldWriteMode(field: string, writeMode: WriteMode) { + fieldWriteModes[field] = writeMode; + if (writeMode === WriteMode.Always) { + const docs = docsWithUpdates[field]; + if (docs) { + docs.forEach(doc => Doc.RunCachedUpdate(doc, field)); + delete docsWithUpdates[field]; + } + } + } + + export function getFieldWriteMode(field: string) { + return fieldWriteModes[field]; + } + + export function registerDocWithCachedUpdate(doc: Doc, field: string) { + let list = docsWithUpdates[field]; + if (!list) { + list = docsWithUpdates[field] = []; + } + list.push(doc); + } + export function init(protocol: string, hostname: string, port: number, identifier: string) { _cache = {}; GUID = identifier; diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 53f589684..7bc31e961 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -422,6 +422,14 @@ export class MainView extends React.Component { </button> </div></li>)} <li key="undoTest"><button className="add-button round-button" title="Click if undo isn't working" onClick={() => UndoManager.TraceOpenBatches()}><FontAwesomeIcon icon="exclamation" size="sm" /></button></li> + <li key="test"><button className="add-button round-button" title="asdf" onClick={(() => { + let state = DocServer.WriteMode.Always; + return () => { + state++; + state = state % 3; + DocServer.setFieldWriteMode("x", state); + }; + })()}><FontAwesomeIcon icon="exclamation" size="sm" /></button></li> <li key="color"><button className="add-button round-button" title="Select Color" style={{ zIndex: 1000 }} onClick={() => this.toggleColorPicker()}><div className="toolbar-color-button" style={{ backgroundColor: InkingControl.Instance.selectedColor }} > <div className="toolbar-color-picker" onClick={this.onColorClick} style={this._colorPickerDisplay ? { color: "black", display: "block" } : { color: "black", display: "none" }}> <SketchPicker color={InkingControl.Instance.selectedColor} onChange={InkingControl.Instance.switchColor} /> diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index 162ac1d98..c8749b7cd 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -8,6 +8,7 @@ import "./WebBox.scss"; import React = require("react"); import { InkTool } from "../../../new_fields/InkField"; import { Cast, FieldValue, NumCast } from "../../../new_fields/Types"; +import { Utils } from "../../../Utils"; @observer export class WebBox extends React.Component<FieldViewProps> { @@ -52,7 +53,7 @@ export class WebBox extends React.Component<FieldViewProps> { if (field instanceof HtmlField) { view = <span id="webBox-htmlSpan" dangerouslySetInnerHTML={{ __html: field.html }} />; } else if (field instanceof WebField) { - view = <iframe src={field.url.href} style={{ position: "absolute", width: "100%", height: "100%" }} />; + view = <iframe src={Utils.CorsProxy(field.url.href)} style={{ position: "absolute", width: "100%", height: "100%" }} />; } else { view = <iframe src={"https://crossorigin.me/https://cs.brown.edu"} style={{ position: "absolute", width: "100%", height: "100%" }} />; } diff --git a/src/new_fields/Doc.ts b/src/new_fields/Doc.ts index c01f4e8cf..ebe3a5ba8 100644 --- a/src/new_fields/Doc.ts +++ b/src/new_fields/Doc.ts @@ -68,6 +68,7 @@ export function DocListCast(field: FieldResult): Doc[] { export const WidthSym = Symbol("Width"); export const HeightSym = Symbol("Height"); +const CachedUpdates = Symbol("Cached updates"); function fetchProto(doc: Doc) { const proto = doc.proto; @@ -147,6 +148,8 @@ export class Doc extends RefField { return "invalid"; } + private [CachedUpdates]: { [key: string]: () => Promise<any> } = {}; + public async [HandleUpdate](diff: any) { const set = diff.$set; if (set) { @@ -154,11 +157,18 @@ export class Doc extends RefField { if (!key.startsWith("fields.")) { continue; } - const value = await SerializationHelper.Deserialize(set[key]); const fKey = key.substring(7); - updatingFromServer = true; - this[fKey] = value; - updatingFromServer = false; + const fn = async () => { + const value = await SerializationHelper.Deserialize(set[key]); + updatingFromServer = true; + this[fKey] = value; + updatingFromServer = false; + }; + if (DocServer.getFieldWriteMode(fKey)) { + this[CachedUpdates][fKey] = fn; + } else { + await fn(); + } } } const unset = diff.$unset; @@ -168,9 +178,16 @@ export class Doc extends RefField { continue; } const fKey = key.substring(7); - updatingFromServer = true; - delete this[fKey]; - updatingFromServer = false; + const fn = async () => { + updatingFromServer = true; + delete this[fKey]; + updatingFromServer = false; + }; + if (DocServer.getFieldWriteMode(fKey)) { + this[CachedUpdates][fKey] = fn; + } else { + await fn(); + } } } } @@ -187,6 +204,13 @@ export namespace Doc { // return Cast(field, ctor); // }); // } + export function RunCachedUpdate(doc: Doc, field: string) { + const update = doc[CachedUpdates][field]; + if (update) { + update(); + delete doc[CachedUpdates][field]; + } + } export function MakeReadOnly(): { end(): void } { makeReadOnly(); return { diff --git a/src/new_fields/util.ts b/src/new_fields/util.ts index c6f693f7f..245b844fb 100644 --- a/src/new_fields/util.ts +++ b/src/new_fields/util.ts @@ -7,6 +7,8 @@ import { ObjectField } from "./ObjectField"; import { action } from "mobx"; import { Parent, OnUpdate, Update, Id, SelfProxy, Self } from "./FieldSymbols"; import { ComputedField } from "./ScriptField"; +import { DocServer } from "../client/DocServer"; +import { CurrentUserUtils } from "../server/authentication/models/current_user_utils"; function _readOnlySetter(): never { throw new Error("Documents can't be modified in read-only mode"); @@ -63,9 +65,14 @@ const _setterImpl = action(function (target: any, prop: string | symbol | number } else { target.__fields[prop] = value; } - if (value === undefined) target[Update]({ '$unset': { ["fields." + prop]: "" } }); + const writeMode = DocServer.getFieldWriteMode(prop as string); if (typeof value === "object" && !(value instanceof ObjectField)) debugger; - else target[Update]({ '$set': { ["fields." + prop]: value instanceof ObjectField ? SerializationHelper.Serialize(value) : (value === undefined ? null : value) } }); + if (!writeMode || (writeMode === DocServer.WriteMode.SameUser && receiver.author === CurrentUserUtils.email)) { + if (value === undefined) target[Update]({ '$unset': { ["fields." + prop]: "" } }); + else target[Update]({ '$set': { ["fields." + prop]: value instanceof ObjectField ? SerializationHelper.Serialize(value) : (value === undefined ? null : value) } }); + } else { + DocServer.registerDocWithCachedUpdate(receiver, prop as string); + } UndoManager.AddEvent({ redo: () => receiver[prop] = value, undo: () => receiver[prop] = curValue diff --git a/src/server/GarbageCollector.ts b/src/server/GarbageCollector.ts index ea5388004..09b52eadf 100644 --- a/src/server/GarbageCollector.ts +++ b/src/server/GarbageCollector.ts @@ -13,7 +13,7 @@ function addDoc(doc: any, ids: string[], files: { [name: string]: string[] }) { if (field === undefined || field === null) { continue; } - if (field.__type === "proxy") { + if (field.__type === "proxy" || field.__type === "prefetch_proxy") { ids.push(field.fieldId); } else if (field.__type === "list") { addDoc(field.fields, ids, files); |