From e87727dd111a5370a064e675b9b7c966cb84dfb0 Mon Sep 17 00:00:00 2001 From: bob Date: Mon, 22 Jul 2019 15:46:53 -0400 Subject: fixed link following to video frames. --- src/client/views/nodes/DocumentView.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index e0975f7bd..9429f0d78 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -351,7 +351,7 @@ export class DocumentView extends DocComponent(Docu // @TODO: shouldn't always follow target context let linkedFwdContextDocs = [first.length ? await (first[0].targetContext) as Doc : undefined, undefined]; - let linkedFwdPage = [first.length ? NumCast(first[0].linkedToPage, undefined) : undefined, undefined]; + let linkedFwdPage = [first.length ? NumCast(first[0].anchor2Page, undefined) : undefined, undefined]; if (!linkedFwdDocs.some(l => l instanceof Promise)) { let maxLocation = StrCast(linkedFwdDocs[0].maximizeLocation, "inTab"); -- cgit v1.2.3-70-g09d2 From c351d0d4f6f4e8492cade7d3056e516178f4a138 Mon Sep 17 00:00:00 2001 From: bob Date: Mon, 22 Jul 2019 17:08:25 -0400 Subject: fixed seeking for html video player element --- .../views/collections/CollectionVideoView.tsx | 40 +++++++++++++++++----- src/client/views/nodes/VideoBox.tsx | 1 + 2 files changed, 33 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/client/views/collections/CollectionVideoView.tsx b/src/client/views/collections/CollectionVideoView.tsx index d7d5773ba..31a8a93e0 100644 --- a/src/client/views/collections/CollectionVideoView.tsx +++ b/src/client/views/collections/CollectionVideoView.tsx @@ -7,6 +7,8 @@ import { CollectionBaseView, CollectionRenderProps, CollectionViewType } from ". import { CollectionFreeFormView } from "./collectionFreeForm/CollectionFreeFormView"; import "./CollectionVideoView.scss"; import React = require("react"); +import { InkingControl } from "../InkingControl"; +import { InkTool } from "../../../new_fields/InkField"; @observer @@ -19,18 +21,19 @@ export class CollectionVideoView extends React.Component { private get uIButtons() { let scaling = Math.min(1.8, this.props.ScreenToLocalTransform().Scale); let curTime = NumCast(this.props.Document.curPage); - return (VideoBox._showControls ? [] : [ -
- {"" + Math.round(curTime)} - {" " + Math.round((curTime - Math.trunc(curTime)) * 100)} -
, + return ([
+ {"" + Math.round(curTime)} + {" " + Math.round((curTime - Math.trunc(curTime)) * 100)} +
, + VideoBox._showControls ? (null) : [
{this._videoBox && this._videoBox.Playing ? "\"" : ">"}
,
F
- ]); + + ]]); } @action @@ -53,12 +56,33 @@ export class CollectionVideoView extends React.Component { } } + _isclick = 0; @action - onResetDown = () => { + onResetDown = (e: React.PointerEvent) => { if (this._videoBox) { this._videoBox.Pause(); - this.props.Document.curPage = 0; + e.stopPropagation(); + this._isclick = 0; + document.addEventListener("pointermove", this.onPointerMove, true); + document.addEventListener("pointerup", this.onPointerUp, true); + InkingControl.Instance.switchTool(InkTool.Eraser); + } + } + + @action + onPointerMove = (e: PointerEvent) => { + this._isclick += Math.abs(e.movementX) + Math.abs(e.movementY); + if (this._videoBox) { + this._videoBox.Seek(Math.max(0, NumCast(this.props.Document.curPage, 0) + Math.sign(e.movementX) * 0.0333)); } + e.stopImmediatePropagation(); + } + @action + onPointerUp = (e: PointerEvent) => { + document.removeEventListener("pointermove", this.onPointerMove, true); + document.removeEventListener("pointerup", this.onPointerUp, true); + InkingControl.Instance.switchTool(InkTool.None); + this._isclick < 10 && (this.props.Document.curPage = 0); } setVideoBox = (videoBox: VideoBox) => { this._videoBox = videoBox; }; diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx index 83ad2a3b3..5624d41a9 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -65,6 +65,7 @@ export class VideoBox extends DocComponent(VideoD @action public Seek(time: number) { this._youtubePlayer && this._youtubePlayer.seekTo(Math.round(time), true); + this.player && (this.player.currentTime = time); } @action public Pause = (update: boolean = true) => { -- cgit v1.2.3-70-g09d2 From de46e5c8a6b484f56a18df53dded58697d6efa51 Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Mon, 22 Jul 2019 17:30:20 -0400 Subject: detailed view toggle on return key pressed --- src/client/views/GlobalKeyHandler.ts | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src') diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts index f378b6c0c..e8a588e58 100644 --- a/src/client/views/GlobalKeyHandler.ts +++ b/src/client/views/GlobalKeyHandler.ts @@ -4,6 +4,7 @@ import { CollectionDockingView } from "./collections/CollectionDockingView"; import { MainView } from "./MainView"; import { DragManager } from "../util/DragManager"; import { action } from "mobx"; +import { Doc } from "../../new_fields/Doc"; const modifiers = ["control", "meta", "shift", "alt"]; type KeyHandler = (keycode: string, e: KeyboardEvent) => KeyControlInfo; @@ -82,6 +83,9 @@ export default class KeyManager { }); }, "delete"); break; + case "enter": + SelectionManager.SelectedDocuments().map(selected => Doc.ToggleDetailLayout(selected.props.Document)); + break; } return { -- cgit v1.2.3-70-g09d2 From cc712e50e41bbe720299b5ab5f2d316c4d4c218a Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Tue, 23 Jul 2019 00:54:03 -0400 Subject: cognitive services, not broken so far --- src/client/cognitive_services/CognitiveServices.ts | 134 +++++++++++++++++++++ src/server/RouteStore.ts | 3 + 2 files changed, 137 insertions(+) create mode 100644 src/client/cognitive_services/CognitiveServices.ts (limited to 'src') diff --git a/src/client/cognitive_services/CognitiveServices.ts b/src/client/cognitive_services/CognitiveServices.ts new file mode 100644 index 000000000..1a002e025 --- /dev/null +++ b/src/client/cognitive_services/CognitiveServices.ts @@ -0,0 +1,134 @@ +import * as request from "request-promise"; +import { Doc, Field } from "../../new_fields/Doc"; +import { Cast } from "../../new_fields/Types"; +import { ImageField } from "../../new_fields/URLField"; +import { values } from "mobx"; +import { List } from "../../new_fields/List"; +import { Docs } from "../documents/Documents"; +import { Result } from "../northstar/model/idea/idea"; +import { RouteStore } from "../../server/RouteStore"; +import { Utils } from "../../Utils"; + +export enum Services { + ComputerVision, + Face +} + +export enum Confidence { + Yikes = 0.0, + Unlikely = 0.2, + Poor = 0.4, + Fair = 0.6, + Good = 0.8, + Excellent = 0.95 +} + +export type Tag = { name: string, confidence: number }; +export type Rectangle = { top: number, left: number, width: number, height: number }; +export type Face = { faceAttributes: any, faceId: string, faceRectangle: Rectangle }; +export type Converter = (results: any) => Field; + +/** + * A file that handles all interactions with Microsoft Azure's Cognitive + * Services APIs. These machine learning endpoints allow basic data analytics for + * various media types. + */ +export namespace CognitiveServices { + + export namespace Image { + + export const analyze = async (imageUrl: string, service: Services) => { + return fetch(Utils.prepend(RouteStore.cognitiveServices + service)).then(async response => { + let apiKey = await response.text(); + if (apiKey) { + return; + } + let uriBase; + let parameters; + + switch (service) { + case Services.Face: + uriBase = 'face/v1.0/detect'; + parameters = { + 'returnFaceId': 'true', + 'returnFaceLandmarks': 'false', + 'returnFaceAttributes': 'age,gender,headPose,smile,facialHair,glasses,' + + 'emotion,hair,makeup,occlusion,accessories,blur,exposure,noise' + }; + break; + case Services.ComputerVision: + uriBase = 'vision/v2.0/analyze'; + parameters = { + 'visualFeatures': 'Categories,Description,Color,Objects,Tags,Adult', + 'details': 'Celebrities,Landmarks', + 'language': 'en', + }; + break; + } + + const options = { + uri: 'https://eastus.api.cognitive.microsoft.com/' + uriBase, + qs: parameters, + body: `{"url": "${imageUrl}"}`, + headers: { + 'Content-Type': 'application/json', + 'Ocp-Apim-Subscription-Key': apiKey + } + }; + + let results: any; + try { + results = await request.post(options).then(response => JSON.parse(response)); + } catch (e) { + results = undefined; + } + return results; + }); + }; + + const analyzeDocument = async (target: Doc, service: Services, converter: Converter, storageKey: string) => { + let imageData = Cast(target.data, ImageField); + if (!imageData || await Cast(target[storageKey], Doc)) { + return; + } + let toStore: any; + let results = await analyze(imageData.url.href, service); + if (!results) { + toStore = "Cognitive Services could not process the given image URL."; + } else { + if (!results.length) { + toStore = converter(results); + } else { + toStore = results.length > 0 ? converter(results) : "Empty list returned."; + } + } + target[storageKey] = toStore; + }; + + export const generateMetadata = async (target: Doc, threshold: Confidence = Confidence.Excellent) => { + let converter = (results: any) => { + let tagDoc = new Doc; + results.tags.map((tag: Tag) => { + if (tag.confidence >= +threshold) { + tagDoc[tag.name] = tag.confidence; + } + }); + tagDoc.title = "Generated Tags"; + tagDoc.confidenceThreshold = threshold.toString(); + return tagDoc; + }; + analyzeDocument(target, Services.ComputerVision, converter, "generatedTags"); + }; + + export const extractFaces = async (target: Doc) => { + let converter = (results: any) => { + let faceDocs = new List(); + results.map((face: Face) => faceDocs.push(Docs.Get.DocumentHierarchyFromJson(face, `Face: ${face.faceId}`)!)); + return faceDocs; + }; + analyzeDocument(target, Services.Face, converter, "faces"); + }; + + } + +} \ No newline at end of file diff --git a/src/server/RouteStore.ts b/src/server/RouteStore.ts index 5c13495ff..96bd62e23 100644 --- a/src/server/RouteStore.ts +++ b/src/server/RouteStore.ts @@ -29,4 +29,7 @@ export enum RouteStore { forgot = "/forgotpassword", reset = "/reset/:token", + // APIS + cognitiveServices = "/cognitiveservices/" + } \ No newline at end of file -- cgit v1.2.3-70-g09d2 From 6248a0a4afd154b84ebea1202a48bec0fd4b87de Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Tue, 23 Jul 2019 01:10:09 -0400 Subject: fixed server compilation bug --- src/client/cognitive_services/CognitiveServices.ts | 4 +--- src/server/RouteStore.ts | 2 +- src/server/index.ts | 15 +++++++++++++++ 3 files changed, 17 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/client/cognitive_services/CognitiveServices.ts b/src/client/cognitive_services/CognitiveServices.ts index 1a002e025..2a3fe1d26 100644 --- a/src/client/cognitive_services/CognitiveServices.ts +++ b/src/client/cognitive_services/CognitiveServices.ts @@ -2,10 +2,8 @@ import * as request from "request-promise"; import { Doc, Field } from "../../new_fields/Doc"; import { Cast } from "../../new_fields/Types"; import { ImageField } from "../../new_fields/URLField"; -import { values } from "mobx"; import { List } from "../../new_fields/List"; import { Docs } from "../documents/Documents"; -import { Result } from "../northstar/model/idea/idea"; import { RouteStore } from "../../server/RouteStore"; import { Utils } from "../../Utils"; @@ -38,7 +36,7 @@ export namespace CognitiveServices { export namespace Image { export const analyze = async (imageUrl: string, service: Services) => { - return fetch(Utils.prepend(RouteStore.cognitiveServices + service)).then(async response => { + return fetch(Utils.prepend(`${RouteStore.cognitiveServices}/${service}`)).then(async response => { let apiKey = await response.text(); if (apiKey) { return; diff --git a/src/server/RouteStore.ts b/src/server/RouteStore.ts index 96bd62e23..e30015e39 100644 --- a/src/server/RouteStore.ts +++ b/src/server/RouteStore.ts @@ -30,6 +30,6 @@ export enum RouteStore { reset = "/reset/:token", // APIS - cognitiveServices = "/cognitiveservices/" + cognitiveServices = "/cognitiveservices" } \ No newline at end of file diff --git a/src/server/index.ts b/src/server/index.ts index 6b4e59bfc..d808e8158 100644 --- a/src/server/index.ts +++ b/src/server/index.ts @@ -284,6 +284,21 @@ addSecureRoute( RouteStore.getCurrUser ); +addSecureRoute(Method.GET, (user, res, req) => { + let requested = req.params.requestedservice; + console.log(requested); + switch (requested) { + case "Face": + res.send(process.env.FACE); + break; + case "ComputerVision": + res.send(process.env.VISION); + break; + default: + res.send(undefined); + } +}, undefined, `${RouteStore.cognitiveServices}/:requestedservice`); + class NodeCanvasFactory { create = (width: number, height: number) => { var canvas = createCanvas(width, height); -- cgit v1.2.3-70-g09d2 From 010c7978ce19392b4f02bdea29e734ac2abac01f Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Tue, 23 Jul 2019 01:33:14 -0400 Subject: further non-breaking cognitive services --- src/client/cognitive_services/CognitiveServices.ts | 8 ++++---- src/client/views/nodes/ImageBox.tsx | 18 +++++++++++++----- src/server/index.ts | 5 ++--- 3 files changed, 19 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/client/cognitive_services/CognitiveServices.ts b/src/client/cognitive_services/CognitiveServices.ts index 2a3fe1d26..d525455cb 100644 --- a/src/client/cognitive_services/CognitiveServices.ts +++ b/src/client/cognitive_services/CognitiveServices.ts @@ -8,8 +8,8 @@ import { RouteStore } from "../../server/RouteStore"; import { Utils } from "../../Utils"; export enum Services { - ComputerVision, - Face + ComputerVision = "vision", + Face = "face" } export enum Confidence { @@ -38,8 +38,8 @@ export namespace CognitiveServices { export const analyze = async (imageUrl: string, service: Services) => { return fetch(Utils.prepend(`${RouteStore.cognitiveServices}/${service}`)).then(async response => { let apiKey = await response.text(); - if (apiKey) { - return; + if (!apiKey) { + return undefined; } let uriBase; let parameters; diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index c3ee1e823..f88150d66 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -25,6 +25,7 @@ import { Docs } from '../../documents/Documents'; import { DocServer } from '../../DocServer'; import { Font } from '@react-pdf/renderer'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { CognitiveServices } from '../../cognitive_services/CognitiveServices'; var requestImageSize = require('../../util/request-image-size'); var path = require('path'); const { Howl, Howler } = require('howler'); @@ -195,10 +196,10 @@ export class ImageBox extends DocComponent(ImageD let field = Cast(this.Document[this.props.fieldKey], ImageField); if (field) { let url = field.url.href; - let subitems: ContextMenuProps[] = []; - subitems.push({ description: "Copy path", event: () => Utils.CopyText(url), icon: "expand-arrows-alt" }); - subitems.push({ description: "Record 1sec audio", event: this.recordAudioAnnotation, icon: "expand-arrows-alt" }); - subitems.push({ + let funcs: ContextMenuProps[] = []; + funcs.push({ description: "Copy path", event: () => Utils.CopyText(url), icon: "expand-arrows-alt" }); + funcs.push({ description: "Record 1sec audio", event: this.recordAudioAnnotation, icon: "expand-arrows-alt" }); + funcs.push({ description: "Rotate", event: action(() => { let proto = Doc.GetProto(this.props.Document); let nw = this.props.Document.nativeWidth; @@ -212,7 +213,14 @@ export class ImageBox extends DocComponent(ImageD this.props.Document.height = w; }), icon: "expand-arrows-alt" }); - ContextMenu.Instance.addItem({ description: "Image Funcs...", subitems: subitems }); + + let modes: ContextMenuProps[] = []; + let dataDoc = Doc.GetProto(this.Document); + modes.push({ description: "Generate Tags", event: () => CognitiveServices.Image.generateMetadata(dataDoc), icon: "tag" }); + modes.push({ description: "Find Faces", event: () => CognitiveServices.Image.extractFaces(dataDoc), icon: "camera" }); + + ContextMenu.Instance.addItem({ description: "Image Funcs...", subitems: funcs }); + ContextMenu.Instance.addItem({ description: "Analyze...", subitems: modes }); } } diff --git a/src/server/index.ts b/src/server/index.ts index d808e8158..5b086a2cf 100644 --- a/src/server/index.ts +++ b/src/server/index.ts @@ -286,12 +286,11 @@ addSecureRoute( addSecureRoute(Method.GET, (user, res, req) => { let requested = req.params.requestedservice; - console.log(requested); switch (requested) { - case "Face": + case "face": res.send(process.env.FACE); break; - case "ComputerVision": + case "vision": res.send(process.env.VISION); break; default: -- cgit v1.2.3-70-g09d2 From 767901272eeea30137330e710cc8cf70fd34f1de Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Tue, 23 Jul 2019 03:13:08 -0400 Subject: autotag based on confidence, allow concealment of computed fields that resolve to undefined with namespace constant ComputedField.undefined --- src/client/cognitive_services/CognitiveServices.ts | 11 ++++-- src/client/views/nodes/FaceRectangle.tsx | 29 ++++++++++++++ src/client/views/nodes/FaceRectangles.tsx | 46 ++++++++++++++++++++++ src/client/views/nodes/ImageBox.tsx | 2 + src/client/views/nodes/KeyValueBox.tsx | 2 +- src/new_fields/ScriptField.ts | 2 + 6 files changed, 87 insertions(+), 5 deletions(-) create mode 100644 src/client/views/nodes/FaceRectangle.tsx create mode 100644 src/client/views/nodes/FaceRectangles.tsx (limited to 'src') diff --git a/src/client/cognitive_services/CognitiveServices.ts b/src/client/cognitive_services/CognitiveServices.ts index d525455cb..04a21c837 100644 --- a/src/client/cognitive_services/CognitiveServices.ts +++ b/src/client/cognitive_services/CognitiveServices.ts @@ -6,6 +6,8 @@ import { List } from "../../new_fields/List"; import { Docs } from "../documents/Documents"; import { RouteStore } from "../../server/RouteStore"; import { Utils } from "../../Utils"; +import { CompileScript } from "../util/Scripting"; +import { ComputedField } from "../../new_fields/ScriptField"; export enum Services { ComputerVision = "vision", @@ -107,12 +109,13 @@ export namespace CognitiveServices { let converter = (results: any) => { let tagDoc = new Doc; results.tags.map((tag: Tag) => { - if (tag.confidence >= +threshold) { - tagDoc[tag.name] = tag.confidence; - } + let sanitized = tag.name.replace(" ", "_"); + let script = `return (${tag.confidence} >= this.confidence) ? ${tag.confidence} : ${ComputedField.undefined}`; + let computed = CompileScript(script, { params: { this: "Doc" } }); + computed.compiled && (tagDoc[sanitized] = new ComputedField(computed)); }); tagDoc.title = "Generated Tags"; - tagDoc.confidenceThreshold = threshold.toString(); + tagDoc.confidence = threshold; return tagDoc; }; analyzeDocument(target, Services.ComputerVision, converter, "generatedTags"); diff --git a/src/client/views/nodes/FaceRectangle.tsx b/src/client/views/nodes/FaceRectangle.tsx new file mode 100644 index 000000000..887efc0d5 --- /dev/null +++ b/src/client/views/nodes/FaceRectangle.tsx @@ -0,0 +1,29 @@ +import React = require("react"); +import { observer } from "mobx-react"; +import { observable, runInAction } from "mobx"; +import { RectangleTemplate } from "./FaceRectangles"; + +@observer +export default class FaceRectangle extends React.Component<{ rectangle: RectangleTemplate }> { + @observable private opacity = 0; + + componentDidMount() { + setTimeout(() => runInAction(() => this.opacity = 1), 500); + } + + render() { + let rectangle = this.props.rectangle; + return ( +
+ ); + } + +} \ No newline at end of file diff --git a/src/client/views/nodes/FaceRectangles.tsx b/src/client/views/nodes/FaceRectangles.tsx new file mode 100644 index 000000000..3570531b2 --- /dev/null +++ b/src/client/views/nodes/FaceRectangles.tsx @@ -0,0 +1,46 @@ +import React = require("react"); +import { Doc, DocListCast } from "../../../new_fields/Doc"; +import { Cast, NumCast } from "../../../new_fields/Types"; +import { observer } from "mobx-react"; +import { Id } from "../../../new_fields/FieldSymbols"; +import FaceRectangle from "./FaceRectangle"; + +interface FaceRectanglesProps { + document: Doc; + color: string; + backgroundColor: string; +} + +export interface RectangleTemplate { + id: string; + style: Partial; +} + +@observer +export default class FaceRectangles extends React.Component { + + render() { + let faces = DocListCast(Doc.GetProto(this.props.document).faces); + let templates: RectangleTemplate[] = faces.map(faceDoc => { + let rectangle = Cast(faceDoc.faceRectangle, Doc) as Doc; + let style = { + top: NumCast(rectangle.top), + left: NumCast(rectangle.left), + width: NumCast(rectangle.width), + height: NumCast(rectangle.height), + backgroundColor: `${this.props.backgroundColor}33`, + border: `solid 2px ${this.props.color}`, + } as React.CSSProperties; + return { + id: rectangle[Id], + style: style + }; + }); + return ( +
+ {templates.map(rectangle => )} +
+ ); + } + +} \ No newline at end of file diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index f88150d66..0f60bd0fb 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -26,6 +26,7 @@ import { DocServer } from '../../DocServer'; import { Font } from '@react-pdf/renderer'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { CognitiveServices } from '../../cognitive_services/CognitiveServices'; +import FaceRectangles from './FaceRectangles'; var requestImageSize = require('../../util/request-image-size'); var path = require('path'); const { Howl, Howler } = require('howler'); @@ -379,6 +380,7 @@ export class ImageBox extends DocComponent(ImageD style={{ color: [DocListCast(this.extensionDoc.audioAnnotations).length ? "blue" : "gray", "green", "red"][this._audioState] }} icon={faFileAudio} size="sm" />
{/* {this.lightbox(paths)} */} + ); } } \ No newline at end of file diff --git a/src/client/views/nodes/KeyValueBox.tsx b/src/client/views/nodes/KeyValueBox.tsx index c9dd9a64e..9fc0f2080 100644 --- a/src/client/views/nodes/KeyValueBox.tsx +++ b/src/client/views/nodes/KeyValueBox.tsx @@ -114,7 +114,7 @@ export class KeyValueBox extends React.Component { let protos = Doc.GetAllPrototypes(doc); for (const proto of protos) { Object.keys(proto).forEach(key => { - if (!(key in ids)) { + if (!(key in ids) && realDoc[key] !== ComputedField.undefined) { ids[key] = key; } }); diff --git a/src/new_fields/ScriptField.ts b/src/new_fields/ScriptField.ts index e8a1ea28a..e5ec34f57 100644 --- a/src/new_fields/ScriptField.ts +++ b/src/new_fields/ScriptField.ts @@ -107,6 +107,8 @@ export namespace ComputedField { useComputed = true; } + export const undefined = "__undefined"; + export function WithoutComputed(fn: () => T) { DisableComputedFields(); try { -- cgit v1.2.3-70-g09d2 From d880e4b2fcb4e7bab3ee25d63209b173efcf37c0 Mon Sep 17 00:00:00 2001 From: Sam Wilkins Date: Tue, 23 Jul 2019 03:51:15 -0400 Subject: escaped name for computed field undefined --- src/client/cognitive_services/CognitiveServices.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/client/cognitive_services/CognitiveServices.ts b/src/client/cognitive_services/CognitiveServices.ts index 04a21c837..d4085cf76 100644 --- a/src/client/cognitive_services/CognitiveServices.ts +++ b/src/client/cognitive_services/CognitiveServices.ts @@ -110,7 +110,7 @@ export namespace CognitiveServices { let tagDoc = new Doc; results.tags.map((tag: Tag) => { let sanitized = tag.name.replace(" ", "_"); - let script = `return (${tag.confidence} >= this.confidence) ? ${tag.confidence} : ${ComputedField.undefined}`; + let script = `return (${tag.confidence} >= this.confidence) ? ${tag.confidence} : "${ComputedField.undefined}"`; let computed = CompileScript(script, { params: { this: "Doc" } }); computed.compiled && (tagDoc[sanitized] = new ComputedField(computed)); }); -- cgit v1.2.3-70-g09d2 From 97776a0f1725de5b512b803497af0801141c7f73 Mon Sep 17 00:00:00 2001 From: bob Date: Tue, 23 Jul 2019 12:30:52 -0400 Subject: switched native video to ontimeupdate instead of a timer --- src/client/views/nodes/VideoBox.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx index 5624d41a9..30ad75000 100644 --- a/src/client/views/nodes/VideoBox.tsx +++ b/src/client/views/nodes/VideoBox.tsx @@ -59,7 +59,7 @@ export class VideoBox extends DocComponent(VideoD this.Playing = true; update && this.player && this.player.play(); update && this._youtubePlayer && this._youtubePlayer.playVideo(); - !this._playTimer && (this._playTimer = setInterval(this.updateTimecode, 5)); + this._youtubePlayer && !this._playTimer && (this._playTimer = setInterval(this.updateTimecode, 5)); this.updateTimecode(); } @@ -72,7 +72,7 @@ export class VideoBox extends DocComponent(VideoD this.Playing = false; update && this.player && this.player.pause(); update && this._youtubePlayer && this._youtubePlayer.pauseVideo(); - this._playTimer && clearInterval(this._playTimer); + this._youtubePlayer && this._playTimer && clearInterval(this._playTimer); this._playTimer = undefined; this.updateTimecode(); } @@ -114,6 +114,7 @@ export class VideoBox extends DocComponent(VideoD setVideoRef = (vref: HTMLVideoElement | null) => { this._videoRef = vref; if (vref) { + this._videoRef!.ontimeupdate = this.updateTimecode; vref.onfullscreenchange = action((e) => this._fullScreen = vref.webkitDisplayingFullscreen); if (this._reactionDisposer) this._reactionDisposer(); this._reactionDisposer = reaction(() => this.props.Document.curPage, () => -- cgit v1.2.3-70-g09d2