diff options
Diffstat (limited to 'src/client')
| -rw-r--r-- | src/client/util/ProsemirrorExampleTransfer.ts | 17 | ||||
| -rw-r--r-- | src/client/views/DocumentDecorations.tsx | 26 | ||||
| -rw-r--r-- | src/client/views/collections/CollectionSubView.tsx | 5 | ||||
| -rw-r--r-- | src/client/views/collections/CollectionView.tsx | 9 | ||||
| -rw-r--r-- | src/client/views/nodes/FormattedTextBox.tsx | 13 | ||||
| -rw-r--r-- | src/client/views/webcam/DashWebRTCVideo.tsx | 2 | ||||
| -rw-r--r-- | src/client/views/webcam/WebCamLogic.js | 61 |
7 files changed, 68 insertions, 65 deletions
diff --git a/src/client/util/ProsemirrorExampleTransfer.ts b/src/client/util/ProsemirrorExampleTransfer.ts index da3815181..81cf54d4c 100644 --- a/src/client/util/ProsemirrorExampleTransfer.ts +++ b/src/client/util/ProsemirrorExampleTransfer.ts @@ -175,13 +175,16 @@ export default function buildKeymap<S extends Schema<any>>(schema: S, mapKeys?: }); const path = (state.doc.resolve(state.selection.from - 1) as any).path; const spaceSeparator = path[path.length - 3].childCount > 1 ? 0 : -1; - const textsel = TextSelection.create(state.doc, range!.end - path[path.length - 3].lastChild.nodeSize + spaceSeparator, range!.end); - const text = range ? state.doc.textBetween(textsel.from, textsel.to) : ""; - let whitespace = text.length - 1; - for (; whitespace >= 0 && text[whitespace] !== " "; whitespace--) { } - if (text.endsWith(":")) { - dispatch(state.tr.addMark(textsel.from + whitespace + 1, textsel.to, schema.marks.metadata.create() as any). - addMark(textsel.from + whitespace + 1, textsel.to - 2, schema.marks.metadataKey.create() as any)); + const anchor = range!.end - path[path.length - 3].lastChild.nodeSize + spaceSeparator; + if (anchor >= 0) { + const textsel = TextSelection.create(state.doc, anchor, range!.end); + const text = range ? state.doc.textBetween(textsel.from, textsel.to) : ""; + let whitespace = text.length - 1; + for (; whitespace >= 0 && text[whitespace] !== " "; whitespace--) { } + if (text.endsWith(":")) { + dispatch(state.tr.addMark(textsel.from + whitespace + 1, textsel.to, schema.marks.metadata.create() as any). + addMark(textsel.from + whitespace + 1, textsel.to - 2, schema.marks.metadataKey.create() as any)); + } } return false; }); diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 7359835c5..3dfe34234 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -5,7 +5,6 @@ import { action, computed, observable, reaction } from "mobx"; import { observer } from "mobx-react"; import { Doc } from "../../new_fields/Doc"; import { PositionDocument } from '../../new_fields/documentSchemas'; -import { ObjectField } from '../../new_fields/ObjectField'; import { ScriptField } from '../../new_fields/ScriptField'; import { Cast, StrCast } from "../../new_fields/Types"; import { CurrentUserUtils } from '../../server/authentication/models/current_user_utils'; @@ -107,27 +106,10 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> if (key === 13) { const text = e.target.value; if (text.startsWith("::")) { - const targetID = text.slice(2, text.length); + this._accumulatedTitle = text.slice(2, text.length); const promoteDoc = SelectionManager.SelectedDocuments()[0]; - DocUtils.Publish(promoteDoc.props.Document, targetID, promoteDoc.props.addDocument, promoteDoc.props.removeDocument); - } else if (text.startsWith(">")) { - const fieldTemplateView = SelectionManager.SelectedDocuments()[0]; - SelectionManager.DeselectAll(); - const fieldTemplate = fieldTemplateView.props.Document; - const containerView = fieldTemplateView.props.ContainingCollectionView; - const docTemplate = fieldTemplateView.props.ContainingCollectionDoc; - if (containerView && docTemplate) { - const metaKey = text.startsWith(">>") ? text.slice(2, text.length) : text.slice(1, text.length); - if (metaKey !== containerView.props.fieldKey && containerView.props.DataDoc) { - const fd = fieldTemplate.data; - fd instanceof ObjectField && (Doc.GetProto(containerView.props.DataDoc)[metaKey] = ObjectField.MakeCopy(fd)); - } - fieldTemplate.title = metaKey; - Doc.MakeMetadataFieldTemplate(fieldTemplate, Doc.GetProto(docTemplate)); - if (text.startsWith(">>")) { - Doc.GetProto(docTemplate).layout = StrCast(fieldTemplateView.props.Document.layout).replace(/fieldKey={'[^']*'}/, `fieldKey={"${metaKey}"}`); - } - } + Doc.SetInPlace(promoteDoc.props.Document, "title", this._accumulatedTitle, true); + DocUtils.Publish(promoteDoc.props.Document, this._accumulatedTitle, promoteDoc.props.addDocument, promoteDoc.props.removeDocument); } e.target.blur(); } @@ -539,7 +521,7 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> {minimizeIcon} {this._edtingTitle ? <> - <input ref={this._keyinput} className="title" type="text" name="dynbox" value={this._accumulatedTitle} style={{ width: "calc(100% - 20px)" }} + <input ref={this._keyinput} className="title" type="text" name="dynbox" autoComplete="on" value={this._accumulatedTitle} style={{ width: "calc(100% - 20px)" }} onBlur={e => this.titleBlur(true)} onChange={this.titleChanged} onKeyPress={this.titleEntered} /> <div className="publishBox" title="make document referenceable by its title" onPointerDown={e => { diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 20941493f..32480ad4e 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -85,7 +85,10 @@ export function CollectionSubView<T>(schemaCtor: (doc: Doc) => T) { this._childLayoutDisposer && this._childLayoutDisposer(); } - @computed get dataDoc() { return this.props.DataDoc && this.props.Document.isTemplateForField ? Doc.GetProto(this.props.DataDoc) : Doc.GetProto(this.props.Document); } + @computed get dataDoc() { + return (this.props.DataDoc && this.props.Document.isTemplateForField ? Doc.GetProto(this.props.DataDoc) : + this.props.Document.resolvedDataDoc ? this.props.Document : Doc.GetProto(this.props.Document)); // if the layout document has a resolvedDataDoc, then we don't want to get its parent which would be the unexpanded template + } // The data field for rendering this collection will be on the this.props.Document unless we're rendering a template in which case we try to use props.DataDoc. // When a document has a DataDoc but it's not a template, then it contains its own rendering data, but needs to pass the DataDoc through diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 8dd844711..de3e9737f 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -37,6 +37,7 @@ import './CollectionView.scss'; import { CollectionViewBaseChrome } from './CollectionViewChromes'; import { CollectionTimeView } from './CollectionTimeView'; import { CollectionMultirowView } from './collectionMulticolumn/CollectionMultirowView'; +import { List } from '../../../new_fields/List'; export const COLLECTION_BORDER_WIDTH = 2; const path = require('path'); library.add(faTh, faTree, faSquare, faProjectDiagram, faSignature, faThList, faFingerprint, faColumns, faEllipsisV, faImage, faEye as any, faCopy); @@ -132,8 +133,9 @@ export class CollectionView extends Touchable<FieldViewProps> { @action.bound addDocument(doc: Doc): boolean { - const targetDataDoc = this.props.Document[DataSym]; - Doc.AddDocToList(targetDataDoc, this.props.fieldKey, doc); + const targetDataDoc = this.props.Document.resolvedDataDoc && !this.props.Document.isTemplateForField ? this.props.Document : Doc.GetProto(this.props.Document[DataSym]); + targetDataDoc[this.props.fieldKey] = new List<Doc>([...DocListCast(targetDataDoc[this.props.fieldKey]), doc]); // DocAddToList may write to targetdataDoc's parent ... we don't want this. should really change GetProto to GetDataDoc and test for resolvedDataDoc there + // Doc.AddDocToList(targetDataDoc, this.props.fieldKey, doc); targetDataDoc[this.props.fieldKey + "-lastModified"] = new DateField(new Date(Date.now())); Doc.GetProto(doc).lastOpened = new DateField; return true; @@ -143,7 +145,8 @@ export class CollectionView extends Touchable<FieldViewProps> { removeDocument(doc: Doc): boolean { const docView = DocumentManager.Instance.getDocumentView(doc, this.props.ContainingCollectionView); docView && SelectionManager.DeselectDoc(docView); - const value = Cast(this.props.Document[DataSym][this.props.fieldKey], listSpec(Doc), []); + const targetDataDoc = this.props.Document.resolvedDataDoc ? this.props.Document : this.props.Document[DataSym]; + const value = Cast(targetDataDoc[this.props.fieldKey], listSpec(Doc), []); let index = value.reduce((p, v, i) => (v instanceof Doc && v === doc) ? i : p, -1); index = index !== -1 ? index : value.reduce((p, v, i) => (v instanceof Doc && Doc.AreProtosEqual(v, doc)) ? i : p, -1); diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 0cc276458..7fbee8881 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -812,7 +812,11 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps & } static _downEvent: any; + _downX = 0; + _downY = 0; onPointerDown = (e: React.PointerEvent): void => { + this._downX = e.clientX; + this._downY = e.clientY; this.doLinkOnDeselect(); FormattedTextBox._downEvent = true; FormattedTextBoxComment.textBox = this; @@ -923,7 +927,9 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps & // } // } - this.hitBulletTargets(e.clientX, e.clientY, e.shiftKey, false); + if (Math.abs(e.clientX - this._downX) < 4 && Math.abs(e.clientX - this._downX) < 4) { + this.hitBulletTargets(e.clientX, e.clientY, e.shiftKey, false); + } if (this._recording) setTimeout(() => { this.stopDictation(true); setTimeout(() => this.recordDictation(), 500); }, 500); } @@ -955,8 +961,9 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps & addStyleSheetRule(FormattedTextBox._bulletStyleSheet, list_node.attrs.mapStyle + list_node.attrs.bulletStyle + ":hover:before", { background: "lightgray" }); } else if (Math.abs(pos.pos - pos.inside) < 2) { if (!highlightOnly) { - this._editorView!.dispatch(this._editorView!.state.tr.setNodeMarkup(pos.inside, list_node.type, { ...list_node.attrs, visibility: !list_node.attrs.visibility })); - this._editorView!.dispatch(this._editorView!.state.tr.setSelection(TextSelection.create(this._editorView!.state.doc, pos.inside))); + const offset = this._editorView!.state.doc.nodeAt(pos.inside)?.type === schema.nodes.ordered_list ? 1 : 0; + this._editorView!.dispatch(this._editorView!.state.tr.setNodeMarkup(pos.inside + offset, list_node.type, { ...list_node.attrs, visibility: !list_node.attrs.visibility })); + this._editorView!.dispatch(this._editorView!.state.tr.setSelection(TextSelection.create(this._editorView!.state.doc, pos.inside + offset))); } addStyleSheetRule(FormattedTextBox._bulletStyleSheet, list_node.attrs.mapStyle + list_node.attrs.bulletStyle + ":hover:before", { background: "lightgray" }); } diff --git a/src/client/views/webcam/DashWebRTCVideo.tsx b/src/client/views/webcam/DashWebRTCVideo.tsx index 0eefbbc91..cbf75f708 100644 --- a/src/client/views/webcam/DashWebRTCVideo.tsx +++ b/src/client/views/webcam/DashWebRTCVideo.tsx @@ -70,7 +70,7 @@ export class DashWebRTCVideo extends React.Component<CollectionFreeFormDocumentV <div className="webcam-cont" style={{ width: "100%", height: "100%" }} onWheel={this.onPostWheel} onPointerDown={this.onPostPointer} onPointerMove={this.onPostPointer} onPointerUp={this.onPostPointer}> <div className="webcam-header">DashWebRTC</div> <input id="roomName" type="text" placeholder="Enter room name" ref={(e) => this.roomText = e!} onKeyDown={this.onEnterKeyDown} /> - <video id="localVideo" className={"RTCVideo" + (this.remoteVideoAdded ? " side" : " main")} autoPlay playsInline ref={(e) => { + <video id="localVideo" className={"RTCVideo" + (this.remoteVideoAdded ? " side" : " main")} autoPlay playsInline muted ref={(e) => { }}></video> <video id="remoteVideo" className="RTCVideo main" autoPlay playsInline ref={(e) => { }}></video> diff --git a/src/client/views/webcam/WebCamLogic.js b/src/client/views/webcam/WebCamLogic.js index 1e0a749ea..3dfb82465 100644 --- a/src/client/views/webcam/WebCamLogic.js +++ b/src/client/views/webcam/WebCamLogic.js @@ -120,6 +120,38 @@ export function initialize(roomName, handlerUI) { console.log('Getting user media with constraints', constraints); + const requestTurn = (turnURL) => { + var turnExists = false; + for (var i in pcConfig.iceServers) { + if (pcConfig.iceServers[i].urls.substr(0, 5) === 'turn:') { + turnExists = true; + turnReady = true; + break; + } + } + if (!turnExists) { + console.log('Getting TURN server from ', turnURL); + // No TURN server. Get one from computeengineondemand.appspot.com: + var xhr = new XMLHttpRequest(); + xhr.onreadystatechange = function () { + if (xhr.readyState === 4 && xhr.status === 200) { + var turnServer = JSON.parse(xhr.responseText); + console.log('Got TURN server: ', turnServer); + pcConfig.iceServers.push({ + 'urls': 'turn:' + turnServer.username + '@' + turnServer.turn, + 'credential': turnServer.password + }); + turnReady = true; + } + }; + xhr.open('GET', turnURL, true); + xhr.send(); + } + } + + + + if (location.hostname !== 'localhost') { requestTurn( `${window.location.origin}/corsProxy/${encodeURIComponent("https://computeengineondemand.appspot.com/turn?username=41784574&key=4080218913")}` @@ -201,34 +233,7 @@ export function initialize(roomName, handlerUI) { trace('Failed to create session description: ' + error.toString()); } - const requestTurn = (turnURL) => { - var turnExists = false; - for (var i in pcConfig.iceServers) { - if (pcConfig.iceServers[i].urls.substr(0, 5) === 'turn:') { - turnExists = true; - turnReady = true; - break; - } - } - if (!turnExists) { - console.log('Getting TURN server from ', turnURL); - // No TURN server. Get one from computeengineondemand.appspot.com: - var xhr = new XMLHttpRequest(); - xhr.onreadystatechange = function () { - if (xhr.readyState === 4 && xhr.status === 200) { - var turnServer = JSON.parse(xhr.responseText); - console.log('Got TURN server: ', turnServer); - pcConfig.iceServers.push({ - 'urls': 'turn:' + turnServer.username + '@' + turnServer.turn, - 'credential': turnServer.password - }); - turnReady = true; - } - }; - xhr.open('GET', turnURL, true); - xhr.send(); - } - } + const handleRemoteStreamAdded = (event) => { console.log('Remote stream added.'); |
