From d1b9049fe50e401ac1a33177babd0cfa4b32f6a0 Mon Sep 17 00:00:00 2001 From: andrewdkim Date: Wed, 12 Feb 2020 03:37:51 -0500 Subject: can select text from web node and upload from mobile --- src/client/util/DragManager.ts | 1 - src/client/views/nodes/FormattedTextBox.tsx | 28 ++++++------ src/client/views/nodes/WebBox.tsx | 50 +++++++++++++++------- src/mobile/MobileInterface.tsx | 20 +++++++++ .../authentication/models/current_user_utils.ts | 1 + 5 files changed, 70 insertions(+), 30 deletions(-) (limited to 'src') diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index bf64e0bdb..5d4b8fc8a 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -289,7 +289,6 @@ export namespace DragManager { if (!ele.parentNode) dragDiv.appendChild(ele); const dragElement = ele.parentNode === dragDiv ? ele : ele.cloneNode(true) as HTMLElement; const rect = ele.getBoundingClientRect(); - console.log("boudning", rect); const scaleX = rect.width / ele.offsetWidth, scaleY = rect.height / ele.offsetHeight; xs.push(rect.left); diff --git a/src/client/views/nodes/FormattedTextBox.tsx b/src/client/views/nodes/FormattedTextBox.tsx index 0d97c3029..213af43c6 100644 --- a/src/client/views/nodes/FormattedTextBox.tsx +++ b/src/client/views/nodes/FormattedTextBox.tsx @@ -700,7 +700,7 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps & setTimeout(async () => { const targetField = Doc.LayoutFieldKey(pdfDoc); const targetAnnotations = await DocListCastAsync(pdfDoc[DataSym][targetField + "-annotations"]);// bcz: better to have the PDF's view handle updating its own annotations - targetAnnotations?.push(pdfRegion); + targetAnnotations ?.push(pdfRegion); }); const link = DocUtils.MakeLink({ doc: this.props.Document, ctx: this.props.ContainingCollectionDoc }, { doc: pdfRegion, ctx: pdfDoc }, "note on " + pdfDoc.title, "pasted PDF link"); @@ -742,14 +742,14 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps & const rtfField = Cast(this.props.Document._textTemplate || this.dataDoc[fieldKey], RichTextField); if (this.ProseRef) { const self = this; - this._editorView?.destroy(); + this._editorView ?.destroy(); this._editorView = new EditorView(this.ProseRef, { - state: rtfField?.Data ? EditorState.fromJSON(config, JSON.parse(rtfField.Data)) : EditorState.create(config), + state: rtfField ?.Data ? EditorState.fromJSON(config, JSON.parse(rtfField.Data)) : EditorState.create(config), handleScrollToSelection: (editorView) => { const ref = editorView.domAtPos(editorView.state.selection.from); let refNode = ref.node as any; while (refNode && !("getBoundingClientRect" in refNode)) refNode = refNode.parentElement; - const r1 = refNode?.getBoundingClientRect(); + const r1 = refNode ?.getBoundingClientRect(); const r3 = self._ref.current!.getBoundingClientRect(); if (r1.top < r3.top || r1.top > r3.bottom) { r1 && (self._scrollRef.current!.scrollTop += (r1.top - r3.top) * self.props.ScreenToLocalTransform().Scale); @@ -848,11 +848,11 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps & this.tryUpdateHeight(); // see if we need to preserve the insertion point - const prosediv = this.ProseRef?.children?.[0] as any; - const keeplocation = prosediv?.keeplocation; + const prosediv = this.ProseRef ?.children ?.[0] as any; + const keeplocation = prosediv ?.keeplocation; prosediv && (prosediv.keeplocation = undefined); - const pos = this._editorView?.state.selection.$from.pos || 1; - keeplocation && setTimeout(() => this._editorView?.dispatch(this._editorView?.state.tr.setSelection(TextSelection.create(this._editorView.state.doc, pos)))); + const pos = this._editorView ?.state.selection.$from.pos || 1; + keeplocation && setTimeout(() => this._editorView ?.dispatch(this._editorView ?.state.tr.setSelection(TextSelection.create(this._editorView.state.doc, pos)))); // jump rich text menu to this textbox const { current } = this._ref; @@ -876,13 +876,13 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps & if ((this._editorView!.root as any).getSelection().isCollapsed) { // this is a hack to allow the cursor to be placed at the end of a document when the document ends in an inline dash comment. Apparently Chrome on Windows has a bug/feature which breaks this when clicking after the end of the text. const pcords = this._editorView!.posAtCoords({ left: e.clientX, top: e.clientY }); const node = pcords && this._editorView!.state.doc.nodeAt(pcords.pos); // get what prosemirror thinks the clicked node is (if it's null, then we didn't click on any text) - if (pcords && node?.type === this._editorView!.state.schema.nodes.dashComment) { + if (pcords && node ?.type === this._editorView!.state.schema.nodes.dashComment) { this._editorView!.dispatch(this._editorView!.state.tr.setSelection(TextSelection.create(this._editorView!.state.doc, pcords.pos + 2))); e.preventDefault(); } if (!node && this.ProseRef) { const lastNode = this.ProseRef.children[this.ProseRef.children.length - 1].children[this.ProseRef.children[this.ProseRef.children.length - 1].children.length - 1]; // get the last prosemirror div - if (e.clientY > lastNode?.getBoundingClientRect().bottom) { // if we clicked below the last prosemirror div, then set the selection to be the end of the document + if (e.clientY > lastNode ?.getBoundingClientRect().bottom) { // if we clicked below the last prosemirror div, then set the selection to be the end of the document this._editorView!.dispatch(this._editorView!.state.tr.setSelection(TextSelection.create(this._editorView!.state.doc, this._editorView!.state.doc.content.size))); } } @@ -939,7 +939,7 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps & for (let off = 1; off < 100; off++) { const pos = this._editorView!.posAtCoords({ left: x + off, top: y }); const node = pos && this._editorView!.state.doc.nodeAt(pos.pos); - if (node?.type === schema.nodes.list_item) { + if (node ?.type === schema.nodes.list_item) { list_node = node; break; } @@ -984,7 +984,7 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps & const self = FormattedTextBox; return new Plugin({ view(newView) { - RichTextMenu.Instance.changeView(newView); + RichTextMenu.Instance && RichTextMenu.Instance.changeView(newView); return RichTextMenu.Instance; } }); @@ -1021,7 +1021,7 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps & } if (e.key === "Escape") { this._editorView!.dispatch(state.tr.setSelection(TextSelection.create(state.doc, state.selection.from, state.selection.from))); - (document.activeElement as any).blur?.(); + (document.activeElement as any).blur ?.(); SelectionManager.DeselectAll(); } e.stopPropagation(); @@ -1043,7 +1043,7 @@ export class FormattedTextBox extends DocAnnotatableComponent<(FieldViewProps & @action tryUpdateHeight(limitHeight?: number) { - let scrollHeight = this._ref.current?.scrollHeight; + let scrollHeight = this._ref.current ?.scrollHeight; if (!this.layoutDoc.animateToPos && this.layoutDoc._autoHeight && scrollHeight && getComputedStyle(this._ref.current!.parentElement!).top === "0px") { // if top === 0, then the text box is growing upward (as the overlay caption) which doesn't contribute to the height computation if (limitHeight && scrollHeight > limitHeight) { diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index 6cae4e878..0b7c3eda9 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -24,6 +24,7 @@ import { documentSchema } from "../../../new_fields/documentSchemas"; import { Id } from "../../../new_fields/FieldSymbols"; import { DragManager } from "../../util/DragManager"; import { ImageUtils } from "../../util/Import & Export/ImageUtils"; +import { select } from "async"; library.add(faStickyNote); @@ -189,30 +190,37 @@ export class WebBox extends DocAnnotatableComponent // find the pressed element in the iframe (currently only works if its an img) let pressedElement: HTMLElement | undefined; let pressedBound: ClientRect | undefined; + let selectedText: string = ""; if (this._iframeRef.current) { const B = this._iframeRef.current.getBoundingClientRect(); const iframeDoc = this._iframeRef.current.contentDocument; if (B && iframeDoc) { // check if there is selected text - const selectedText = iframeDoc.getSelection(); - if (selectedText && selectedText.toString.length > -1) { - - } - console.log("selectedText", selectedText ? selectedText.toString() : ""); - - // TODO: this only works when scale = 1 as it is currently only inteded for mobile upload - const element = iframeDoc.elementFromPoint(this._pressX - B.left, this._pressY - B.top); - console.log("found element", element, element && element.nodeName); - if (element && element.nodeName) {//} === "IMG") { - pressedBound = element.getBoundingClientRect(); - pressedElement = element.cloneNode(true) as HTMLElement; + const text = iframeDoc.getSelection(); + if (text && text.toString().length > 0) { + selectedText = text.toString(); + + // get html of the selected text + const range = text.getRangeAt(0); + const contents = range.cloneContents(); + const div = document.createElement("div"); + div.appendChild(contents); + pressedElement = div; + + pressedBound = range.getBoundingClientRect(); + } else { + // TODO: this only works when scale = 1 as it is currently only inteded for mobile upload + const element = iframeDoc.elementFromPoint(this._pressX - B.left, this._pressY - B.top); + if (element && element.nodeName) {//} === "IMG") { + pressedBound = element.getBoundingClientRect(); + pressedElement = element.cloneNode(true) as HTMLElement; + } } } } // mark the pressed element if (pressedElement && pressedBound) { - console.log("clones b", pressedElement.getBoundingClientRect(), pressedBound); if (this._iframeIndicatorRef.current) { this._iframeIndicatorRef.current.style.top = pressedBound.top + "px"; this._iframeIndicatorRef.current.style.left = pressedBound.left + "px"; @@ -224,13 +232,25 @@ export class WebBox extends DocAnnotatableComponent // start dragging the pressed element if long pressed this._longPressSecondsHack = setTimeout(() => { - if (pressedElement && pressedBound) { + if (selectedText && pressedBound && pressedElement) { + e.stopPropagation(); + e.preventDefault(); + // create doc with the selected text's html + const doc = Docs.Create.HtmlDocument(pressedElement.innerHTML); + + // create dragging ghost with the selected text + if (this._iframeDragRef.current) this._iframeDragRef.current.appendChild(pressedElement); + + // start the drag + const dragData = new DragManager.DocumentDragData([doc]); + DragManager.StartDocumentDrag([pressedElement], dragData, this._pressX - pressedBound.top, this._pressY - pressedBound.top, { hideSource: true }); + } else if (pressedElement && pressedBound) { e.stopPropagation(); e.preventDefault(); if (pressedElement.nodeName === "IMG") { const src = pressedElement.getAttribute("src"); // TODO: may not always work if (src) { - const doc = Docs.Create.ImageDocument(src, { _width: 300 }); + const doc = Docs.Create.ImageDocument(src); ImageUtils.ExtractExif(doc); // add clone to div so that dragging ghost is placed properly diff --git a/src/mobile/MobileInterface.tsx b/src/mobile/MobileInterface.tsx index 83410b99d..0c2ed8156 100644 --- a/src/mobile/MobileInterface.tsx +++ b/src/mobile/MobileInterface.tsx @@ -35,6 +35,9 @@ import GoogleAuthenticationManager from '../client/apis/GoogleAuthenticationMana import { listSpec } from '../new_fields/Schema'; import { Id } from '../new_fields/FieldSymbols'; import { DocumentManager } from '../client/util/DocumentManager'; +import RichTextMenu from '../client/util/RichTextMenu'; +import { WebField } from "../new_fields/URLField"; +import { FieldResult } from "../new_fields/Doc"; library.add(faLongArrowAltLeft); @@ -235,6 +238,20 @@ export default class MobileInterface extends React.Component { e.preventDefault(); } + addWebToCollection = async () => { + let url = "https://en.wikipedia.org/wiki/Hedgehog"; + if (this.mainContainer) { + const data = Cast(this.mainContainer.data, listSpec(Doc)); + if (data) { + const webDoc = await data[0]; + const urlField: FieldResult = Cast(webDoc.data, WebField); + url = urlField ? urlField.url.toString() : "https://en.wikipedia.org/wiki/Hedgehog"; + + } + } + Docs.Create.WebDocument(url, { _width: 300, _height: 300, title: "Mobile Upload Web Doc" }); + } + renderUploadContent() { if (this.mainContainer) { return ( @@ -244,6 +261,7 @@ export default class MobileInterface extends React.Component {
+ {/* */}
@@ -302,6 +320,7 @@ export default class MobileInterface extends React.Component { {/* */} + {/* */} @@ -315,4 +334,5 @@ Scripting.addGlobal(function onSwitchMobileInking() { return MobileInterface.Ins Scripting.addGlobal(function renderMobileInking() { return MobileInterface.Instance.renderInkingContent(); }); Scripting.addGlobal(function onSwitchMobileUpload() { return MobileInterface.Instance.onSwitchUpload(); }); Scripting.addGlobal(function renderMobileUpload() { return MobileInterface.Instance.renderUploadContent(); }); +Scripting.addGlobal(function addWebToMobileUpload() { return MobileInterface.Instance.addWebToCollection(); }); diff --git a/src/server/authentication/models/current_user_utils.ts b/src/server/authentication/models/current_user_utils.ts index 6c916689a..71da0b380 100644 --- a/src/server/authentication/models/current_user_utils.ts +++ b/src/server/authentication/models/current_user_utils.ts @@ -155,6 +155,7 @@ export class CurrentUserUtils { } static setupMobileUploadDoc(userDoc: Doc) { + // const addButton = Docs.Create.FontIconDocument({ onDragStart: ScriptField.MakeScript('addWebToMobileUpload()'), title: "Add Web Doc to Upload Collection", icon: "plus", backgroundColor: "black" }) const webDoc = Docs.Create.WebDocument("https://www.britannica.com/animal/cat", { title: "Upload Images From the Web", _chromeStatus: "enabled", lockedPosition: true }); -- cgit v1.2.3-70-g09d2 From 6edcf16fff7461e12800a6619488205a5c420470 Mon Sep 17 00:00:00 2001 From: andrewdkim Date: Wed, 12 Feb 2020 20:29:57 -0500 Subject: merge --- src/client/views/GestureOverlay.tsx | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx index 78a5389d2..e8e9e8c28 100644 --- a/src/client/views/GestureOverlay.tsx +++ b/src/client/views/GestureOverlay.tsx @@ -146,13 +146,9 @@ export default class GestureOverlay extends Touchable { const nts = this.getNewTouches(te); if (nts.nt.length < 5) { const target = document.elementFromPoint(te.changedTouches.item(0).clientX, te.changedTouches.item(0).clientY); -<<<<<<< HEAD - target ?.dispatchEvent( -======= te.changedTouches.item(0).identifier; console.log(te.touches); - target?.dispatchEvent( ->>>>>>> 33d5a12af14e1ed50e5c3164b363fbbc253506a0 + target ?.dispatchEvent( new CustomEvent>("dashOnTouchStart", { bubbles: true, @@ -173,7 +169,7 @@ export default class GestureOverlay extends Touchable { const target = document.elementFromPoint(te.changedTouches.item(0).clientX, te.changedTouches.item(0).clientY); let pt: any = te.touches[te.touches.length - 1]; if (nts.nt.length === 1 && pt.radiusX > 1 && pt.radiusY > 1) { - target?.dispatchEvent( + target ?.dispatchEvent( new CustomEvent>("dashOnTouchHoldStart", { bubbles: true, -- cgit v1.2.3-70-g09d2 From 0299ecb4db88560fe623b429f36191402c00b264 Mon Sep 17 00:00:00 2001 From: kimdahey Date: Wed, 12 Feb 2020 21:26:19 -0500 Subject: changed priority of mobile iframe selection from text to image --- package-lock.json | 4 +-- src/client/views/nodes/WebBox.tsx | 64 ++++++++++++++++++++------------------- src/mobile/MobileInkOverlay.tsx | 2 +- src/mobile/MobileInterface.tsx | 25 ++++++++++----- 4 files changed, 54 insertions(+), 41 deletions(-) (limited to 'src') diff --git a/package-lock.json b/package-lock.json index ec265527d..1741b50dc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16242,7 +16242,7 @@ }, "string_decoder": { "version": "1.1.1", - "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { "safe-buffer": "~5.1.0" @@ -18563,7 +18563,7 @@ }, "wrap-ansi": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "resolved": "http://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", "requires": { "string-width": "^1.0.1", diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index 0b7c3eda9..f1620b80e 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -191,29 +191,31 @@ export class WebBox extends DocAnnotatableComponent let pressedElement: HTMLElement | undefined; let pressedBound: ClientRect | undefined; let selectedText: string = ""; + let pressedImg: boolean = false; if (this._iframeRef.current) { const B = this._iframeRef.current.getBoundingClientRect(); const iframeDoc = this._iframeRef.current.contentDocument; if (B && iframeDoc) { - // check if there is selected text - const text = iframeDoc.getSelection(); - if (text && text.toString().length > 0) { - selectedText = text.toString(); - - // get html of the selected text - const range = text.getRangeAt(0); - const contents = range.cloneContents(); - const div = document.createElement("div"); - div.appendChild(contents); - pressedElement = div; - - pressedBound = range.getBoundingClientRect(); + // TODO: this only works when scale = 1 as it is currently only inteded for mobile upload + const element = iframeDoc.elementFromPoint(this._pressX - B.left, this._pressY - B.top); + if (element && element.nodeName === "IMG") { + pressedBound = element.getBoundingClientRect(); + pressedElement = element.cloneNode(true) as HTMLElement; + pressedImg = true; } else { - // TODO: this only works when scale = 1 as it is currently only inteded for mobile upload - const element = iframeDoc.elementFromPoint(this._pressX - B.left, this._pressY - B.top); - if (element && element.nodeName) {//} === "IMG") { - pressedBound = element.getBoundingClientRect(); - pressedElement = element.cloneNode(true) as HTMLElement; + // check if there is selected text + const text = iframeDoc.getSelection(); + if (text && text.toString().length > 0) { + selectedText = text.toString(); + + // get html of the selected text + const range = text.getRangeAt(0); + const contents = range.cloneContents(); + const div = document.createElement("div"); + div.appendChild(contents); + pressedElement = div; + + pressedBound = range.getBoundingClientRect(); } } } @@ -232,19 +234,7 @@ export class WebBox extends DocAnnotatableComponent // start dragging the pressed element if long pressed this._longPressSecondsHack = setTimeout(() => { - if (selectedText && pressedBound && pressedElement) { - e.stopPropagation(); - e.preventDefault(); - // create doc with the selected text's html - const doc = Docs.Create.HtmlDocument(pressedElement.innerHTML); - - // create dragging ghost with the selected text - if (this._iframeDragRef.current) this._iframeDragRef.current.appendChild(pressedElement); - - // start the drag - const dragData = new DragManager.DocumentDragData([doc]); - DragManager.StartDocumentDrag([pressedElement], dragData, this._pressX - pressedBound.top, this._pressY - pressedBound.top, { hideSource: true }); - } else if (pressedElement && pressedBound) { + if (pressedImg && pressedElement && pressedBound) { e.stopPropagation(); e.preventDefault(); if (pressedElement.nodeName === "IMG") { @@ -260,6 +250,18 @@ export class WebBox extends DocAnnotatableComponent DragManager.StartDocumentDrag([pressedElement], dragData, this._pressX, this._pressY, { hideSource: true }); } } + } else if (selectedText && pressedBound && pressedElement) { + e.stopPropagation(); + e.preventDefault(); + // create doc with the selected text's html + const doc = Docs.Create.HtmlDocument(pressedElement.innerHTML); + + // create dragging ghost with the selected text + if (this._iframeDragRef.current) this._iframeDragRef.current.appendChild(pressedElement); + + // start the drag + const dragData = new DragManager.DocumentDragData([doc]); + DragManager.StartDocumentDrag([pressedElement], dragData, this._pressX - pressedBound.top, this._pressY - pressedBound.top, { hideSource: true }); } }, 1500); } diff --git a/src/mobile/MobileInkOverlay.tsx b/src/mobile/MobileInkOverlay.tsx index f00c77203..1537ae034 100644 --- a/src/mobile/MobileInkOverlay.tsx +++ b/src/mobile/MobileInkOverlay.tsx @@ -78,7 +78,7 @@ export default class MobileInkOverlay extends React.Component { }; const target = document.elementFromPoint(this._x + 10, this._y + 10); - target ?.dispatchEvent( + target?.dispatchEvent( new CustomEvent("dashOnGesture", { bubbles: true, diff --git a/src/mobile/MobileInterface.tsx b/src/mobile/MobileInterface.tsx index 0c2ed8156..5d3a517ae 100644 --- a/src/mobile/MobileInterface.tsx +++ b/src/mobile/MobileInterface.tsx @@ -38,6 +38,7 @@ import { DocumentManager } from '../client/util/DocumentManager'; import RichTextMenu from '../client/util/RichTextMenu'; import { WebField } from "../new_fields/URLField"; import { FieldResult } from "../new_fields/Doc"; +import { List } from '../new_fields/List'; library.add(faLongArrowAltLeft); @@ -252,18 +253,28 @@ export default class MobileInterface extends React.Component { Docs.Create.WebDocument(url, { _width: 300, _height: 300, title: "Mobile Upload Web Doc" }); } + clearUpload = async () => { + if (this.mainContainer) { + const data = Cast(this.mainContainer.data, listSpec(Doc)); + if (data) { + const collectionDoc = await data[1]; + const children = DocListCast(collectionDoc.data); + children.forEach(doc => { + }); + // collectionDoc[data] = new List(); + } + } + } + renderUploadContent() { if (this.mainContainer) { return (
-
- -
-
- {/* */} - -
+ + {/* */} + {/* */} +